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/09/05 18:34:04 UTC

[incubator-sedona] branch master updated: [SEDONA-159] Add Nth accessor functions to the Flink API (#679)

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 0083d2c3 [SEDONA-159] Add Nth accessor functions to the Flink API (#679)
0083d2c3 is described below

commit 0083d2c3a9c3443013c9de0dca1e6e368196294f
Author: Kengo Seki <se...@apache.org>
AuthorDate: Tue Sep 6 03:33:59 2022 +0900

    [SEDONA-159] Add Nth accessor functions to the Flink API (#679)
---
 .../java/org/apache/sedona/common/Functions.java   | 17 ++++++++
 docs/api/flink/Function.md                         | 30 ++++++++++++++
 .../main/java/org/apache/sedona/flink/Catalog.java |  2 +
 .../apache/sedona/flink/expressions/Functions.java | 16 ++++++++
 .../java/org/apache/sedona/flink/FunctionTest.java | 16 ++++++++
 .../sql/sedona_sql/expressions/Functions.scala     | 48 +---------------------
 6 files changed, 83 insertions(+), 46 deletions(-)

diff --git a/common/src/main/java/org/apache/sedona/common/Functions.java b/common/src/main/java/org/apache/sedona/common/Functions.java
index c6714c75..11498f99 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -157,6 +157,23 @@ public class Functions {
         return geometry.reverse();
     }
 
+    public static Geometry geometryN(Geometry geometry, int n) {
+        if (n < geometry.getNumGeometries()) {
+            return geometry.getGeometryN(n);
+        }
+        return null;
+    }
+
+    public static Geometry interiorRingN(Geometry geometry, int n) {
+        if (geometry instanceof Polygon) {
+            Polygon polygon = (Polygon) geometry;
+            if (n < polygon.getNumInteriorRing()) {
+                return polygon.getInteriorRingN(n);
+            }
+        }
+        return null;
+    }
+
     public static Geometry pointN(Geometry geometry, int n) {
         if(!(geometry instanceof LineString)) {
             return null;
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 53b4925c..760721cc 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -281,6 +281,36 @@ Result:
 +-----------------------------+
 ```
 
+## ST_GeometryN
+
+Introduction: Return the 0-based Nth geometry if the geometry is a GEOMETRYCOLLECTION, (MULTI)POINT, (MULTI)LINESTRING, MULTICURVE or (MULTI)POLYGON. Otherwise, return null
+
+Format: `ST_GeometryN(geom: geometry, n: Int)`
+
+Since: `v1.3.0`
+
+Example:
+```SQL
+SELECT ST_GeometryN(ST_GeomFromText('MULTIPOINT((1 2), (3 4), (5 6), (8 9))'), 1)
+```
+
+Output: `POINT (3 4)`
+
+## ST_InteriorRingN
+
+Introduction: Returns the Nth interior linestring ring of the polygon geometry. Returns NULL if the geometry is not a polygon or the given N is out of range
+
+Format: `ST_InteriorRingN(geom: geometry, n: Int)`
+
+Since: `v1.3.0`
+
+Example:
+```SQL
+SELECT ST_InteriorRingN(ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0), (1 1, 2 1, 2 2, 1 2, 1 1), (1 3, 2 3, 2 4, 1 4, 1 3), (3 3, 4 3, 4 4, 3 4, 3 3))'), 0)
+```
+
+Output: `LINEARRING (1 1, 2 1, 2 2, 1 2, 1 1)`
+
 ## ST_IsClosed
 
 Introduction: RETURNS true if the LINESTRING start and end point are the same.
diff --git a/flink/src/main/java/org/apache/sedona/flink/Catalog.java b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
index f4787411..97244865 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -45,6 +45,8 @@ public class Catalog {
                 new Functions.ST_GeoHash(),
                 new Functions.ST_PointOnSurface(),
                 new Functions.ST_Reverse(),
+                new Functions.ST_GeometryN(),
+                new Functions.ST_InteriorRingN(),
                 new Functions.ST_PointN(),
                 new Functions.ST_ExteriorRing(),
                 new Functions.ST_AsEWKT(),
diff --git a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
index 33f890d4..e11ba35e 100644
--- a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
+++ b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
@@ -133,6 +133,22 @@ public class Functions {
         }
     }
 
+    public static class ST_GeometryN extends ScalarFunction {
+        @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+        public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o, int n) {
+            Geometry geom = (Geometry) o;
+            return org.apache.sedona.common.Functions.geometryN(geom, n);
+        }
+    }
+
+    public static class ST_InteriorRingN extends ScalarFunction {
+        @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+        public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o, int n) {
+            Geometry geom = (Geometry) o;
+            return org.apache.sedona.common.Functions.interiorRingN(geom, n);
+        }
+    }
+
     public static class ST_PointN extends ScalarFunction {
         @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
         public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o, int n) {
diff --git a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
index a5994e5f..bd3a8d24 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -144,6 +144,22 @@ public class FunctionTest extends TestBase{
         assertEquals("POLYGON ((-0.5 -0.5, 0.5 -0.5, 0.5 0.5, -0.5 0.5, -0.5 -0.5))", result.toString());
     }
 
+    @Test
+    public void testGeometryN() {
+        Table collectionTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))') AS collection");
+        Table resultTable = collectionTable.select(call(Functions.ST_GeometryN.class.getSimpleName(), $("collection"), 1));
+        Point point = (Point) first(resultTable).getField(0);
+        assertEquals("POINT (30 30)", point.toString());
+    }
+
+    @Test
+    public void testInteriorRingN() {
+        Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromText('POLYGON((7 9,8 7,11 6,15 8,16 6,17 7,17 10,18 12,17 14,15 15,11 15,10 13,9 12,7 9),(9 9,10 10,11 11,11 10,10 8,9 9),(12 14,15 14,13 11,12 14))') AS polygon");
+        Table resultTable = polygonTable.select(call(Functions.ST_InteriorRingN.class.getSimpleName(), $("polygon"), 1));
+        LinearRing linearRing = (LinearRing) first(resultTable).getField(0);
+        assertEquals("LINEARRING (12 14, 15 14, 13 11, 12 14)", linearRing.toString());
+    }
+
     @Test
     public void testPointN_positiveN() {
         int n = 1;
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
index 5b742429..73b351f7 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
@@ -20,7 +20,6 @@ package org.apache.spark.sql.sedona_sql.expressions
 
 import org.apache.sedona.common.Functions
 import org.apache.sedona.sql.utils.GeometrySerializer
-import org.apache.spark.internal.Logging
 import org.apache.spark.sql.catalyst.InternalRow
 import org.apache.spark.sql.catalyst.expressions.codegen.CodegenFallback
 import org.apache.spark.sql.catalyst.expressions._
@@ -793,33 +792,7 @@ case class ST_ExteriorRing(inputExpressions: Seq[Expression])
 
 
 case class ST_GeometryN(inputExpressions: Seq[Expression])
-  extends Expression with CodegenFallback with Logging {
-  assert(inputExpressions.length == 2)
-
-  override def nullable: Boolean = true
-
-  override def eval(input: InternalRow): Any = {
-    val geometry = inputExpressions(0).toGeometry(input)
-    val n = inputExpressions(1).toInt(input)
-    geometry match {
-      case geom: Geometry => getNthGeom(geom, n)
-      case _ => null
-    }
-  }
-
-  private def getNthGeom(geom: Geometry, index: Int): GenericArrayData = {
-    val nthGeom = Try(geom.getGeometryN(index))
-    nthGeom match {
-      case Failure(exception) =>
-        logWarning(s"Geometry ${geom.toString}, Out Of index")
-        null
-      case Success(geom) => geom.toGenericArrayData
-    }
-  }
-
-  override def dataType: DataType = GeometryUDT
-
-  override def children: Seq[Expression] = inputExpressions
+  extends InferredBinaryExpression(Functions.geometryN) {
 
   protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
     copy(inputExpressions = newChildren)
@@ -827,24 +800,7 @@ case class ST_GeometryN(inputExpressions: Seq[Expression])
 }
 
 case class ST_InteriorRingN(inputExpressions: Seq[Expression])
-  extends Expression with CodegenFallback {
-  assert(inputExpressions.length == 2)
-
-  override def nullable: Boolean = true
-
-  override def eval(input: InternalRow): Any = {
-    val geometry = inputExpressions(0).toGeometry(input)
-    val n = inputExpressions(1).toInt(input)
-    geometry match {
-      case geom: Polygon => geom.getInteriorRingN(n)
-        .toGenericArrayData
-      case _ => null
-    }
-  }
-
-  override def dataType: DataType = GeometryUDT
-
-  override def children: Seq[Expression] = inputExpressions
+  extends InferredBinaryExpression(Functions.interiorRingN) {
 
   protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
     copy(inputExpressions = newChildren)