Hi, guys, it seems that the discussion silent now, so do we have some 
conclusion that can contribute to current code, i.e. the suggested API change 
or new abstraction ?

Or better, can someone give a design doc so that we can push and make that 
implemented ?

Personally I was always looking forward to the result, because Apache Flink 
suffers for the bad planning performance for Join re-order or traits 
auto-adapter.

Best,
Danny Chan
在 2019年11月20日 +0800 AM2:14,Vladimir Ozerov <ppoze...@gmail.com>,写道:
> HI Igor,
>
> Thank you for the details. Meanwhile, I solved it with separation of
> conversion rules from the physical optimization rules. So the first pass
> creates physical nodes with unknown physical properties (top-bottom), while
> subsequent processing of the leaf nodes triggers rules which convert "bad"
> physical nodes to "good" physical nodes with know distribution and
> collation.
>
> Regards,
> Vladimir.
>
> пн, 18 нояб. 2019 г. в 13:43, Seliverstov Igor <gvvinbl...@gmail.com>:
>
> > Vladimir,
> >
> > Hope it may help you.
> >
> > Currently we applied the next way (just rough description):
> >
> > 1) We created an API to derive possible traits permutations on the basis
> > of children traits (quite similar to one, described in «On Demand trait
> > set request» topic)
> >
> > 2) added a general rule that copies Logical nodes, but requesting our
> > convention from their children (IGNITE convention, ANY distribution, EMPTY
> > collation) and sets importance of old Logical nodes to zero - so, we have a
> > Logical parent which input satisfies any possible distribution and no rules
> > matched to previous logical node any more.
> >
> > 3) Physical rules to create physical rel nodes only if physical traits may
> > be derived (there is no «barrier», described in one of previous messages) -
> > derived traits are a collection, we don’t create a physical rel node for
> > each possible traits set, also we may set zero importance for previously
> > created rel nodes to decrease search space.
> >
> > Now we know actual and required distribution, we don’t need
> > AbstractConverters and able just call TraitDef.convert() method inside a
> > rule.
> > A rule still able to produce the same output several times, but
> > «memorization" inside the planner solves it for us.
> >
> > preliminary tests show almost zero overhead of the approach.
> >
> > Regards,
> > Igor
> >
> >
> > > 14 нояб. 2019 г., в 14:49, Vladimir Ozerov <ppoze...@gmail.com>
> > написал(а):
> > >
> > > Hi Xing,
> > >
> > > Thanks for your suggestion. Yes, this may help, and if I get your idea
> > > right, I already had it in my reproducer:
> > > 1) Create the converted physical input:
> > >
> > https://github.com/devozerov/calcite-optimizer/blob/master/src/main/java/devozerov/physical/ProjectPhysicalRule.java#L49
> > > 2) Use it in case no physical children were found:
> > >
> > https://github.com/devozerov/calcite-optimizer/blob/master/src/main/java/devozerov/physical/ProjectPhysicalRule.java#L79
> > >
> > > This idea is borrowed from Apache Drill physical rules. But the problem
> > is
> > > that this approach leads to a suboptimal plan - parent node doesn't know
> > > the future distribution of a child node. And as a result, it doesn't know
> > > it's own distribution. So the final plan is constructed in that way:
> > > 1.1) Root enforced "SINGLETON" on its child:
> > > -> PhysicalRoot[SINGLETON]
> > > -> Converter[SINGLETON]
> > > -> PhysicalProject[*ANY*]
> > > -> PhysicalScan[REPLICATED]
> > >
> > > 1.2) But since the child (PhysicalProject) failed to infer distribution
> > > during rule call, it falls back to ANY distribution. In order to satisfy
> > > SINGLETON distribution of a parent, we inject an exchange in the final
> > plan:
> > > -> PhysicalRoot[SINGLETON]
> > > * -> Exchange[SINGLETON]*
> > > -> PhysicalProject[*ANY*]
> > > -> PhysicalScan[REPLICATED]
> > >
> > > 2) But this is a suboptimal plan. The optimal plan is:
> > > -> PhysicalRoot[SINGLETON]
> > > -> PhysicalProject[REPLICATED]
> > > -> PhysicalScan[REPLICATED]
> > >
> > > You may observe it in my tests:
> > > 1)
> > >
> > https://github.com/devozerov/calcite-optimizer/blob/master/src/test/java/devozerov/OptimizerTest.java#L46
> > > -
> > > works as you described and produces not optimal plan with exchange
> > > 2)
> > >
> > https://github.com/devozerov/calcite-optimizer/blob/master/src/test/java/devozerov/OptimizerTest.java#L30
> > > -
> > > rely on AbstractConverter-s and produce an optimal plan with bottom-up
> > > trait propagation at the cost of significantly increased planning time
> > >
> > > Regards,
> > > Vladimir.
> > >
> > > пт, 8 нояб. 2019 г. в 16:15, XING JIN <jinxing.co...@gmail.com>:
> > >
> > > > Hi Vladimir,
> > > >
> > > > I think the way PlannerTests#GoodSingleRule and EnumerableXXXRule work
> > may
> > > > help you ~
> > > > They work by a top-down fashion, but when matching parent, they convert
> > the
> > > > children explicitly.
> > > > You may try below steps:
> > > > 1. Construct a rule LogicalParentRule to match the LogicalParent without
> > > > distribution/physical requirement for the LogicalChild;
> > > > 2. In this rule, you call 'planner.changeTraits' on the LogicalChild to
> > > > build a new child with physical convention. Note that at this moment
> > only
> > > > an empty RelSubset is created and no PhysicalChild exists.
> > > > 3. Then set the RelNode to be the new input of LogicalParent;
> > > >
> > > > By above steps, you can build a parent-child relationship between
> > > > LogicalParent and PhysicalChild, and at last the PhysicalParentRule
> > will be
> > > > fired based on this relationship.
> > > >
> > > > I have a commit to illustrate my idea, check VolcanoPlannerTest#testDEV
> > in
> > > > below link, hope it may help you ~
> > > > https://github.com/jinxing64/calcite/tree/demo
> > > >
> > > > Also I'm +1 with Seliverstov that to get all parents of a set, which
> > > > against the current check in RelSubset#getParentRels
> > > >
> > > > Best,
> > > > Jin
> > > >
> > > > Vladimir Ozerov <ppoze...@gmail.com> 于2019年11月5日周二 下午6:41写道:
> > > >
> > > > > Hi Xiening,
> > > > >
> > > > > I read the thread about on-demand trait requests. It seems pretty
> > similar
> > > > > to what I am trying to achieve, as it facilitates the bottom-up
> > > > propagation
> > > > > of physical traits. In fact, both your and my strategy propagate 
> > > > > traits
> > > > > bottom-up, but I do this through rules, which also fire bottom-up,
> > while
> > > > in
> > > > > your case only the traits are propagated bottom-up, while rules
> > continue
> > > > > working in a top-down fashion.
> > > > >
> > > > > However, I am thinking of how I would potentially implement my
> > optimizer
> > > > > with your approach, and it feels like with on-demand traits resulting
> > > > > implementation of metadata queries may become very complex to that
> > point
> > > > > that it will look like another set of rules, parallel to the already
> > > > > existing ruleset. For example, consider that I have a couple of
> > > > distributed
> > > > > tables in an OLTP application. These tables have a number of indexes,
> > > > and I
> > > > > would like to join them. First, I have a number of choices on how to
> > join
> > > > > tables with respect to distribution. Then, I have a number of choices
> > on
> > > > > which access method to use. Because sometimes it is beneficial to pick
> > > > > index scans instead of table scans even without index conditions, for
> > > > > example, to preserve a comfortable collation. So when my logical scan
> > > > > receives such metadata request, it typically cannot return all 
> > > > > possible
> > > > > combinations, because there are too many of them. Instead, some
> > > > heuristical
> > > > > or cost-based logic will be used to calculate a couple of most
> > > > prospective
> > > > > ones. But it seems that we will have to duplicate the same logic in 
> > > > > the
> > > > > corresponding rule, aren't we?
> > > > >
> > > > > I would love to read your design because this is a really interesting
> > > > > topic, and it is of great importance for the distributed engines
> > > > developed
> > > > > on top of Calcite since proper use of distribution and collation is 
> > > > > the
> > > > key
> > > > > success factor for efficient query optimization.
> > > > >
> > > > > Regards,
> > > > > Vladimir.
> > > > >
> > > > > пт, 1 нояб. 2019 г. в 00:40, Xiening Dai <xndai....@gmail.com>:
> > > > >
> > > > > > Actually we solved this problem in our setup using a mechanism 
> > > > > > called
> > > > > > “Pull-Up Traits”, which explores the possible trait set of 
> > > > > > children’s
> > > > > input
> > > > > > to decide parent’s physical properties. In order to determine child
> > > > input
> > > > > > trait, you would have to look at child’s children, and all the way 
> > > > > > to
> > > > the
> > > > > > leaves nodes or a barrier. A barrier is a rel node which cannot 
> > > > > > derive
> > > > > any
> > > > > > traits regardless the input. A good example would be a user define
> > > > > function
> > > > > > which would throw off any distribution or collation. Then we realize
> > > > just
> > > > > > pulling up is not enough, sometimes we would need to look at 
> > > > > > parent’s
> > > > > > requirement as well. So we try to solve this in a unified framework,
> > > > > which
> > > > > > we call “On Demand Trait” and implement it as part of the framework 
> > > > > > so
> > > > > > anyone can be benefited. I hope Haisheng can share a design doc once
> > we
> > > > > > have more concrete ideas.
> > > > > >
> > > > > >
> > > > > > > On Oct 31, 2019, at 11:37 AM, Jinfeng Ni <j...@apache.org> wrote:
> > > > > > >
> > > > > > > Hi Vladimir,
> > > > > > >
> > > > > > > The SubsetTransformer interface and the iterating over the 
> > > > > > > RelNodes
> > > > > > > within a RelSubset in Drill is exactly implemented to do the trait
> > > > > > > propagation. We also had to rely on AbstractConverter to fire
> > > > > > > necessary rule to avoid the CanNotPlan issue. At some point, 
> > > > > > > Calcite
> > > > > > > community chooses to remove AbstractConverter and Drill had to 
> > > > > > > add it
> > > > > > > back, which is probably one of the main reasons for us to continue
> > > > > > > using a Calcite fork. I still remember we constantly had to deal
> > > > with
> > > > > > > the dilemma between "CanNotPlan" and long planing time due to
> > > > explored
> > > > > > > search space.
> > > > > > >
> > > > > > > Glad to see more people are joining the effort to solve this long
> > > > > > > overdue issue, something missing in Calcite's core optimizer
> > > > framework
> > > > > > > "since before Calcite was Calcite" (Jacques's words).
> > > > > > >
> > > > > > > Jinfeng
> > > > > > >
> > > > > > >
> > > > > > > On Thu, Oct 31, 2019 at 3:38 AM Vladimir Ozerov 
> > > > > > > <ppoze...@gmail.com>
> > > > > > wrote:
> > > > > > > >
> > > > > > > > Hi Danny,
> > > > > > > >
> > > > > > > > Thank you very much for the links. What is described here is 
> > > > > > > > pretty
> > > > > much
> > > > > > > > similar to the problem I describe. Especially the discussion 
> > > > > > > > about
> > > > > trait
> > > > > > > > propagation, as this is basically what I need - to explore 
> > > > > > > > potential
> > > > > > traits
> > > > > > > > of children before optimizing parents. And this is basically 
> > > > > > > > what
> > > > > Drill
> > > > > > > > already does with it's SubsetTransformer:
> > > > > > > > 1) There is a SubsetTransformer interface, which iterates over
> > > > > physical
> > > > > > > > relations of the given subset [1]
> > > > > > > > 2) If you want to make a physical project, you iterate over 
> > > > > > > > physical
> > > > > > > > relations of the input subset and create possible physical 
> > > > > > > > projects
> > > > > [2]
> > > > > > > > 3) But if you cannot find any physical input, then you trigger
> > > > > creation
> > > > > > of
> > > > > > > > a "bad" physical project, which is very likely to have poor cost
> > > > > > because it
> > > > > > > > cannot take advantage of input's distribution information [3]
> > > > > > > > So, step 2 - is a trait set propagation which is needed by many
> > > > > > > > distributed engines. Step 3 - an attempt to workaround current
> > > > > > > > VolcanoPlanner behavior, when a parent rule is fired only if
> > > > produced
> > > > > > child
> > > > > > > > node has compatible trait set.
> > > > > > > >
> > > > > > > > I do not know Calcite's architecture that good but at first 
> > > > > > > > glance,
> > > > > the
> > > > > > > > proposed ability to re-fire rules of a specific Rel seems good
> > > > enough.
> > > > > > It
> > > > > > > > doesn't expand search space, because no new nodes are created, 
> > > > > > > > and
> > > > it
> > > > > > seems
> > > > > > > > to be relatively simple to implement.
> > > > > > > >
> > > > > > > > [1]
> > > > > > > >
> > > > > >
> > > > >
> > > >
> > https://github.com/apache/drill/blob/1.16.0/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/SubsetTransformer.java
> > > > > > > > [2]
> > > > > > > >
> > > > > >
> > > > >
> > > >
> > https://github.com/apache/drill/blob/1.16.0/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/ProjectPrule.java#L66
> > > > > > > > [3]
> > > > > > > >
> > > > > >
> > > > >
> > > >
> > https://github.com/apache/drill/blob/1.16.0/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/ProjectPrule.java#L69
> > > > > > > >
> > > > > > > > чт, 31 окт. 2019 г. в 12:21, Danny Chan <yuzhao....@gmail.com>:
> > > > > > > >
> > > > > > > > > Thanks Vladimir for bringing up this discussion !
> > > > > > > > >
> > > > > > > > > Did you notice that there is a JIRA issue about this problem 
> > > > > > > > > ? [1]
> > > > > > Also a
> > > > > > > > > discussion about how to propagate the traits [2]
> > > > > > > > >
> > > > > > > > > [1] https://issues.apache.org/jira/browse/CALCITE-2970
> > > > > > > > > [2]
> > > > > > > > >
> > > > > >
> > > > >
> > > >
> > https://ponymail-vm.apache.org/_GUI_/thread.html/79dac47ea50b5dfbd3f234e368ed61d247fb0eb989f87fe01aedaf25@%3Cdev.calcite.apache.org%3E
> > > > > > > > >
> > > > > > > > > Best,
> > > > > > > > > Danny Chan
> > > > > > > > > 在 2019年10月31日 +0800 PM3:56,Vladimir Ozerov <ppoze...@gmail.com
> > > > > ,写道:
> > > > > > > > > > Hi colleagues,
> > > > > > > > > >
> > > > > > > > > > I would like to discuss with the community the possibility 
> > > > > > > > > > of
> > > > > adding a
> > > > > > > > > new
> > > > > > > > > > public method to VolcanoPlanner which will forcefully 
> > > > > > > > > > re-trigger
> > > > the
> > > > > > > > > rules
> > > > > > > > > > for the specific rel. This is a follow up of a discussion 
> > > > > > > > > > started
> > > > in
> > > > > > the
> > > > > > > > > > other thread [1].
> > > > > > > > > >
> > > > > > > > > > **Problem statement**
> > > > > > > > > > When converting between conventions during optimization
> > > > > VolcanoPlanner
> > > > > > > > > > prefers the top-bottom approach, so that the nodes are 
> > > > > > > > > > converted
> > > > > from
> > > > > > the
> > > > > > > > > > root. But in some cases, the intermediate node must be 
> > > > > > > > > > converted
> > > > > after
> > > > > > > > > its
> > > > > > > > > > children. This is especially true for distributed SQL 
> > > > > > > > > > engines,
> > > > which
> > > > > > rely
> > > > > > > > > > on distribution traits during the optimization process: it 
> > > > > > > > > > is not
> > > > > > > > > possible
> > > > > > > > > > to efficiently choose a proper physical implementation of a 
> > > > > > > > > > parent
> > > > > > node
> > > > > > > > > > unless the physical representation of a child node is known.
> > > > > > > > > >
> > > > > > > > > > It seems that presently VolcanoPlanner cannot address such 
> > > > > > > > > > cases
> > > > by
> > > > > > > > > > default. Consider that we have two nodes and associated 
> > > > > > > > > > rules
> > > > which
> > > > > > > > > convert
> > > > > > > > > > them to physical counterparts:
> > > > > > > > > > [LogicalParent <- LogicalChild]
> > > > > > > > > > The parent should be converted after the child. When the 
> > > > > > > > > > child is
> > > > > > > > > > converted, the physical node is created:
> > > > > > > > > > [LogicalParent <- {LogicalChild, PhysicalChild}]
> > > > > > > > > > In order to finish the optimization process, we need to 
> > > > > > > > > > convert
> > > > the
> > > > > > > > > parent.
> > > > > > > > > > But parent rules are not fired, because PhysicalChild has 
> > > > > > > > > > traits
> > > > > > > > > > incompatible with LogicalParent.
> > > > > > > > > >
> > > > > > > > > > Presently the problem could be solved in two ways:
> > > > > > > > > > 1) Always produce conversions when going top-down. In this 
> > > > > > > > > > case, I
> > > > > > first
> > > > > > > > > > create a physical parent, then a physical child. The 
> > > > > > > > > > problem is
> > > > that
> > > > > > > > > > created parent is not optimal because it didn't know child
> > > > > > distribution
> > > > > > > > > at
> > > > > > > > > > the time of creation. So the full flow would be: create a 
> > > > > > > > > > bad
> > > > > parent,
> > > > > > > > > > create a good child, create a good parent.
> > > > > > > > > > 1.1) [LogicalParent <- LogicalChild]
> > > > > > > > > > 1.2) [{LogicalParent, PhysicalParentBad} <- LogicalChild]
> > > > > > > > > > 1.3) [{LogicalParent, PhysicalParentBad} <- {LogicalChild,
> > > > > > > > > PhysicalChild}]
> > > > > > > > > > 1.4) [{LogicalParent, PhysicalParentBad, 
> > > > > > > > > > PhysicalParentGood} <-
> > > > > > > > > > {LogicalChild, PhysicalChild}]
> > > > > > > > > > What is worse, the creation of a not optimal parent will 
> > > > > > > > > > trigger
> > > > > > rules on
> > > > > > > > > > its parent, which in turn may create a not optimal 
> > > > > > > > > > parent-parent
> > > > > node,
> > > > > > > > > etc.
> > > > > > > > > >
> > > > > > > > > > 2) Make sure that your convention returns true for
> > > > > > > > > > Convention.canConvertConvention. In this case, every time a 
> > > > > > > > > > new
> > > > rel
> > > > > is
> > > > > > > > > > added to a RelSet, its traitset will be compared to 
> > > > > > > > > > traitsets of
> > > > all
> > > > > > > > > other
> > > > > > > > > > rels in the set. For every pair of traitset we may ask the 
> > > > > > > > > > engine
> > > > to
> > > > > > > > > create
> > > > > > > > > > a relevant AbstractConverter. The net effect is that
> > > > > > > > > "physical-to-logical"
> > > > > > > > > > converter is created, which re-triggers the rule on the 
> > > > > > > > > > logical
> > > > > parent
> > > > > > > > > > since their conventions are compatible:
> > > > > > > > > > 2.1) [LogicalParent <- LogicalChild]
> > > > > > > > > > 2.2) [LogicalParent <- {LogicalChild, PhysicalChild}]
> > > > > > > > > > 2.3) [LogicalParent <- {LogicalChild, PhysicalChild,
> > > > > > > > > > PhysicalToLogicalConverter}]
> > > > > > > > > > 2.4) [{LogicalParent, PhysicalParent} <- {LogicalChild,
> > > > > PhysicalChild,
> > > > > > > > > > PhysicalToLogicalConverter}]
> > > > > > > > > >
> > > > > > > > > > The problem with that approach is that it is too 
> > > > > > > > > > coarse-grained
> > > > > since
> > > > > > we
> > > > > > > > > > operate on traitsets rather than rels. As a result, 
> > > > > > > > > > additional
> > > > > memory
> > > > > > and
> > > > > > > > > > CPU pressure are introduced because usually too many 
> > > > > > > > > > converters
> > > > are
> > > > > > > > > > created, which triggers the rules over and over again.
> > > > > > > > > >
> > > > > > > > > > **Affected products**
> > > > > > > > > > At the moment two distributed engines are being developed 
> > > > > > > > > > for
> > > > > > Hazelcast
> > > > > > > > > and
> > > > > > > > > > Apache Ignite. Both require bottom-up optimization and 
> > > > > > > > > > currently
> > > > > rely
> > > > > > on
> > > > > > > > > > the second workaround.
> > > > > > > > > > Another example is Apache Drill. I do not know whether its
> > > > community
> > > > > > is
> > > > > > > > > > concerned with the issue, but it also uses bottom-up 
> > > > > > > > > > optimization
> > > > > for
> > > > > > > > > many
> > > > > > > > > > rules and employs both the aforementioned workarounds. As a
> > > > result,
> > > > > I
> > > > > > > > > guess
> > > > > > > > > > that Drill's optimizer also creates too many rels during
> > > > > optimization
> > > > > > and
> > > > > > > > > > suffer from huge search space. Please correct me if I am 
> > > > > > > > > > wrong.
> > > > > > > > > >
> > > > > > > > > > **Proposal**
> > > > > > > > > > The key problem is that there is no way to re-fire rules on 
> > > > > > > > > > a
> > > > > specific
> > > > > > > > > > node. The original problem could have been solved, if it 
> > > > > > > > > > would be
> > > > > > > > > possible
> > > > > > > > > > to re-fire rules on a LogicalParent without creating any
> > > > additional
> > > > > > rels.
> > > > > > > > > > That would lead to a clear optimization flow:
> > > > > > > > > > 2.1) [LogicalParent <- LogicalChild]
> > > > > > > > > > 2.2) [LogicalParent <- {LogicalChild, PhysicalChild}]
> > > > > > > > > > 2.3) [{LogicalParent, PhysicalParent} <- {LogicalChild,
> > > > > > PhysicalChild}]
> > > > > > > > > >
> > > > > > > > > > We can add the following method to VolcanoPlanner 
> > > > > > > > > > (RelOptPlanner?)
> > > > > > > > > > interface:
> > > > > > > > > > void fireRules(RelNode rel)
> > > > > > > > > >
> > > > > > > > > > This method will fire the rules on a passed node in a 
> > > > > > > > > > deferred
> > > > mode
> > > > > > as if
> > > > > > > > > > it was the new node just added to the optimizer. This would
> > > > require
> > > > > > > > > slight
> > > > > > > > > > changes to RuleQueue.addMatch method, and possibly some 
> > > > > > > > > > other
> > > > > places.
> > > > > > > > > >
> > > > > > > > > > Usage example:
> > > > > > > > > > class PhysicalChildRule extends RelOptRule {
> > > > > > > > > > void onMatch(RelOptRuleCall call) {
> > > > > > > > > > LogicalChild logicalRel = call.get(0);
> > > > > > > > > > PhysicalChild physicalRel = ...;
> > > > > > > > > >
> > > > > > > > > > call.transformTo(physicalRel);
> > > > > > > > > > optimizer.fireRules(logicalRel);
> > > > > > > > > > }
> > > > > > > > > > }
> > > > > > > > > >
> > > > > > > > > > What does the community think about such a method? Does it 
> > > > > > > > > > make
> > > > any
> > > > > > sense
> > > > > > > > > > to you? If not, do you aware of any other ways on how to 
> > > > > > > > > > organize
> > > > > > > > > bottom-up
> > > > > > > > > > optimization with VolcanoPlanner without the creation of
> > > > additional
> > > > > > rels?
> > > > > > > > > >
> > > > > > > > > > If the community is OK in general, I can create try to 
> > > > > > > > > > create a PR
> > > > > > with a
> > > > > > > > > > prototype.
> > > > > > > > > >
> > > > > > > > > > Would appreciate your feedback.
> > > > > > > > > >
> > > > > > > > > > Regards,
> > > > > > > > > > Vladimir.
> > > > > > > > > >
> > > > > > > > > > [1]
> > > > > > > > > >
> > > > > > > > >
> > > > > >
> > > > >
> > > >
> > https://ponymail-vm.apache.org/_GUI_/thread.html/13e7ab2040bfa4902db6647992ec4203ceb0262cfcb28d38ef7e9e32@%3Cdev.calcite.apache.org%3E
> > > > > > > > >
> > > > > >
> > > > > >
> > > > >
> > > >
> >
> >

Reply via email to