Conversation
|
nit: the Jira number has an extra |
| import org.apache.flink.table.planner.plan.nodes.physical.stream.StreamPhysicalRel | ||
| import org.apache.flink.table.planner.plan.schema.{IntermediateRelTable, LegacyTableSourceTable, TableSourceTable} | ||
| import org.apache.flink.table.planner.plan.utils.{ChangelogPlanUtils, ExpressionFormat, InputRefVisitor, JoinTypeUtil, LookupJoinUtil, RelExplainUtil, TemporalJoinUtil} | ||
| import org.apache.flink.table.planner.plan.utils._ |
There was a problem hiding this comment.
nit: normal practise is to list all of the import packages.
|
@morazow If I am understanding this correctly, the filtered pushed down joins cause the Volcano planner to uniquely identify I wonder what happens if one of the lookup joins supports filter push down but the other doesn't? Does the include the name of the source as well as the filter? It would be good to have tests for when both sources support filter pushdown, neither do and only 1 does. |
2a6053f to
867644d
Compare
|
Thanks @davidradl, addressed your findings, please have another look 🤝
Yes, but based on the getDigests method, which results in a string like below: Here we have the table name, but no information on the pushed down filter conditions. For this issue to happen, the lookup table's should be same (since it is in the digest), so we cannot test if one part supports and other part doesn't test case. Additionally, if the source doesn't support the filter pushdown it will be represented in the digest with the |
…able table source
867644d to
eca1bf6
Compare
xuyangzhong
left a comment
There was a problem hiding this comment.
Thanks for digging into this bug and driving this fix. I just left some comments.
| } | ||
|
|
||
| private def getTableFilterString(t: TableSourceTable): String = { | ||
| val filterOpt = t.abilitySpecs.collectFirst { case spec: FilterPushDownSpec => spec } |
There was a problem hiding this comment.
I'm wondering should PartitionPushDownSpec also need to be added into this part.
| .item("joinType", JoinTypeUtil.getFlinkJoinType(joinType)) | ||
| .item("lookup", lookupKeys) | ||
| .itemIf("where", whereString, whereString.nonEmpty) | ||
| .itemIf("filter", filterPushdownString, filterPushdownString.nonEmpty) |
There was a problem hiding this comment.
nit what about filterPushedDown?
| import org.junit.jupiter.params.ParameterizedTest | ||
| import org.junit.jupiter.params.provider.CsvSource | ||
|
|
||
| class UnionLookupJoinITCase extends StreamingTestBase { |
There was a problem hiding this comment.
Could you please move this test to LookupJoinITCase?
|
Hello @xuyangzhong , Thanks for the review! I have addressed your suggestions, please have a look. I put them to separate commit for now, later I'll squash it 👍 |
xuyangzhong
left a comment
There was a problem hiding this comment.
Thanks for the update. Please forgive me for missing your message... I have one comment as well.
|
|
||
| super | ||
| .explainTerms(pw) | ||
| .item("table", tableIdentifier.asSummaryString()) |
There was a problem hiding this comment.
What about reusing this item table with:
val tableDesc: String = temporalTable match {
case t: TableSourceTable => t.getQualifiedName.asScala.mkString(", ")
case t: LegacyTableSourceTable[_] => t.tableIdentifier.asSummaryString()
}
super
.explainTerms(pw)
.item("table", tableDesc)
...
Although the plans for some tests may change, this will not actually affect compatibility, and it can be aligned with the digest in CommonPhysicalTableSourceScan.
|
This PR is being marked as stale since it has not had any activity in the last 90 days. If you are having difficulty finding a reviewer, please reach out to the If this PR is no longer valid or desired, please feel free to close it. |
|
This PR has been closed since it has not had any activity in 120 days. |
|
@morazow I picked this up since the bot closed it rather than anyone rejecting it. You're a co-author on the commit, the reproduction and the test case are yours. Happy to hand it back if you'd rather carry it yourself. New PR: #29200 @xuyangzhong on your two comments:
Went this way, but kept the dotted table name. The lookup join now appends
It ended up as a One thing the new PR does not fix: the scan also digests its table hints, so two lookup joins differing only in an |
|
Amazing! Thanks @MartijnVisser and @xuyangzhong for reviews 🤝 |
What is the purpose of the change
Brief description of the bug
Given a union all query:
In this situation the planner will pushdown the filter condition into the table part of the lookup join, but the structure of the lookup joins stays the same, e.g, they will have same
digestswith different table / temporal table.This is the problem since the Calcite Volcano optimizer will register them equivalent because it does so using the digest of the relation nodes.
This introduces the bug because when optimizing the Union, both parts of the query will be treated same (even though we have different where clauses) and the found cheapest plan will be same for both lookup joins.
You can also see the effect if you put non-existing filter first the result will be empty, because the first lookupjoin is also used for the second part of the union.
Alternative Solutions
The better solution would be to improve the LookupJoin expression to also include the filter condition into the table name. For example,
But this would require many refactoring, and mainly in the tests.
In this PR, I have opted for adding another
filterwith pushed down filter conditions if the LookupJoin contains a table with filter pushdowns.Brief change log
Verifying this change
The change adds test case that reproduces the bug that can be verified by the fixes.
Does this pull request potentially affect one of the following parts:
@Public(Evolving): noDocumentation