Repository navigation
[core] Support composite BTree equality queries for data evolution tables - #10339
Merged
JingsongLi merged 13 commits intoOct 2, 2026
Merged
Conversation
leaves12138
approved these changes
Oct 2, 2026
leaves12138
left a comment
Contributor
There was a problem hiding this comment.
Reviewed c2cb701. No blocking findings within the documented Java/common+core complete-equality scope.
Validation on JDK 8:
- 321 focused tests passed across composite matching/storage, eager and deferred queries, evaluated coverage, manifest identities, incremental builds, scalar/search prefilters and split serialization.
- An additional 328 existing scalar BTree reader/writer regression tests passed. Both suites ran without fast-build, with the normal validation checks enabled.
- Added an isolated seeded differential test: 80 nested AND/OR predicates across FULL/DETAIL and eager/reader execution (320 comparisons), with differently covered scalar/composite definitions and unindexed tail rows. All results matched direct row predicate evaluation.
The separation between metadata-proven misses, actual evaluated coverage and unsupported-reader fallback is consistent in the reviewed paths. Scope boundaries remain important: composite files written by the earlier unreleased encoding must be rebuilt; Python multi-index compatibility and composite SQL/prefix/range integration remain follow-ups, not capabilities validated by this approval. The full remote CI matrix is still in progress.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Part 2 of the composite BTree series, following merged #10338 and split from #10327. Connect complete-key equality lookups to data evolution index construction, query planning and coverage accounting.
List<DataField>factory APIs merged in [core] Add composite BTree key storage and point lookups #10338. Replace the custom tuple encoding withRowCompactedSerializerbehindKeySerializer; canonicalize RowKind and floating NaN values, use one serializer per thread, and remove the extra tuple-arity checks.SQL topology integration in Spark/Flink follows in part 3; this PR includes only the mechanical migration of existing single-column topology calls to the field-list API. Composite prefix/range/IN/IS NULL bounds and scan-budget/index-selection extensions follow in part 4. This PR replaces the unreleased composite key encoding from #10338; composite indexes built with that implementation must be rebuilt. It introduces no new table options.
Tests
fast-buildwas not used for final verification).git diff --checkpassed.Split verification
Reconstructed from the reviewed equality snapshot
4e34273c09in a new worktree based on masterdf43423696. The complete source branch atc738a41321was preserved. The merged field-list API remains in place; the serializer reuse and removal of extra arity checks are explicit follow-up changes requested during review; no composite range-planning or engine topology changes are included.Independent dependency, query/coverage, and storage reviews found no remaining P0–P2 issues. The longest-key selection regression is recorded as an explicit test addition for the final-series tree-equivalence check.
Serializer follow-up
Removed the per-component length codec and delegated serialization/deserialization to
RowCompactedSerializer. Typed object comparison remains in theKeySerializeradapter.Canonicalize RowKind and floating NaN values in a temporary row to keep equality and Bloom hashing consistent without changing the source row or the shared row serializer.
Added compacted encoding compatibility, RowKind, concurrent round-trip, NaN payload and Bloom point-lookup regressions. The encoding and NaN regressions were observed failing before their respective fixes.
Final follow-up verification: 64 Java tests passed on JDK 8 across
CompositeBTreeIndexTest,CompositeBTreePredicateTest,BTreeThreadSafetyTest,BTreeBloomFilterTest,SortedFileMetaSelectorTest,CompositeBTreeTableTest,SortedGlobalIndexWriterTestandSortedGlobalIndexScannerTest, with Checkstyle, Spotless and Enforcer enabled. Independent review found no remaining P0-P2 issues.Key ownership follow-up
Remove the composite-specific copying and serializer checks from
BTreeIndexWriter, restoring its original implementation. NoKeySerializer.copy()API is added.Composite deserialization follows the same ownership contract as string deserialization: copy the input bytes and return a new row with fields backed by that independent allocation. The existing
RowCompactedSerializeradapter already satisfies this contract.Verify that consecutive deserialization calls and modifications to input buffers leave previously returned keys intact. Use independently deserialized keys for posting/local-range tests and assert the retained min/max metadata for both BTree file versions.
Final verification: 65 Java tests passed on JDK 8, with Checkstyle, Spotless and Enforcer enabled. Independent review confirmed returned rows/field storage are independent and found no remaining P0-P2 issues.
Composite predicate entry point
Replace
visitCompositeEqual(List<Object>)withvisitComposite(Predicate)and remove the old API. Query planning passes its composite predicate directly to the reader.Retain the ordered index fields in the BTree reader. Match complete equalities by field name/type and construct the point key in index order, independent of the predicate schema and conjunction order.
Keep the current complete-equality scope: NULL/contradictory equalities return a supported empty result; incomplete keys and currently unsupported range/IN/OR predicates return an empty Optional so callers can fall back. Single-column readers decline composite predicates. Future range/prefix support can extend this same entry point.
Update point-lookup/local-range tests to use predicates; cover field-order changes, contradictions, unsupported conditions and single-column isolation.
Final verification: 108 Java tests passed on JDK 8, covering direct reader behavior, eager/deferred query execution, coverage/fallback and sorted-index construction, with Checkstyle, Spotless and Enforcer enabled. Independent review found no remaining P0-P2 issues.
Evaluation constructor simplification
Evaluationconstructor and update all six scalar/refinement call sites to passnullcoverage explicitly. Composite queries continue passing their concrete coverage.null) and explicitly empty coverage; scanner fallback behavior is unchanged.GlobalIndexEvaluatorTest,GlobalIndexQueryTestandSortedGlobalIndexScannerTest, with Checkstyle, Spotless and Enforcer enabled.Sorted builder field-list API
withIndexField(String)fromSortedGlobalIndexScannerandSortedGlobalIndexWriter. Migrate all 28 calls across core tests and Flink/Spark topology code towithIndexFields(Collections.singletonList(...)).flink1/spark3profiles and Checkstyle, Spotless and Enforcer enabled. Independent review found no remaining P0-P2 issues; no old method definitions or calls remain.mvn -pl paimon-core,paimon-flink/paimon-flink-common,paimon-spark/paimon-spark-common \ -am -Pspark3,flink1 -DwildcardSuites=none -DfailIfNoTests=false \ -Dtest=SortedGlobalIndexScannerTest,SortedGlobalIndexWriterTest,CompositeBTreeTableTest,SortedIndexTopoBuilderTest,IndexQuerySourceTest testPython scope
paimon-pythonhas no diff against the base and that the non-Python diff is identical to the previously verified version.Per-field coverage rule
DataEvolutionGlobalIndexCoverage. Every definition with non-emptyextraFieldIdsis excluded from per-field coverage, including its primary field. Only independent single-field definitions contribute;nulland empty extra-field arrays remain valid single-field definitions.CompositeBTreeTableTest,GlobalIndexQueryTest,BtreeGlobalIndexTableTest,FullTextSearchBuilderTest,VectorSearchBuilderTestandVectorSearchRowFilterExactnessTest, with Checkstyle, Spotless and Enforcer enabled. Independent review found no remaining P0-P2 issues.Scanner and query single-field selection
isCompositeBTreewith index-type-independentisMultiFieldIndexbased on non-emptyextraFieldIds. Scalar prefilters and scalar reader construction exclude all multi-field definitions. Retain the BTree capability constraint for TopN.GlobalIndexQueryscalar planning: only independent single-field definitions can serve scalar leaves, including in-reader execution and residuals next to a complete composite condition. The actual BTree composite matching remains in query planning.Generic manifest definition identity
IndexManifestFileHandler. Index types are grouped by the existing outer layer; compare each definition's complete ordered field-id list within a type. Different definitions may coexist, while overlapping ranges for the same definition require deleting the prior file first.IndexManifestFileHandlerTestandCompositeBTreeTableTest, with Checkstyle, Spotless and Enforcer enabled. Independent review of the Java diff found no remaining P0-P2 issues.Reader best effort follow-up
supportsPredicate,requiresGlobalEvaluation, and the special eager fallback from deferred index planning. Readers determine which predicates can use each index at runtime.Final follow-up verification: 206 Java tests passed on JDK 8, with Checkstyle, Spotless and Enforcer enabled. Independent static review found no production P0–P2 findings.
mvn -pl paimon-core -am -DfailIfNoTests=false -DwildcardSuites=none \ -Dtest=CompositeBTreeTableTest,IndexQuerySplitTest,GlobalIndexQueryTest,DataEvolutionBatchScanTest,BtreeGlobalIndexTableTest,BitmapGlobalIndexTableTest,GlobalIndexEvaluatorTest,CompositeBTreePredicateTest,CompositeBTreeIndexTest,SortedFileMetaSelectorTest testCI follow-up: vector-search coverage expectations
Synchronize the mixed vector-search integration test with the single-field coverage rule: multi-field definitions do not remove rows from the FULL data fallback, and their matching index files remain attached to that fallback. Keep the exact final Top-K result assertion.
Verification: the original failure reproduced locally before the correction. All 21 vector-search procedure tests passed with Flink 1 on JDK 8, and all 21 passed with Flink 2 on JDK 11, with Checkstyle, Spotless and Enforcer enabled. The shared Flink module was rebuilt from clean output for the second profile.