zeroshade commented on code in PR #2380:
URL: https://github.com/apache/iceberg-go/pull/2380#discussion_r4469820269


##########
table/conflict_validation.go:
##########
@@ -923,37 +979,23 @@ func eqDeletePartitionsToFilter(files []iceberg.DataFile, 
meta Metadata) (iceber
                        specInfoByID[specID] = specInfo
                }
 
-               // Sort partition field IDs for deterministic expression order.
                fieldIDs := make([]int, 0, len(p))

Review Comment:
   This PR removes several comments that still apply: "Sort partition field IDs 
for deterministic expression order", the note that `canonicalPartitionKey` is 
injective, and "Resolve each source field at most once per partition spec…" 
(which backs the `currentSchemaCalls == 1` check). Could these be restored?



##########
table/conflict_validation.go:
##########
@@ -876,6 +877,59 @@ type equalityDeleteSourceFieldInfo struct {
        found bool
 }
 
+// NaNs are not equal to themselves as Go map keys, while the existing
+// equality evaluator compares two NaNs as equal. Binary sets use hash keys,
+// which can collide, so retain individual predicates for those values too.
+func equalityDeleteLiteralCanUseSet(lit iceberg.Literal) bool {
+       switch value := lit.(type) {
+       case iceberg.Float32Literal:
+               return !math.IsNaN(float64(value))
+       case iceberg.Float64Literal:
+               return !math.IsNaN(float64(value))
+       case iceberg.BoolLiteral, iceberg.Int32Literal, iceberg.Int64Literal,
+               iceberg.DateLiteral, iceberg.TimeLiteral, 
iceberg.TimestampLiteral,
+               iceberg.TimestampNsLiteral, iceberg.StringLiteral, 
iceberg.UUIDLiteral, iceberg.DecimalLiteral:
+               return true
+       default:
+               return false
+       }
+}
+
+type equalityDeleteIdentityGroupKey struct {
+       specID  int
+       fieldID int
+}
+
+type equalityDeleteIdentityGroup struct {
+       fieldName string
+       fieldType iceberg.Type
+       index     int
+       literals  []iceberg.Literal
+}
+
+// balancedConflictDisjunction keeps multi-field partition filters shallow.
+// The old left fold required traversal depth proportional to the number of

Review Comment:
   Please describe current behaviour rather than "the old left fold".



##########
table/conflict_validation.go:
##########
@@ -923,37 +979,23 @@ func eqDeletePartitionsToFilter(files []iceberg.DataFile, 
meta Metadata) (iceber
                        specInfoByID[specID] = specInfo
                }
 
-               // Sort partition field IDs for deterministic expression order.
                fieldIDs := make([]int, 0, len(p))
                for id := range p {
                        fieldIDs = append(fieldIDs, id)
                }
                sort.Ints(fieldIDs)
 
-               // Non-identity transforms (bucket, day, hour, truncate, year, 
month) store
-               // post-transform values in DataFile.Partition(). Building a 
row-space predicate
-               // with those values would cause 
validateAddedDataFilesMatchingFilter to
-               // re-apply the transform, producing wrong matches 
(double-transformation).
-               // Fall back to AlwaysTrue (conservative: treat the eq-delete 
as table-wide)
-               // until a full PartitionSet-style partition-space approach is 
added.
-               identityOnly := true
+               // A non-identity value is already transformed, so applying 
another

Review Comment:
   The previous comment explained why: identity-transform values are 
re-transformed in row space (double transformation), and the fallback stays 
until a PartitionSet-style approach exists. Could that detail be kept? The 
`identityOnly` → early-return rewrite also seems unrelated to this change.



##########
table/eq_delete_predicate_scale_bench_test.go:
##########
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package table
+
+import (
+       "fmt"
+       "testing"
+
+       "github.com/apache/iceberg-go"
+)
+
+var eqDeleteConflictPredicateScaleSink iceberg.BooleanExpression
+
+// BenchmarkEqDeleteConflictPredicateScale measures the end-to-end predicate
+// construction and schema binding used by serializable equality-delete
+// conflict checks. Run the same benchmark on the upstream base and this

Review Comment:
   "Run the same benchmark on the upstream base and this branch" is about this 
PR. Also, `BenchmarkEqDeletePartitionsToFilter` in 
`partition_conflict_bench_test.go` already benchmarks this function with the 
same input helper; could it get a bind step instead of a new file?



##########
table/conflict_validation.go:
##########
@@ -995,25 +1036,62 @@ func eqDeletePartitionsToFilter(files 
[]iceberg.DataFile, meta Metadata) (iceber
                                return nil, fmt.Errorf("partition field %q: 
%w", sourceField.name, err)
                        }
 
-                       conjuncts = append(conjuncts, 
iceberg.LiteralPredicate(iceberg.OpEQ, iceberg.Reference(sourceField.name), 
lit))
+                       if len(fieldIDs) == 1 && len(files) >= 32 && 
equalityDeleteLiteralCanUseSet(lit) {

Review Comment:
   What is `32` based on? It counts input files rather than distinct 
partitions, and grouping at 16 partitions costs about the same. If it only 
keeps the exact expressions expected by existing small tests, consider removing 
it and updating those tests; otherwise make it a named constant with a reason. 
Also, this block looks up the field again with `FindFieldByID` (ignoring the 
found flag) right after `specInfo.sourceFields` resolved it. Storing the type 
in `equalityDeleteSourceFieldInfo` would avoid that.



##########
table/eq_delete_conflict_perf_test.go:
##########
@@ -0,0 +1,168 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package table
+
+import (
+       "fmt"
+       "math"
+       "testing"
+
+       "github.com/apache/iceberg-go"
+       "github.com/stretchr/testify/require"
+)
+
+func TestEqDeleteConflictSingleFieldWithNullAndSeparatedValues(t *testing.T) {

Review Comment:
   Could these tests go in `partition_conflict_test.go` with the other 
`eqDeletePartitionsToFilter` tests? `TestEqDeleteConflictSetLiteralSafety` 
calls the helper directly (the NaN test already covers it through the real 
path), and `TestBalancedConflictDisjunctionPreservesTerms` checks only the tree 
shape. Consider dropping both.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to