You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by ji...@apache.org on 2022/11/16 03:30:06 UTC
[incubator-sedona] branch master updated: [SEDONA-192] Null handling in predicates (#712)
This is an automated email from the ASF dual-hosted git repository.
jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-sedona.git
The following commit(s) were added to refs/heads/master by this push:
new 1a0c8e23 [SEDONA-192] Null handling in predicates (#712)
1a0c8e23 is described below
commit 1a0c8e237344c8e2ef95b1eb3104881021d37105
Author: Tanel Kiis <ta...@users.noreply.github.com>
AuthorDate: Wed Nov 16 05:30:00 2022 +0200
[SEDONA-192] Null handling in predicates (#712)
---
.../sql/sedona_sql/expressions/Predicates.scala | 28 +++++++++++++++-------
.../org/apache/sedona/sql/predicateTestScala.scala | 18 ++++++++++++++
2 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Predicates.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Predicates.scala
index 454110fe..9d9d1261 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Predicates.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Predicates.scala
@@ -20,22 +20,24 @@ package org.apache.spark.sql.sedona_sql.expressions
import org.apache.sedona.sql.utils.GeometrySerializer
import org.apache.spark.sql.catalyst.InternalRow
-import org.apache.spark.sql.catalyst.expressions.Expression
+import org.apache.spark.sql.catalyst.expressions.{ExpectsInputTypes, Expression, NullIntolerant}
import org.apache.spark.sql.catalyst.expressions.codegen.CodegenFallback
import org.apache.spark.sql.catalyst.util.ArrayData
import org.apache.spark.sql.types.{BooleanType, DataType}
import org.locationtech.jts.geom.Geometry
-import org.apache.spark.sql.catalyst.expressions.ExpectsInputTypes
import org.apache.spark.sql.types.AbstractDataType
import org.apache.spark.sql.sedona_sql.UDT.GeometryUDT
-abstract class ST_Predicate extends Expression with FoldableExpression with ExpectsInputTypes {
+abstract class ST_Predicate extends Expression
+ with FoldableExpression
+ with ExpectsInputTypes
+ with NullIntolerant {
def inputExpressions: Seq[Expression]
override def toString: String = s" **${this.getClass.getName}** "
- override def nullable: Boolean = false
+ override def nullable: Boolean = children.exists(_.nullable)
override def inputTypes: Seq[AbstractDataType] = Seq(GeometryUDT, GeometryUDT)
@@ -43,12 +45,20 @@ abstract class ST_Predicate extends Expression with FoldableExpression with Expe
override def children: Seq[Expression] = inputExpressions
- override def eval(inputRow: InternalRow): Any = {
+ override final def eval(inputRow: InternalRow): Any = {
val leftArray = inputExpressions(0).eval(inputRow).asInstanceOf[ArrayData]
- val rightArray = inputExpressions(1).eval(inputRow).asInstanceOf[ArrayData]
- val leftGeometry = GeometrySerializer.deserialize(leftArray)
- val rightGeometry = GeometrySerializer.deserialize(rightArray)
- evalGeom(leftGeometry, rightGeometry)
+ if (leftArray == null) {
+ null
+ } else {
+ val rightArray = inputExpressions(1).eval(inputRow).asInstanceOf[ArrayData]
+ if (rightArray == null) {
+ null
+ } else {
+ val leftGeometry = GeometrySerializer.deserialize(leftArray)
+ val rightGeometry = GeometrySerializer.deserialize(rightArray)
+ evalGeom(leftGeometry, rightGeometry)
+ }
+ }
}
def evalGeom(leftGeometry: Geometry, rightGeometry: Geometry): Boolean
diff --git a/sql/src/test/scala/org/apache/sedona/sql/predicateTestScala.scala b/sql/src/test/scala/org/apache/sedona/sql/predicateTestScala.scala
index c870e058..da0c088f 100644
--- a/sql/src/test/scala/org/apache/sedona/sql/predicateTestScala.scala
+++ b/sql/src/test/scala/org/apache/sedona/sql/predicateTestScala.scala
@@ -19,6 +19,9 @@
package org.apache.sedona.sql
+import org.apache.spark.sql.catalyst.expressions.{EmptyRow, Literal}
+import org.apache.spark.sql.sedona_sql.expressions.{ST_Contains, ST_CoveredBy, ST_Covers, ST_Crosses, ST_Disjoint, ST_Equals, ST_Intersects, ST_OrderingEquals, ST_Overlaps, ST_Point, ST_Touches, ST_Within}
+
class predicateTestScala extends TestBaseScala {
describe("Sedona-SQL Predicate Test") {
@@ -245,5 +248,20 @@ class predicateTestScala extends TestBaseScala {
assert(!within.get(0).asInstanceOf[Boolean])
assert(coveredBy.get(0).asInstanceOf[Boolean])
}
+
+ Seq(
+ ST_Contains, ST_Intersects, ST_Within, ST_Covers, ST_CoveredBy, ST_Crosses,
+ ST_Overlaps, ST_Touches, ST_Equals, ST_Disjoint, ST_OrderingEquals
+ ).foreach { predicate =>
+ it(s"Passed null handling in $predicate") {
+ val point = ST_Point(Literal.create(0.0) :: Literal.create(0.0) :: Literal.create(0.0):: Nil)
+ val missing = Literal.create(null)
+
+ assert(predicate(point :: point :: Nil).eval(EmptyRow) != null)
+ assert(predicate(point :: missing :: Nil).eval(EmptyRow) == null)
+ assert(predicate(missing :: point :: Nil).eval(EmptyRow) == null)
+ assert(predicate(missing :: missing :: Nil).eval(EmptyRow) == null)
+ }
+ }
}
}