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/07 23:01:04 UTC
[incubator-sedona] branch master updated: [SEDONA-164] Add geometry count functions to the Flink API (#684)
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 dad4e5ee [SEDONA-164] Add geometry count functions to the Flink API (#684)
dad4e5ee is described below
commit dad4e5ee0754f3b694eca830e7335560f85f2e03
Author: Kengo Seki <se...@apache.org>
AuthorDate: Thu Sep 8 08:00:59 2022 +0900
[SEDONA-164] Add geometry count functions to the Flink API (#684)
---
.../java/org/apache/sedona/common/Functions.java | 15 ++++++++
docs/api/flink/Function.md | 43 ++++++++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 3 ++
.../apache/sedona/flink/expressions/Functions.java | 24 ++++++++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 21 +++++++++++
.../sql/sedona_sql/expressions/Functions.scala | 36 ++----------------
.../expressions/NullSafeExpressions.scala | 4 ++
7 files changed, 113 insertions(+), 33 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 3c729bc9..d3e6bcc3 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -209,6 +209,21 @@ public class Functions {
return writer.write(geometry).toString();
}
+ public static int nPoints(Geometry geometry) {
+ return geometry.getNumPoints();
+ }
+
+ public static int numGeometries(Geometry geometry) {
+ return geometry.getNumGeometries();
+ }
+
+ public static Integer numInteriorRings(Geometry geometry) {
+ if (geometry instanceof Polygon) {
+ return ((Polygon) geometry).getNumInteriorRing();
+ }
+ return null;
+ }
+
public static String asGML(Geometry geometry) {
return new GMLWriter().write(geometry);
}
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 1396cfda..b21c0bba 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -431,6 +431,49 @@ SELECT ST_Length(polygondf.countyshape)
FROM polygondf
```
+## ST_NPoints
+
+Introduction: Returns the number of points of the geometry
+
+Since: `v1.3.0`
+
+Format: `ST_NPoints (A:geometry)`
+
+Example:
+```SQL
+SELECT ST_NPoints(polygondf.countyshape)
+FROM polygondf
+```
+
+## ST_NumGeometries
+
+Introduction: Returns the number of Geometries. If geometry is a GEOMETRYCOLLECTION (or MULTI*) return the number of geometries, for single geometries will return 1.
+
+Format: `ST_NumGeometries (A:geometry)`
+
+Since: `v1.3.0`
+
+Example:
+```SQL
+SELECT ST_NumGeometries(df.geometry)
+FROM df
+```
+
+## ST_NumInteriorRings
+
+Introduction: Returns number of interior rings of polygon geometries.
+
+Format: `ST_NumInteriorRings(geom: geometry)`
+
+Since: `v1.3.0`
+
+Example:
+```SQL
+SELECT ST_NumInteriorRings(ST_GeomFromText('POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0), (1 1, 2 1, 2 2, 1 2, 1 1))'))
+```
+
+Output: `1`
+
## ST_PointN
Introduction: Return the Nth point in a single linestring or circular linestring in the geometry. Negative values are counted backwards from the end of the LineString, so that -1 is the last point. Returns NULL if there is no linestring in the geometry.
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 48e9a7b5..7b246f44 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -50,6 +50,9 @@ public class Catalog {
new Functions.ST_GeometryN(),
new Functions.ST_InteriorRingN(),
new Functions.ST_PointN(),
+ new Functions.ST_NPoints(),
+ new Functions.ST_NumGeometries(),
+ new Functions.ST_NumInteriorRings(),
new Functions.ST_ExteriorRing(),
new Functions.ST_AsEWKT(),
new Functions.ST_AsEWKB(),
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 798065f7..a7965446 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
@@ -173,6 +173,30 @@ public class Functions {
}
}
+ public static class ST_NPoints extends ScalarFunction {
+ @DataTypeHint("Integer")
+ public Integer eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) {
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.nPoints(geom);
+ }
+ }
+
+ public static class ST_NumGeometries extends ScalarFunction {
+ @DataTypeHint("Integer")
+ public Integer eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) {
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.numGeometries(geom);
+ }
+ }
+
+ public static class ST_NumInteriorRings extends ScalarFunction {
+ @DataTypeHint("Integer")
+ public Integer eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) {
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.numInteriorRings(geom);
+ }
+ }
+
public static class ST_ExteriorRing 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) {
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 a78e6ad1..a7f44d14 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -197,6 +197,27 @@ public class FunctionTest extends TestBase{
assertEquals("POINT (0.5 0.5)", point.toString());
}
+ @Test
+ public void testNPoints() {
+ Table polygonTable = createPolygonTable(1);
+ Table resultTable = polygonTable.select(call(Functions.ST_NPoints.class.getSimpleName(), $(polygonColNames[0])));
+ assertEquals(5, first(resultTable).getField(0));
+ }
+
+ @Test
+ public void testNumGeometries() {
+ 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_NumGeometries.class.getSimpleName(), $("collection")));
+ assertEquals(3, first(resultTable).getField(0));
+ }
+
+ @Test
+ public void testNumInteriorRings() {
+ 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_NumInteriorRings.class.getSimpleName(), $("polygon")));
+ assertEquals(2, first(resultTable).getField(0));
+ }
+
@Test
public void testExteriorRing() {
Table polygonTable = createPolygonTable(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 450ea530..9d7da6d8 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
@@ -107,15 +107,7 @@ case class ST_ConvexHull(inputExpressions: Seq[Expression])
* @param inputExpressions
*/
case class ST_NPoints(inputExpressions: Seq[Expression])
- extends UnaryGeometryExpression with CodegenFallback {
-
- override def nullSafeEval(geometry: Geometry): Any = {
- geometry.getCoordinates.length
- }
-
- override def dataType: DataType = IntegerType
-
- override def children: Seq[Expression] = inputExpressions
+ extends InferredUnaryExpression(Functions.nPoints) {
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
copy(inputExpressions = newChildren)
@@ -840,19 +832,7 @@ case class ST_IsClosed(inputExpressions: Seq[Expression])
}
case class ST_NumInteriorRings(inputExpressions: Seq[Expression])
- extends UnaryGeometryExpression with CodegenFallback {
- assert(inputExpressions.length == 1)
-
- override protected def nullSafeEval(geometry: Geometry): Any = {
- geometry match {
- case polygon: Polygon => polygon.getNumInteriorRing
- case _: Geometry => null
- }
- }
-
- override def dataType: DataType = IntegerType
-
- override def children: Seq[Expression] = inputExpressions
+ extends InferredUnaryExpression(Functions.numInteriorRings) {
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
copy(inputExpressions = newChildren)
@@ -972,17 +952,7 @@ case class ST_IsRing(inputExpressions: Seq[Expression])
* @param inputExpressions Geometry
*/
case class ST_NumGeometries(inputExpressions: Seq[Expression])
- extends UnaryGeometryExpression with CodegenFallback {
- assert(inputExpressions.length == 1)
-
- override protected def nullSafeEval(geometry: Geometry): Any = {
- geometry.getNumGeometries()
- }
-
- override def dataType: DataType = IntegerType
-
-
- override def children: Seq[Expression] = inputExpressions
+ extends InferredUnaryExpression(Functions.numGeometries) {
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
copy(inputExpressions = newChildren)
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala
index 4fe2d5b1..8b2b1496 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/NullSafeExpressions.scala
@@ -74,6 +74,8 @@ object InferrableType {
new InferrableType[Geometry] {}
implicit val javaDoubleInstance: InferrableType[java.lang.Double] =
new InferrableType[java.lang.Double] {}
+ implicit val javaIntegerInstance: InferrableType[java.lang.Integer] =
+ new InferrableType[java.lang.Integer] {}
implicit val doubleInstance: InferrableType[Double] =
new InferrableType[Double] {}
implicit val booleanInstance: InferrableType[Boolean] =
@@ -120,6 +122,8 @@ object InferredTypes {
GeometryUDT
} else if (typeOf[T] =:= typeOf[java.lang.Double]) {
DoubleType
+ } else if (typeOf[T] =:= typeOf[java.lang.Integer]) {
+ IntegerType
} else if (typeOf[T] =:= typeOf[Double]) {
DoubleType
} else if (typeOf[T] =:= typeOf[Int]) {