Skip to content

Conversation

@LuciferYang
Copy link
Contributor

@LuciferYang LuciferYang commented Sep 10, 2020

What changes were proposed in this pull request?

After #29660 and #29689 there are 13 remaining failed cases of sql core module with Scala 2.13.

The reason for the remaining failed cases is the optimization result of CostBasedJoinReorder maybe different with same input in Scala 2.12 and Scala 2.13 if there are more than one same cost candidate plans.

In this pr give a way to make the optimization result deterministic as much as possible to pass all remaining failed cases of sql/core module in Scala 2.13, the main change of this pr as follow:

  • Change to use LinkedHashMap instead of Map to store foundPlans in JoinReorderDP.search method to ensure same iteration order with same insert order because iteration order of Map behave differently under Scala 2.12 and 2.13

  • Fixed StarJoinCostBasedReorderSuite affected by the above change

  • Regenerate golden files affected by the above change.

Why are the changes needed?

We need to support a Scala 2.13 build.

Does this PR introduce any user-facing change?

No

How was this patch tested?

  • Scala 2.12: Pass the Jenkins or GitHub Action

  • Scala 2.13: All tests passed.

Do the following:

dev/change-scala-version.sh 2.13
mvn clean install -DskipTests  -pl sql/core -Pscala-2.13 -am
mvn test -pl sql/core -Pscala-2.13

Before

Tests: succeeded 8485, failed 13, canceled 1, ignored 52, pending 0
*** 13 TESTS FAILED ***

After

Tests: succeeded 8498, failed 0, canceled 1, ignored 52, pending 0
All tests passed.

@LuciferYang
Copy link
Contributor Author

LuciferYang commented Sep 10, 2020

cc @srowen , this patch fixed remaining failed cases of sql core module with Scala 2.13 and after this patch all test passed now.

@LuciferYang LuciferYang changed the title [SPARK-32808][SQL] Let CostBasedJoinReorder produce deterministic result with Scala 2.12 and 2.13 [SPARK-32808][SQL] Pass all test of sql/core module in Scala 2.13 Sep 10, 2020
Copy link
Member

@srowen srowen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like @cloud-fan or @gatorsmile to review just because it changes so many of the expected results.

// SPARK-32687: Change to use `LinkedHashMap` to make sure that items are
// inserted and iterated in the same order.
val ret = new mutable.LinkedHashMap[Set[Int], JoinPlan]()
idToJoinPlanSeq.foreach(v => ret.put(v._1, v._2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just construct this above, with a .foreach instead of .map? or just call .addAll on the result of the .map.
I guess LinkedHashMap takes more memory, but that shouldn't matter much here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it ~ Address 10d4953 fix this.


/** Map[set of item ids, join plan for these items] */
type JoinPlanMap = Map[Set[Int], JoinPlan]
type JoinPlanMap = mutable.LinkedHashMap[Set[Int], JoinPlan]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is OK, though it's not strictly necessary to make the type def this specific

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to use LinkedHashMap instead of Map to store foundPlans in JoinReorderDP.search method to ensure same iteration order with same insert order because iteration order of Map behave differently under Scala 2.12 and 2.13

Can we make it as a separate PR? The plan changes need more reviews

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to use Map[Set[Int], JoinPlan] or not to define JoinPlanMap type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gatorsmile Use a separate JIRA number?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same JIRA I think, just a separate PR. I'm not sure it matters that much though, it's a tiny part of the change really? we just need more eyes on the plan changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same JIRA I think, just a separate PR. I'm not sure it matters that much though, it's a tiny part of the change really? we just need more eyes on the plan changes.

It seems that there is no way to divide 2 PR because if we change CostBasedJoinReorder only, the test cases in sql/core module will be failed.

Copy link
Contributor Author

@LuciferYang LuciferYang Sep 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So all excepted plan changes are due to use of LinkedHashMap instead of Map

@SparkQA
Copy link

SparkQA commented Sep 10, 2020

Test build #128507 has finished for PR 29711 at commit 8a0bb43.

  • This patch fails SparkR unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@LuciferYang
Copy link
Contributor Author

LuciferYang commented Sep 10, 2020

@gatorsmile @srowen @cloud-fan already make this as a separate PR SPARK-32848, #29717

@LuciferYang LuciferYang reopened this Sep 10, 2020
@SparkQA
Copy link

SparkQA commented Sep 10, 2020

Test build #128530 has finished for PR 29711 at commit 10d4953.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

: : : +- * Filter (8)
: : : +- * ColumnarToRow (7)
: : : +- Scan parquet default.store_sales (6)
: : : +- * BroadcastHashJoin Inner BuildRight (9)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm skimming the changes, and this seems non-trivial? but then again I am not so sure how to read these plans expertly enough to evaluate. The plan below starts by scanning a different table, for example.

We may just have to accept changes like this, if they're equivalent, to make sure they do not depend on implementation details of hash maps. But @gatorsmile @cloud-fan et al do these look like plausible equivalent plans for example?

Exchange [ss_customer_sk] #2
WholeStageCodegen (4)
Project [i_brand_id,i_brand,i_manufact_id,i_manufact,ss_customer_sk,ss_ext_sales_price,s_zip]
Project [ss_customer_sk,ss_ext_sales_price,i_brand_id,i_brand,i_manufact_id,i_manufact,s_zip]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this kind of thing possibly affect the order of columns from a select * or is that accounted for elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

val newJoin = Join(left, right, Inner, joinConds.reduceOption(And), JoinHint.NONE)
val collectedJoinConds = joinConds ++ oneJoinPlan.joinConds ++ otherJoinPlan.joinConds
val remainingConds = conditions -- collectedJoinConds
val neededAttr = AttributeSet(remainingConds.flatMap(_.references)) ++ topOutput
val neededFromNewJoin = newJoin.output.filter(neededAttr.contains)
val newPlan =
if ((newJoin.outputSet -- neededFromNewJoin).nonEmpty) {
Project(neededFromNewJoin, newJoin)
} else {
newJoin
}

Project node add by above code part in JoinReorderDP#buildJoin method, I think the Project output order decided by join order

Copy link
Contributor

@cloud-fan cloud-fan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change is safe, as it just switches to LinkedHashMap. I looked at a few plan changes and they are indeed no-op, e.g. change from "A join B" to "B join A" without changing the build side.

@LuciferYang
Copy link
Contributor Author

@srowen @gatorsmile Is there any other problem in this pr that needs to be fixed? It seems that @cloud-fan thinks the change is safe.

@srowen
Copy link
Member

srowen commented Sep 17, 2020

I'll merge this tomorrow if there are no more objections.

@srowen
Copy link
Member

srowen commented Sep 18, 2020

Merged to master

@srowen srowen closed this in 2128c4f Sep 18, 2020
@LuciferYang
Copy link
Contributor Author

thx~ @srowen @cloud-fan @gatorsmile

@LuciferYang LuciferYang deleted the SPARK-32808-3 branch June 6, 2022 03:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants