-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-55617][SQL] Add VariantGet to V2ExpressionBuilder for DSv2 filter pushdown #54394
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.spark.sql.connector.expressions; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| import org.apache.spark.annotation.Evolving; | ||
| import org.apache.spark.sql.internal.connector.ExpressionWithToString; | ||
| import org.apache.spark.sql.types.DataType; | ||
|
|
||
| /** | ||
| * Variant get expression. | ||
| * | ||
| * @since 4.1.0 | ||
| */ | ||
| @Evolving | ||
| public class VariantGet extends ExpressionWithToString { | ||
| private final Expression child; | ||
| private final String path; | ||
| private final DataType targetType; | ||
| private final boolean failOnError; | ||
| private final String timeZoneId; | ||
|
|
||
| /** | ||
| * Creates VariantGet expression. | ||
| * @param child variant column reference | ||
| * @param path JSON path string | ||
| * @param targetType expected result type | ||
| * @param failOnError whether to throw on cast failure ({@code variant_get}) or return null | ||
| * ({@code try_variant_get}) | ||
| * @param timeZoneId timezone bound on the catalyst expression for timestamp casts, or null | ||
| */ | ||
| public VariantGet( | ||
| Expression child, | ||
| String path, | ||
| DataType targetType, | ||
| boolean failOnError, | ||
| String timeZoneId) { | ||
| this.child = child; | ||
| this.path = path; | ||
| this.targetType = targetType; | ||
| this.failOnError = failOnError; | ||
| this.timeZoneId = timeZoneId; | ||
| } | ||
|
|
||
| public Expression child() { return child; } | ||
| public String path() { return path; } | ||
| public DataType targetType() { return targetType; } | ||
| public boolean failOnError() { return failOnError; } | ||
| public String timeZoneId() { return timeZoneId; } | ||
|
|
||
| @Override | ||
| public Expression[] children() { return new Expression[]{ child }; } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| VariantGet that = (VariantGet) o; | ||
| return failOnError == that.failOnError && | ||
| Objects.equals(child, that.child) && | ||
| Objects.equals(path, that.path) && | ||
| Objects.equals(targetType, that.targetType) && | ||
| Objects.equals(timeZoneId, that.timeZoneId); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(child, path, targetType, failOnError, timeZoneId); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,9 +22,10 @@ import org.apache.spark.internal.LogKeys.EXPR | |
| import org.apache.spark.sql.catalyst.expressions._ | ||
| import org.apache.spark.sql.catalyst.expressions.aggregate.{AggregateExpression, AggregateFunction, Complete} | ||
| import org.apache.spark.sql.catalyst.expressions.objects.{Invoke, StaticInvoke} | ||
| import org.apache.spark.sql.catalyst.expressions.variant.VariantGet | ||
| import org.apache.spark.sql.catalyst.optimizer.ConstantFolding | ||
| import org.apache.spark.sql.connector.catalog.functions.ScalarFunction | ||
| import org.apache.spark.sql.connector.expressions.{Cast => V2Cast, Expression => V2Expression, Extract => V2Extract, FieldReference, GeneralScalarExpression, GetArrayItem => V2GetArrayItem, LiteralValue, NullOrdering, SortDirection, SortValue, UserDefinedScalarFunc} | ||
| import org.apache.spark.sql.connector.expressions.{Cast => V2Cast, Expression => V2Expression, Extract => V2Extract, FieldReference, GeneralScalarExpression, GetArrayItem => V2GetArrayItem, LiteralValue, NullOrdering, SortDirection, SortValue, UserDefinedScalarFunc, VariantGet => V2VariantGet} | ||
| import org.apache.spark.sql.connector.expressions.aggregate.{AggregateFunc, Avg, Count, CountStar, GeneralAggregateFunc, Max, Min, Sum, UserDefinedAggregateFunc} | ||
| import org.apache.spark.sql.connector.expressions.filter.{AlwaysFalse, AlwaysTrue, And => V2And, Not => V2Not, Or => V2Or, Predicate => V2Predicate} | ||
| import org.apache.spark.sql.internal.SQLConf | ||
|
|
@@ -333,6 +334,18 @@ class V2ExpressionBuilder(e: Expression, isPredicate: Boolean = false) extends L | |
| case _ => | ||
| None | ||
| } | ||
| case v: VariantGet if v.path.foldable => | ||
| (Option(v.path.eval()).map(_.toString), generateExpression(v.child)) match { | ||
| case (Some(path), Some(colRef: FieldReference)) => | ||
| val vg = new V2VariantGet(colRef, path, v.targetType, v.failOnError, | ||
| v.timeZoneId.orNull) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added two more tests:
|
||
| if (isPredicate && v.dataType.isInstanceOf[BooleanType]) { | ||
| Some(new V2Predicate("BOOLEAN_EXPRESSION", Array[V2Expression](vg))) | ||
| } else { | ||
| Some(vg) | ||
| } | ||
| case _ => None | ||
| } | ||
| // TODO supports other expressions | ||
| case ApplyFunctionExpression(function, children) => | ||
| val childrenExpressions = children.flatMap(generateExpression(_)) | ||
|
|
||
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.
@gengliangwang this needs to be revised
Jira ticket is resolved with Fix Version 5.0.0, commit goes master and branch-4.x, API is marked
@since 4.1.0There 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.
@pan3793 thanks, I just created #56537 for this.