The Div macro wraps content in a div tag with optional class and styles. This allows us to use macros such as the Style macro below.
Current state:
| Current State | |
|---|---|
Discussion thread: here
JIRA: here
Released: <Hudi Version>
For tables or partitions, where the majority of records change every cycle, it is inefficient to do upsert or merge. We want to provide hive like 'insert overwrite' API to ignore all the existing data and create a commit with just new data provided. These API can also be used for certain operational tasks to fix a specific corrupted partition. We can do 'insert overwrite' on that partition with records from the source. This can be much faster than restore and replay for some data sources.
Hoodie supports multiple write operations such as insert, upsert, bulk_insert on the target table. At a high level, we like to add two new operations:
Below, we discuss some high level implementation choices. Most of the discussion is centered on one partition. It is relatively easy to extend this to multiple partitions.
Also, note that my focus is primarily on COW tables. I tried giving examples for MOR tables too. But I don't fully grasp complexity and edge cases in MOR tables, so please highlight any mistakes/bad assumptions.
We reuse existing file groups in partition and distribute new records among them. We create new file groups if number of new records is much larger than existing file groups can support. If number of new records is much smaller, then there are two high level strategies to distribute records.
I am inclined towards #1 to minimize IO in subsequent writes.
Example for Copy On Write:
files in partition before | insert overwrite with similar number of records | insert overwrite with much larger number of records | insert overwrite with 1 record |
Partition contains file1-t0.parquet, file2-t0.parquet | Partition will add file1-t1.parquet, file2-t1.parquet | Partition will add file1-t1.parquet, file2-t1.parquet file3-t1.parquet . . .fileN-t1.parquet | Partition will add file1-t1.parquet, file2-t1.parquet One of the parquet files above will be empty. Other will have one record |
Example for Merge On Read:
Note that for MOR, we schedule compaction inline before doing ‘insert overwrite’. We don’t have to wait for compaction to complete.
So assume initial state of partition has commit at t0. ‘Insert overwrite’ is done at t2. We schedule compaction at t1 before starting ‘insert overwrite’ at t2.
files in partition before | insert overwrite with similar number of records | insert overwrite with much larger number of records | insert overwrite with 1 record |
Partition contains file1-t0.parquet, file2-t0.parquet .file1-t00.log | Partition will add file1-t2.parquet, file2-t2.parquet Previous files continue to exist. After compaction runs, they will change to: file1-t1.parquet file2-t0.parquet | Partition will add file1-t2.parquet, file2-t2.parquet file3-t2.parquet . . .fileN-t2.parquet Previous files continue to exist. After compaction runs, they will change to: file1-t1.parquet file2-t0.parquet | Partition will add file1-t2.parquet, file2-t2.parquet One of the parquet files above will be empty. Other will have one record. Previous files continue to exist. After compaction runs, they will change to: file1-t1.parquet file2-t0.parquet |
Advantages:
Disadvantages:
Existing file groups are marked for 'deletion'. New file groups are created based on number of new records
Example for Copy On Write:
files in partition before | insert overwrite with similar number of records | insert overwrite with much larger number of records | insert overwrite with 1 record |
Partition contains file1-t0.parquet, file2-t0.parquet | Partition will add file3-t1.parquet, file4-t1.parquet file1, file2 marked invalid in metadata after t1 | Partition will add file3-t1.parquet, file4-t1.parquet file5-t1.parquet . . .fileN-t1.parquet file1, file2 marked invalid in metadata after t1 | Partition will add file3-t1.parquet file1, file2 marked invalid in metadata after t1 |
Example for Merge On Read:
files in partition before | insert overwrite with similar number of records | insert overwrite with much larger number of records | insert overwrite table with 1 record |
Partition contains file1-t0.parquet, file2-t0.parquet .file1-t00.log | file3-t1.parquet file4-t1.parquet file1, file2 marked invalid in metadata after t1 | Partition will add file3-t1.parquet, file4-t1.parquet . . .fileN-t1.parquet file1, file2 marked invalid in metadata after t1 | Partition will add file3-t1.parquet file1, file2 marked invalid in metadata after t1 |
Advantages:
Disadvantages:
Add an extra level of versioning on the partition itself.
Example for Copy On Write:
files in partition before | insert overwrite with similar number of records | insert overwrite with much larger number of records | insert overwrite with 1 record |
Partition contains file1-t0.parquet, file2-t0.parquet | Partition contains file1-t0.parquet, file2-t0.parquet A new directory ‘partition-t1’ is created. partition-t1 will add file3-t1.parquet, file4-t1.parquet | Partition contains file1-t0.parquet, file2-t0.parquet A new directory ‘partition-t1’ is created. partition-t1 will add file3-t1.parquet, file4-t1.parquet file5-t1.parquet . . .fileN-t1.parquet | Partition contains file1-t0.parquet, file2-t0.parquet A new directory ‘partition-t1’ is created. partition-t1 will add file3-t1.parquet |
Example for Merge On Read:
files in partition before | insert overwrite with similar number of records | insert overwrite with much larger number of records | insert overwrite table with 1 record |
Partition contains file1-t0.parquet, file2-t0.parquet .file1-t00.log | Partition contains file1-t0.parquet, file2-t0.parquet .file1-t00.log A new directory ‘partition-t1’ is created. partition-t1 will add file3-t1.parquet, file4-t1.parquet | Partition contains file1-t0.parquet, file2-t0.parquet .file1-t00.log A new directory ‘partition-t1’ is created. partition-t1 will add file3-t1.parquet, file4-t1.parquet . . . fileN-t1.parquet | Partition contains file1-t0.parquet, file2-t0.parquet .file1-t00.log A new directory ‘partition-t1’ is created. partition-t1 will add file3-t1.parquet, file4-t1.parquet |
Advantages:
Disadvantages:
Regardless of implementation approach chosen, we need to add/change existing high level API. At the moment, we incline towards creating two new operations on spark dataframe instead of adding flags on existing operation because the actions taken are equivalent to deleting all pre-existing data. But open to feedback.
hoodie.datasource.write.operation: insert_overwrite_tableSimilarly a new high level public method is added on HoodieWriteClient (We can discuss merging these two into one as well)
After weighing trade-offs, we are inclined towards going with Option 2. Option 1 has lot of complexity especially with MOR tables. Option 3 would add a lot of complexity in general. With Option2, we can take multiple steps.