Hi Benchao, If that’s the case, then why are filters with non-custom operators pushed down? For example: https://pastebin.com/raw/aPLnHMaS Here I use `table.id = 1`,where `table` comes from the null-generating side of the join. Filter push down occurs, but only when FILTER_INTO_JOIN is enabled.
-Ian On 2023/08/30 12:39:24 Benchao Li wrote: > Hi Ian, > > FilterJoinRule[1] is designed to not push filters to null-generating > side of Join, it has nothing to do with your custom UDF. > > [1] > https://github.com/apache/calcite/blob/2bf1e7b2e8596a61b5ac19aa7bebb9910c4eea94/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java#L111-L125 > > Alessandro Solimando <[email protected]<mailto:[email protected]>> 于2023年8月30日周三 > 14:13写道: > > > > Hi Ian, > > I did not have time to dig more into your question (not very familiar with > > the way you register functions), but for RuleEventLogger you might want to > > check these slides (9 to 12 for how to activate it, the rest 15 to 23 on > > how to read the output): > > https://www.slideshare.net/StamatisZampetakis/debugging-planning-issues-using-calcites-builtin-loggers > > . > > > > Hth, > > Alessandro > > > > > > > > On Wed, 30 Aug 2023 at 04:14, Ian Bertolacci > > <[email protected]<mailto:[email protected]>lid> wrote: > > > > > Hello, > > > We have defined some extra comparison functions for our users. > > > However, we’ve noticed that filter push-down (using ` > > > CoreRules.FILTER_INTO_JOIN`) does not occur when the operands to the > > > functions come from the opposite side of an outer join (i.e. from the > > > right > > > side of a left outer join, or from the left side of a right outer join). > > > > > > Here is a demonstration of this with SQL, the logical plan, and the > > > physical plan post optimization: https://pastebin.com/raw/KjE40z5X > > > In this example, I’ve defined a simple function called “test” which takes > > > a BigInt and returns Boolean. > > > In the first query, the operand to `test` comes from the left side of the > > > left join, and the tree before planning has the filter node above the > > > join, > > > and after planning the filter is below the join. > > > In the second query, the operand to `test` comes from the left side of the > > > right join, and the tree before planning has the filter node above the > > > join, but after planning the filter is still above the join. > > > (I was hoping to get the output from the RuleEventLogger, but I haven’t > > > been able to get it working.) > > > > > > I figure the push down is not happening because we are not properly > > > communicating how these functions handles null (which is to return null, > > > which would be false-y, and therefore allow the join to be converted to an > > > inner join and the filter pushed down below the join). > > > We are not providing these functions as SqlOperator instances in a > > > SqlOperatorTable; instead we use `ScalarFunctionImpl.create` on native > > > methods, and provide those Function instances through the Schema, via > > > `AbstractSchema.getFunctionMultimap` (which eventually make it to the > > > CatalogReader) > > > I’m guessing that if we were providing these via a SqlOperatorTable (which > > > we’re hoping to do sometime soon) that having the return type of the > > > operator be nullable, or have the nullability be inferred from the > > > operands, would allow the planner to push the filter below the join. > > > > > > Am I right? > > > In the meantime, is there a way to provide this nullability information > > > through `ScalarFunctionImpl.create` pathway we’re currently using? > > > > > > Thanks! > > > -Ian J. Bertolacci > > > > > > > -- > > Best, > Benchao Li >
