Uh oh!
There was an error while loading. Please reload this page.
[SPARK-15076][SQL] Add ReorderAssociativeOperator optimizer - #12850
[SPARK-15076][SQL] Add ReorderAssociativeOperator optimizer#12850dongjoon-hyun wants to merge 5 commits into
Conversation
SparkQA
commented
May 3, 2016
Test build #57567 has finished for PR 12850 at commit
|
SparkQA
commented
May 4, 2016
Test build #57781 has finished for PR 12850 at commit
|
SparkQA
commented
May 6, 2016
Test build #58006 has finished for PR 12850 at commit
|
SparkQA
commented
May 8, 2016
Test build #58113 has finished for PR 12850 at commit
|
dongjoon-hyun
commented
May 10, 2016
Rebased to see the result on re-enable hive queries. |
SparkQA
commented
May 10, 2016
Test build #58246 has finished for PR 12850 at commit
|
SparkQA
commented
May 13, 2016
Test build #58519 has finished for PR 12850 at commit
|
SparkQA
commented
May 16, 2016
Test build #58648 has finished for PR 12850 at commit
|
SparkQA
commented
May 19, 2016
Test build #58875 has finished for PR 12850 at commit
|
dongjoon-hyun
commented
May 19, 2016
Rebased to trigger Jenkins test again. |
SparkQA
commented
May 19, 2016
Test build #58884 has finished for PR 12850 at commit
|
SparkQA
commented
May 22, 2016
Test build #59114 has finished for PR 12850 at commit
|
dongjoon-hyun
commented
May 24, 2016
SparkQA
commented
May 27, 2016
Test build #59531 has finished for PR 12850 at commit
|
There was a problem hiding this comment.
what about a + 1 + b + 2? I think we need a more general approach, like reordering the Add nodes to put all literals together.
There was a problem hiding this comment.
Thank you for review, @cloud-fan !
I see. That sounds great.
Let me think about how to eliminate all constants then.
SparkQA
commented
May 31, 2016
Test build #59645 has finished for PR 12850 at commit
|
Hi, @cloud-fan . |
There was a problem hiding this comment.
Similar to ReorderJoin, we should have a new rule ReorderAssociativeOperator to do this optimization, instead of putting it in ConstantFolding.
There was a problem hiding this comment.
Oh, that could be.
There is some difference on level of granulity.
Join-related optimizers might be improved later to cost-based optimizers while ConstantFolder optimizer is just about removing constants on a single expression.
Do you think it is a good idea to put the different levels of concerns together?
I can do this in any way you decide. :)
There was a problem hiding this comment.
I think this is OK, BooleanSimplification is also kind of constant folding but we made a new rule for it.
dongjoon-hyun
commented
May 31, 2016
Hi, @cloud-fan . |
SparkQA
commented
May 31, 2016
Test build #59691 has finished for PR 12850 at commit
|
SparkQA
commented
May 31, 2016
Test build #59690 has finished for PR 12850 at commit
|
SparkQA
commented
Jun 1, 2016
Test build #59700 has finished for PR 12850 at commit
|
dongjoon-hyun
commented
Jun 1, 2016
Hi, @cloud-fan . |
cloud-fan
commented
Jun 1, 2016
I discussed it with @davies offline and here is our conclusion:
In general, we think this feature brings too much nondeterminacy compared to the benefits it brings. What do you think? |
dongjoon-hyun
commented
Jun 1, 2016
Thank you for deep discussion on this. I think like this. For 1), there are machine-generated queries by BI tools. This is an important category of queries. In many cases, BIs (or other tools having UI) will generated queries by simple rules and those rule does not care about the output queries. The optimization is the role of DBMS or Spark. So, static optimizations are always important. This PR also minimizes the size of generated codes, too. For 2), other optimizers already remove or duplicate UDFs. Spark dose not give the control of the execution order. As you know, we already made the conclusion to leave an explicit note like the following for this (in SPARK-15282 and #13087). For 3), could you give some problematic real cases? This PR reordered only addition or multiplications, but I think this PR does not change the final result value. The following is the behavior of current Spark. (Not this PR. You can see that in the physical plan.) scala> sql("select 2147483640 + a + 7 from (select explode(array(1,2,3)) a)").explain()
==PhysicalPlan==*Project [((2147483640+ a#8) +7) AS ((2147483640+ a) +7)#9]
+-Generate explode([1,2,3]), false, false, [a#8]
+-ScanOneRowRelation[]
scala> sql("select 2147483640 + a + 7 from (select explode(array(1,2,3)) a)").collect()
res1:Array[org.apache.spark.sql.Row] =Array([-2147483648], [-2147483647], [-2147483646])
scala> sql("select a + 2147483647 from (select explode(array(1,2,3)) a)").collect()
res2:Array[org.apache.spark.sql.Row] =Array([-2147483648], [-2147483647], [-2147483646])
scala> sql("select 214748364 * a from (select explode(array(1,2,3)) a)").collect()
res3:Array[org.apache.spark.sql.Row] =Array([214748364], [429496728], [644245092])
scala> sql("select 214748364 * a * 10 from (select explode(array(1,2,3)) a)").collect()
res4:Array[org.apache.spark.sql.Row] =Array([2147483640], [-16], [2147483624])
scala> sql("select a * 2147483640 from (select explode(array(1,2,3)) a)").collect()
res5:Array[org.apache.spark.sql.Row] =Array([2147483640], [-16], [2147483624])Apparently, the optimization of this PR will work like the above. |
dongjoon-hyun
commented
Jun 1, 2016
Hi, @cloud-fan and @davies . |
cloud-fan
commented
Jun 1, 2016
UDF is the first thing I came out, and yes, it must be deterministic. But as we have the You can still improve this PR to handle non-deterministic cases, but that will make this PR more complex and harder to reason about, which may not worth. cc @davies |
dongjoon-hyun
commented
Jun 1, 2016
Thank you for feedback. I'm really happy with your attention! |
dongjoon-hyun
commented
Jun 1, 2016
I added the missing part, |
There was a problem hiding this comment.
how about
def flattenAdd(e: Expression): Seq[Expression] = e match {
case Add(l, r) => flattenAdd(l) ++ flattenAdd(r)
case other => other
}
...
plan transformAllExpressions {
case a: Add if a.deterministic && a.dataType.isInstanceOf[IntegralType] =>
val (foldables, others) => flattenAdd(a).partition(_.foldable)
if (foldables.size > 1) {
val foldableExpr = foldables.reduce(Add(_, _))
val c = Literal.create(foldableExpr.eval(), a.dataType)
if (others.isEmpty) c else Add(others.reduce(Add(_, _)), c)
} else {
a
}
}
We can duplicate some code for Multiply, and I think this maybe more readable than the current version.
There was a problem hiding this comment.
I see. That could be.
We also need to add isSingleOperatorExpr there.
Otherwise, flattenAdd(Add(Multiply(1, 2), 3)) -> (3).
There was a problem hiding this comment.
flattenAdd(Add(Multiply(1, 2), 3)) will become [Multiply(1, 2), 3], and we won't get wrong result
There was a problem hiding this comment.
Oh, I see. You generalize my PR again! Great!
cloud-fan
commented
Jun 2, 2016
looks like it's not such difficult to handle all cases, this optimization LGTM |
There was a problem hiding this comment.
I already added non-deterministic case here.
dongjoon-hyun
commented
Jun 2, 2016
Thank you for reconsidering this PR positively. I'll update soon according to your advice. |
dongjoon-hyun
commented
Jun 2, 2016
@cloud-fan . |
SparkQA
commented
Jun 2, 2016
Test build #59788 has finished for PR 12850 at commit
|
SparkQA
commented
Jun 2, 2016
Test build #59795 has finished for PR 12850 at commit
|
| case Multiply(l, r) => flattenMultiply(l) ++ flattenMultiply(r) | ||
| case other => other :: Nil | ||
| } | ||
There was a problem hiding this comment.
we should do:
plan transform {
case q: LogicalPlan => q transformExpressionsDown {
......
}
}
or here we just optimize the top level plan.
There was a problem hiding this comment.
My bad. I changed this in a hurry. I'll fix soon.
cloud-fan
commented
Jun 2, 2016
cc @davies , can you take a look? |
rxin
commented
Jun 2, 2016
BTW it goes without saying ... if you do decide to merge this, don't merge it in branch-2.0. |
SparkQA
commented
Jun 2, 2016
Test build #59824 has finished for PR 12850 at commit
|
cloud-fan
commented
Jun 2, 2016
thanks, merging to master! |
dongjoon-hyun
commented
Jun 2, 2016
Oh, thank you! @cloud-fan . |
What changes were proposed in this pull request?
This issue add a new optimizer
ReorderAssociativeOperatorby taking advantage of integral associative property. Currently, Spark works like the following.1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + ainto45 + a.a + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9.This PR can handle Case 2 for Add/Multiply expression whose data types are
ByteType,ShortType,IntegerType, andLongType. The followings are the plan comparison betweenbeforeandafterthis issue.Before
After
This PR is greatly generalized by @cloud-fan 's key ideas; he should be credited for the work he did.
How was this patch tested?
Pass the Jenkins tests including new testsuite.