Skip to content

Conversation

@rdblue
Copy link
Contributor

@rdblue rdblue commented Aug 6, 2020

This adds a position delete row filter and helpers for constructing a row filter that will filter deletes to a specific data file and merge deletes from multiple delete files. These utilities are written using CloseableIterable and handle file closing.

@rdblue rdblue added this to the Row-level Delete milestone Aug 6, 2020
@rdblue rdblue requested a review from aokolnychyi August 6, 2020 01:24
@rdblue
Copy link
Contributor Author

rdblue commented Aug 6, 2020

FYI @prodeezy and @rymurr if you want to review.

import org.apache.iceberg.util.StructLikeWrapper;

public class Deletes {
private static final Schema POSITION_DELETE_SCHEMA = new Schema(
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 can move this to a better place later, but it isn't available elsewhere so it makes sense to add it here.

Copy link
Contributor

@rymurr rymurr left a comment

Choose a reason for hiding this comment

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

LGTM, I enjoyed the streaming sort algorithm :-)

Something for later: a benchmark to understand how large delete files can be before the filter cost explodes.

@rdblue
Copy link
Contributor Author

rdblue commented Aug 6, 2020

Something for later: a benchmark to understand how large delete files can be before the filter cost explodes.

Agreed. We might want to read all of the delete files at once and keep the records in memory if the set is small enough. We will definitely want to look into that for the vectorized case.

@aokolnychyi
Copy link
Contributor

Let me go through this now.


public class Deletes {
private static final Schema POSITION_DELETE_SCHEMA = new Schema(
Types.NestedField.required(1, "filename", Types.StringType.get(), "Data file location of the deleted row"),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why filename and not file_path like we use for DataFile?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Didn't think about it. file_path sounds good to me.

return new SortedMerge<>(Long::compare, positions);
}

private static class PositionDeleteFilter<T> extends CloseableGroup implements CloseableIterable<T> {
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 mean we will filter out positions after we read data and project meta columns? Do we plan to push this down to readers in the future? How will it work with vectorized execution?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This filter doesn't require us to answer most of those questions right now. All it requires is some object and a way to get the position of that object. That should be flexible enough that we can handle position as a column or using a class that directly supports it.

For the initial integration with Spark, I was thinking that we would add the _pos metadata column at the end of the requested projection. That way, we can return the rows without copying the data. At most, we would need to tell the row to report that it is one column shorter.

The main idea here is to make it easy for readers to create filters for tasks and apply them. The reader just needs to open the delete files, then pass them to these methods to merge deletes together and use them as a row filter.

For vectorization, we will probably want a different implementation, but we could reuse some of these classes (like the merging iterator).


@Override
protected boolean shouldKeep(T row) {
long currentPos = extractPos.apply(row);
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 assume rows are ordered by position?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it assumes that positions are ascending, like the delete positions.

List<CloseableIterable<Long>> positions = Lists.transform(deleteFiles, deletes ->
CloseableIterable.transform(locationFilter.filter(deletes), row -> (Long) POSITION_ACCESSOR.get(row)));

return new SortedMerge<>(Long::compare, positions);
Copy link
Contributor

Choose a reason for hiding this comment

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

One of the assumptions was that positional deletes are lightweight and we can build an in-memory map from file_path to a set of deleted positions for a given task. If I understand correctly, the current logic will scan deleteFiles for every data file.

Copy link
Contributor

@aokolnychyi aokolnychyi Aug 6, 2020

Choose a reason for hiding this comment

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

Do we consider merge sort as a primary way of applying positional deletes or as a fallback when the number of delete files is too large?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right. This implementation is the streaming one. It should be simpler to build the version that caches deletes as a set.

@aokolnychyi
Copy link
Contributor

This looks good to me too. The build failed, though.

[ant:checkstyle] [ERROR] /home/travis/build/apache/iceberg/core/src/test/java/org/apache/iceberg/deletes/TestPositionFilter.java:22:1: Use org.apache.iceberg.relocated.* classes from bundled-guava module instead. [BanUnrelocatedGuavaClasses]

Copy link
Contributor

@aokolnychyi aokolnychyi left a comment

Choose a reason for hiding this comment

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

+1 when the tests pass

@rdblue rdblue merged commit 4836006 into apache:master Aug 6, 2020
@rdblue
Copy link
Contributor Author

rdblue commented Aug 6, 2020

Thanks for reviewing @rymurr, @aokolnychyi!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a merge-based row filter for equality deletes

3 participants