-
Notifications
You must be signed in to change notification settings - Fork 28.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SPARK-35794][SQL] Allow custom plugin for AQE cost evaluator #32944
Conversation
cc @cloud-fan could you help take a look when you have time? Thanks. |
does it work well with #32816 ? |
@cloud-fan - I think so. If we decide merge this first, then in #32816, we don't need the extra config |
Kubernetes integration test starting |
Kubernetes integration test status failure |
@c21 thank you for ping me. Not sure it's worth to make cost evaluator as plugin. You mentioned sort (I think it's local sort, isn't it ?), and can you provide a real use case about it ? |
Test build #139911 has finished for PR 32944 at commit
|
I don't think it's that simple. If force-skew-join-handling is enabled, Spark must use |
@ulysses-you - e.g.
AQE might change it to
With our Cosco remote shuffle service, we already implemented the sorted shuffle ( |
@cloud-fan - from my checking of #32816, it looks like the only logic controlled by the new config |
@c21 thanks for the explaination, the example |
@ulysses-you - sure, I agree with boolean config is more intuitive and easier to use. If we do need the boolean config, we can add special logic in |
.version("3.2.0") | ||
.internal() | ||
.stringConf | ||
.createWithDefault("org.apache.spark.sql.execution.adaptive.SimpleCostEvaluator") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can make it an optional conf: spark.sql.adaptive.customCostEvaluatorClass
. If not set, we use the builtin impl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cloud-fan - sure, updated.
*/ | ||
def instantiate(className: String): CostEvaluator = { | ||
logDebug(s"Creating CostEvaluator $className") | ||
val clazz = Utils.classForName[CostEvaluator](className) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use the standard API in Spark: Utils.loadExtensions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cloud-fan - good call, updated.
@@ -38,7 +38,7 @@ case class SimpleCost(value: Long) extends Cost { | |||
* A simple implementation of [[CostEvaluator]], which counts the number of | |||
* [[ShuffleExchangeLike]] nodes in the plan. | |||
*/ | |||
object SimpleCostEvaluator extends CostEvaluator { | |||
case class SimpleCostEvaluator() extends CostEvaluator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can still be an object, if we follow https://github.com/apache/spark/pull/32944/files#r662513062
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cloud-fan - yeah, updated.
Kubernetes integration test starting |
Kubernetes integration test status success |
@@ -3555,6 +3564,9 @@ class SQLConf extends Serializable with Logging { | |||
|
|||
def coalesceShufflePartitionsEnabled: Boolean = getConf(COALESCE_PARTITIONS_ENABLED) | |||
|
|||
def adaptiveCustomCostEvaluatorClass: Option[String] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we don't have to create a method here if it's only called once
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cloud-fan - sure, updated.
val query = "SELECT * FROM testData join testData2 ON key = a where value = '1'" | ||
|
||
withSQLConf(SQLConf.ADAPTIVE_CUSTOM_COST_EVALUATOR_CLASS.key -> | ||
"org.apache.spark.sql.execution.adaptive.SimpleShuffleSortCostEvaluator") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this custom cost evaluator change the query plan? It seems to be the same with the builtin cost evaluator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cloud-fan - this evaluator does not change plan, and to be the same with the builtin evaluator for this query. Do we want to come up a different one here? I think this just validates the custom evaluator works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM, let's leave it then
Test build #140547 has finished for PR 32944 at commit
|
@c21 can you fix the code conflicts? |
@cloud-fan - thanks, just rebased to latest master. |
Kubernetes integration test starting |
sql/core/src/main/scala/org/apache/spark/sql/execution/adaptive/AdaptiveSparkPlanExec.scala
Show resolved
Hide resolved
sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala
Outdated
Show resolved
Hide resolved
@c21, can you at least mark |
Kubernetes integration test status success |
Kubernetes integration test starting |
Kubernetes integration test status success |
Test build #140567 has finished for PR 32944 at commit
|
Test build #140570 has finished for PR 32944 at commit
|
@HyukjinKwon - updated per discussion, and this is ready for review again, thanks. |
Kubernetes integration test starting |
Kubernetes integration test status success |
Test build #140618 has finished for PR 32944 at commit
|
buildConf("spark.sql.adaptive.customCostEvaluatorClass") | ||
.doc("The custom cost evaluator class to be used for adaptive execution. If not being set," + | ||
" Spark will use its own SimpleCostEvaluator by default.") | ||
.version("3.2.0") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the only think is that the version has to be 3.3.0 since we cut the branch now. Since this PR won't likely affect anything in the main code, I am okay with merging to 3.2.0 either tho. I will leave it to @cloud-fan and you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3.2 is the first version that enables AQE by default, and this seems to be a useful extension. Let's include it in 3.2.
thanks, merging to master/3.2! |
### What changes were proposed in this pull request? Current AQE has cost evaluator to decide whether to use new plan after replanning. The current used evaluator is `SimpleCostEvaluator` to make decision based on number of shuffle in the query plan. This is not perfect cost evaluator, and different production environments might want to use different custom evaluators. E.g., sometimes we might want to still do skew join even though it might introduce extra shuffle (trade off resource for better latency), sometimes we might want to take sort into consideration for cost as well. Take our own setting as an example, we are using a custom remote shuffle service (Cosco), and the cost model is more complicated. So We want to make the cost evaluator to be pluggable, and developers can implement their own `CostEvaluator` subclass and plug in dynamically based on configuration. The approach is to introduce a new config to allow define sub-class name of `CostEvaluator` - `spark.sql.adaptive.customCostEvaluatorClass`. And add `CostEvaluator.instantiate` to instantiate the cost evaluator class in `AdaptiveSparkPlanExec.costEvaluator`. ### Why are the changes needed? Make AQE cost evaluation more flexible. ### Does this PR introduce _any_ user-facing change? No but an internal config is introduced - `spark.sql.adaptive.customCostEvaluatorClass` to allow custom implementation of `CostEvaluator`. ### How was this patch tested? Added unit test in `AdaptiveQueryExecSuite.scala`. Closes #32944 from c21/aqe-cost. Authored-by: Cheng Su <chengsu@fb.com> Signed-off-by: Wenchen Fan <wenchen@databricks.com> (cherry picked from commit 044dddf) Signed-off-by: Wenchen Fan <wenchen@databricks.com>
Thank you @cloud-fan and @HyukjinKwon for review! |
What changes were proposed in this pull request?
Current AQE has cost evaluator to decide whether to use new plan after replanning. The current used evaluator is
SimpleCostEvaluator
to make decision based on number of shuffle in the query plan. This is not perfect cost evaluator, and different production environments might want to use different custom evaluators. E.g., sometimes we might want to still do skew join even though it might introduce extra shuffle (trade off resource for better latency), sometimes we might want to take sort into consideration for cost as well. Take our own setting as an example, we are using a custom remote shuffle service (Cosco), and the cost model is more complicated. So We want to make the cost evaluator to be pluggable, and developers can implement their ownCostEvaluator
subclass and plug in dynamically based on configuration.The approach is to introduce a new config to allow define sub-class name of
CostEvaluator
-spark.sql.adaptive.customCostEvaluatorClass
. And addCostEvaluator.instantiate
to instantiate the cost evaluator class inAdaptiveSparkPlanExec.costEvaluator
.Why are the changes needed?
Make AQE cost evaluation more flexible.
Does this PR introduce any user-facing change?
No but an internal config is introduced -
spark.sql.adaptive.customCostEvaluatorClass
to allow custom implementation ofCostEvaluator
.How was this patch tested?
Added unit test in
AdaptiveQueryExecSuite.scala
.