Repository navigation
[FLINK-41068][table] Don't store build rows whose join key can never match in LATERAL SNAPSHOT joins - #29565
[FLINK-41068][table] Don't store build rows whose join key can never match in LATERAL SNAPSHOT joins#29565rionmonster wants to merge 2 commits into
Conversation
…match in LATERAL SNAPSHOT joins A build row whose join key has a NULL in a field that is not null-safe can never match, but LateralSnapshotJoinOperator buffered it and added it to the build table, where it stayed until the build side retracted it or state TTL removed it. All such rows share one key, so they ended up in the state of a single subtask, and every probe with a NULL key scanned them. The operator no longer stores these rows. The build side is never preserved, so the output doesn't change. Retractions are still applied, so a row that an earlier version stored is removed, but a retraction of such a row that finds nothing is not counted in numUnmatchedBuildRetractions. Generated-by: Claude Code (Claude Opus 5.5)
gustavodemorais
left a comment
There was a problem hiding this comment.
Thanks for the PR, @rionmonster!
| h.open(); | ||
| addBuildChange(h, insertRecord(null, "v_null", 1L)); | ||
| // A build row that can never match is not stored | ||
| assertThat(bufferedChangesForKey(h, op, null)).hasSize(filterNullKey ? 0 : 1); |
There was a problem hiding this comment.
The NULL-key build tests only use +I and -D. Could we also add a +U NULL-key row to joinRespectsNullKeysFilter and use an UPDATE_BEFORE for the stored row in retractsNullKeyBuildRowStoredByEarlierVersion? Right now narrowing the guard to RowKind.INSERT wouldn't fail any test.
There was a problem hiding this comment.
Thanks for the review, much appreciated! Good catch here, I've gone ahead and updated this and verified that the guard handles it as expected! 👍
There was a problem hiding this comment.
Thanks @rionmonster! I don't see the changes on the PR yet - the head is still e09288c. Could you push them?
There was a problem hiding this comment.
Doh! That's what I get for trying to juggle 4-5 branches at a time. The changes should be pushed up now. Thanks again for the review @gustavodemorais!
…d simplify the metric docs Generated-by: Claude Code (Claude Opus 5.5)
What is the purpose of the change
LateralSnapshotJoinOperatorstored build rows whose join key has a NULL in a field that isn't null-safe. Such rows can never match. Unlike in the window and interval joins, nothing bounds this state except state TTL: a row stays until the build side retracts it, or until TTL removes it if TTL is configured. All such rows share one key, so they pile up in a single subtask, and every probe with a NULL key scans all of them. This is the follow-up to FLINK-41034 for this operator.Brief change log
processElement2doesn't buffer an INSERT or UPDATE_AFTER build change whenJoinConditionWithNullFilters#currentKeyCannotMatchis true. The build side is never preserved, so the output doesn't change. The idle-flip timer is still armed first, because any build record counts as a build-side signal.applyBuildChangesdoesn't count a retraction of such a row innumUnmatchedBuildRetractionswhen it finds nothing. Otherwise the metric would count every NULL-key delete. The metric's description in the docs (English and Chinese) says so. Non-NULL keys are counted as before.Verifying this change
This change added tests:
LateralSnapshotJoinOperatorTest#joinRespectsNullKeysFilternow also checks that a NULL-key build row isn't stored, for INNER and LEFT joins. With a null-safe key the row is still stored, which is the positive control.LateralSnapshotJoinOperatorTest#retractsNullKeyBuildRowStoredByEarlierVersionrestores state with a stored NULL-key row, on the heap and RocksDB backends. It checks that the row's retraction still removes it, and that a retraction of a row that was never stored isn't counted in the metric.The new checks fail if NULL-key rows are stored, if their retractions are dropped too, or if those retractions are counted. The existing LATERAL SNAPSHOT tests pass: the runtime join tests, and the planner plan, semantic, restore and ITCase tests.
No new restore test is needed, because the state layout doesn't change. NULL-key rows stored by an earlier version stay until they are retracted or TTL removes them, as before.
Does this pull request potentially affect one of the following parts:
@Public(Evolving): noDocumentation
numUnmatchedBuildRetractionsis updated.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Claude Opus 5.5)