Core: Implement source-ids to deal with multi arguments transforms#12897
Core: Implement source-ids to deal with multi arguments transforms#12897jbonofre wants to merge 8 commits into
Conversation
|
@rdblue @Fokko @RussellSpitzer ^^ Thanks ! |
| fields.add(new PartitionField(sourceId, fieldId, name, transform)); | ||
| Builder add(List<Integer> sourceIds, int fieldId, String name, Transform<?, ?> transform) { | ||
| // we use the first entry in the source-ids list here | ||
| checkAndAddPartitionName(name, sourceIds.get(0)); |
There was a problem hiding this comment.
How does this work for multi arg partition field?
Do we need a logic that accepts the sourceIds and resolve the name of multi arg transform?
There was a problem hiding this comment.
The sourceId here is to resolve conflict (no impact on name):
if (sourceColumnId != null) {
// for identity transform case we allow conflicts between partition and schema field name
// as
// long as they are sourced from the same schema field
Preconditions.checkArgument(
schemaField == null || schemaField.fieldId() == sourceColumnId,
"Cannot create identity partition sourced from different field in schema: %s",
name);
Let me check if we should compare fieldId with each column id.
There was a problem hiding this comment.
The current logic looks like
if (check conflicts). {
if identity {
make sure we aren't using a different field name for this identity transform
} else {
make sure we aren't matching any other column name
}
}
Make sure it's not empty
Make sure we haven't already used this name for another partition
Add partitionI have no idea why those last 2 checks aren't part of the "if check conflicts" branch
Anyyyyyyway. I think this whole validation probably should be rewritten. The first branch we are checking basically based a lot of implicit assumptions when we should just be passing in the transform. But we don't have to do any of that now.
For now I think we should pass in sourceIds and just have the first branch include a "if sourceIds.length == 1"
There was a problem hiding this comment.
OK, let me refactore this part.
a5b96f2 to
549c197
Compare
|
|
||
| for (UnboundPartitionField field : fields) { | ||
| Type fieldType = schema.findType(field.sourceId); | ||
| Type fieldType = schema.findType(field.sourceIds.get(0)); |
There was a problem hiding this comment.
I know we don't have a multi-arg transform to resolve here yet but this doesn't seem like the right thing to do. I think Transforms.fromString needs to be modified to accept fromString(list[types], transformName)
There was a problem hiding this comment.
Yes, agree. Let me update that.
| .isInstanceOf(IllegalArgumentException.class) | ||
| .hasMessage( | ||
| "Cannot parse partition field, either source-id or source-ids has to be present"); | ||
| } |
There was a problem hiding this comment.
We should have some tests for "toJson" as well?
We also need a check that the validation for identity transforms still holds true. Ie you cannot make a multi-arg transform with the same name as any of the columns
There was a problem hiding this comment.
I added a test in TestPartitionSpecParser testing when neither source-id and source-ids are provided: testFromJsonWithoutSourceIdAndSourceIds().
I will add additional tests for toJson path too.
RussellSpitzer
left a comment
There was a problem hiding this comment.
Overall this looks pretty good to me. I think we are missing some testing but the approach looks correct. There are a few utility methods we need to fix up as well to accept sourceIds
|
Thanks @RussellSpitzer ! Let me fix the util methods and add tests. Thanks again ! |
549c197 to
1552f6c
Compare
|
Hey guys. I was traveling this week. I'm now back on this pr, updating according to the comments. |
|
I did a first update to introduce multi-args in |
ccc3e48 to
b1b407f
Compare
|
Finally back from several trips, so resuming work on this PR. |
|
Here we go again 😄 |
|
Back again :) |
|
I'm back (again 😄 ) on Iceberg, resuming my different PRs. Resuming the work. |
eb304c2 to
a84596f
Compare
| return fieldList; | ||
| } | ||
|
|
||
| private ListMultimap<Integer, PartitionField> lazyFieldsBySourceId() { |
There was a problem hiding this comment.
Since it indexes by the first sourceId i'm not sure what will actually happen, we probably need to do something here
There was a problem hiding this comment.
I used a simple approach now, iterating on all source ids:
for (PartitionField field : fields) {
for (int sourceId : field.sourceIds()) {
multiMap.put(sourceId, field);
}
}
I think it makes sense in this context.
Thoughts ?
| if (element.has(FIELD_ID)) { | ||
| builder.addField(transform, sourceId, JsonUtil.getInt(FIELD_ID, element), name); | ||
| fieldIdCount++; | ||
| if (element.has(SOURCE_IDS)) { |
There was a problem hiding this comment.
I think we should at least warn here if source id is also present and has a different value. I could also see throwing an exception but we generally don't fail unless we absolutely have to when parsing. As long as the writer would override the bad source-id I think we are ok
There was a problem hiding this comment.
I'm hesitating here. To limit the impact, finally, I preferred to log (warn) when both source-ids and source-id are present (instead of failing).
Thoughts ?
5c4b042 to
ecde76e
Compare
444ee1c to
410934d
Compare
Add a precondition guard on PartitionField.sourceId() to prevent misuse with multi-arg transforms, fix toString() to use Joiner instead of List.toString(), migrate all sourceId() call sites in PartitionSpec to use sourceIds(), and add a consistency check in PartitionSpecParser when both source-id and source-ids are present.
…source-ids Follow reviewer guidance to warn rather than throw when parsing, since Iceberg generally avoids hard failures during deserialization.
The testFromJsonFieldsWithMultipleSourceIds test was calling sourceId() on a field with multiple source IDs, which now throws after the hardening in 7a4cc92. Use sourceIds() instead.
410934d to
80e8700
Compare
|
Hi @jbonofre, are you still planning to pursue this PR? I'm asking because I recently implemented the v3 read-tolerance side of this in PyIceberg (apache/iceberg-python#3630: fields with multiple |
Following the update on the spec regarding
source-idandsource-ids(thanks again @Fokko 😄 ), here's the PR to introducesource-idsfield in partition spec.A few notes:
source-idssource-idandsource-idselements in the json (exclusive), both populatingsource-idsinternal representation (asList<Integer>)TestPartitionSpecParseris still testingsource-id, but alsosource-idsparsing, and neithersource-idandsource-idspresence (throwingIllegalArgumentExceptionin that case)