Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core, Puffin: Add DV file writer #11476

Merged
merged 3 commits into from
Nov 6, 2024
Merged

Conversation

aokolnychyi
Copy link
Contributor

This PR adds a base DV file writer with basic tests. More tests to come once we support DV reads.

Benchmark                                                           (deletedRowsRatio)  (referencedDataFileCount)  Mode  Cnt           Score         Error   Units
DVWriterBenchmark.dv                                                              0.01                          5    ss   10           0.062 ±       0.003    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.01                          5    ss   10           0.219 ±       0.017    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.01                          5    ss   10           0.146 ±       0.006    s/op

DVWriterBenchmark.dv                                                              0.01                         10    ss   10           0.103 ±       0.010    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.01                         10    ss   10           0.435 ±       0.016    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.01                         10    ss   10           0.265 ±       0.014    s/op

DVWriterBenchmark.dv                                                              0.03                          5    ss   10           0.136 ±       0.006    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.03                          5    ss   10           0.479 ±       0.018    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.03                          5    ss   10           0.337 ±       0.018    s/op

DVWriterBenchmark.dv                                                              0.03                         10    ss   10           0.219 ±       0.013    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.03                         10    ss   10           0.918 ±       0.028    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.03                         10    ss   10           0.618 ±       0.014    s/op

DVWriterBenchmark.dv                                                              0.05                          5    ss   10           0.218 ±       0.014    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.05                          5    ss   10           0.696 ±       0.010    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.05                          5    ss   10           0.527 ±       0.008    s/op

DVWriterBenchmark.dv                                                              0.05                         10    ss   10           0.366 ±       0.011    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.05                         10    ss   10           1.389 ±       0.024    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.05                         10    ss   10           0.986 ±       0.007    s/op

DVWriterBenchmark.dv                                                              0.10                          5    ss   10           0.307 ±       0.007    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.10                          5    ss   10           1.179 ±       0.039    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.10                          5    ss   10           1.004 ±       0.010    s/op

DVWriterBenchmark.dv                                                              0.10                         10    ss   10           0.594 ±       0.006    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                        0.10                         10    ss   10           2.260 ±       0.039    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                   0.10                         10    ss   10           2.045 ±       0.054    s/op

DVWriterBenchmark.dv                                                               0.2                          5    ss   10           0.709 ±       0.011    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                         0.2                          5    ss   10           2.151 ±       0.017    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                    0.2                          5    ss   10           1.969 ±       0.046    s/op

DVWriterBenchmark.dv                                                               0.2                         10    ss   10           1.370 ±       0.047    s/op
DVWriterBenchmark.fileScopedParquetDeletes                                         0.2                         10    ss   10           4.386 ±       0.034    s/op
DVWriterBenchmark.partitionScopedParquetDeletes                                    0.2                         10    ss   10           3.849 ±       0.030    s/op

This work is part of #11122.


private final OutputFileFactory fileFactory;
private final Function<CharSequence, PositionDeleteIndex> loadPreviousDeletes;
private final CharSequenceMap<Deletes> deletesByPath = CharSequenceMap.create();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to discuss whether we should accept String or CharSequence in DV writers. We migrated to String for our new DataFile and DeleteFile fields but it is a different use case. We don't have to necessarily serialize these values. If an engine supports custom CharSequence objects, it may benefit from this API and skip the conversion.

It has no benefits for Spark, though. We have to convert to String.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that String makes more sense for now because:

  • to my knowledge, most of query engines support String
  • if a query engine needs CharSequence, the conversion is not very painful

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware of any engine that would take advantage of it here, but I'm not sure it really causes any significant complexity to maintain as CharSequence. I'm fine either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avro Utf8 is the only example I remember.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It's probably a good idea to use String. We can always move to CharSequence later with minimal changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on using String, which I've also mentioned in https://github.com/apache/iceberg/pull/11302/files#r1824137648

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Let's use String. It will have less overhead for engines like Spark that use String.

@@ -21,8 +21,8 @@
import org.apache.iceberg.StructLike;

/** Copy the StructLike's values into a new one. It does not handle list or map values now. */
class StructCopy implements StructLike {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to move this into a utility. Just not sure which at this point. Ideas are welcome.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a "generic" IoUtil ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this even belong in io? This feels like it should be in types.TypeUtil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it belongs to StructLikeUtil or something like this. Doesn't seem to belong to io.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for StructLikeUtil or similar.

@jbonofre, the io classes typically refer to FileIO and buffer management utils in Iceberg. I'm not quite sure why this is currently in the io package. I think it's probably better to not continue using io so that it's easier to find later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I like the StructLikeUtil name.

+1 for that. Thanks !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the logic to the util and deprecated this class not to break anyone.

}

@TestTemplate
public void testBasicDVs() throws IOException {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add more once we support DV reads.

return new Blob(
StandardBlobTypes.DV_V1,
ImmutableList.of(MetadataColumns.ROW_POSITION.fieldId()),
-1 /* snapshot ID is inherited */,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per V1 Puffin spec.

* @param spec the data file partition spec
* @param partition the data file partition
*/
void write(CharSequence path, long pos, PartitionSpec spec, StructLike partition);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Little bit of a nit here, but does write make sense? We're actually marking for delete. FileAppender and most "Writers" use add, should this just be delete?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. What about DVFileWriter as the name? That seems OK but if there are alternatives, let me know.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielcweeks from my standpoint, delete() would be confusing. As the class is named DeleteVectorFileWriter (yes, I would prefer a full name instead of DV), I think it makes sense to use write() there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my view, delete makes sense now as previously we passed PositionDelete object and used the common writer abstraction. That said, I am OK either way.

I do want to keep the shorter class name. I use DV naming consistently throughout the code and it allows me to stay on one line most of the time. Our 100 character line limit is no joke!

return StructCopy.copy(struct);
}

private static class StructCopy implements StructLike {
Copy link
Contributor Author

@aokolnychyi aokolnychyi Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied the existing class but made private. The old one is deprecated and will be removed in 1.9.

Comment on lines 68 to 70
this.tableDir = Files.createTempDirectory(temp, "junit").toFile();
assertThat(tableDir.delete()).isTrue(); // created during table creation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.tableDir = Files.createTempDirectory(temp, "junit").toFile();
assertThat(tableDir.delete()).isTrue(); // created during table creation

FYI this typically isn't needed, because tableDir is already initialized in the super class. See also #11460 where existing tests have been refactored to remove this unnecessary re-initialization

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, good call. Missed that change!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also removed the metadata dir and empty line.

@aokolnychyi aokolnychyi merged commit 7938403 into apache:main Nov 6, 2024
49 checks passed
@aokolnychyi
Copy link
Contributor Author

Thanks for reviewing, @nastra @danielcweeks @jbonofre @rdblue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants