You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ja...@apache.org on 2020/12/02 22:46:49 UTC
[incubator-pinot] branch master updated: some geo function
improvements (#6306)
This is an automated email from the ASF dual-hosted git repository.
jackie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push:
new 4be939a some geo function improvements (#6306)
4be939a is described below
commit 4be939ae2a1a87c8e914208b1928d3f943698f4c
Author: Yupeng Fu <yu...@users.noreply.github.com>
AuthorDate: Wed Dec 2 14:46:30 2020 -0800
some geo function improvements (#6306)
## Description
- Add a third parameter to `ST_Point` to create the point in geography, this simplifies the geographic point creation. Instead of `ST_GeogFromText(ST_AsText(ST_Point(group_lat, group_lon))`, we can now use `ST_Point(group_lat, group_lon, 1)`.
- Support `ST_Point` creation from literal such as `ST_Point(44.183189,-115.761905)`
- Swapped latitude, longitude for `ST_Distance` calculation for geography.
## Upgrade Notes
- The signature of `ST_Point` is changed to take an optional third parameter. 0 (default) means geometry, 1 means geography
- In `ST_Distance(ST_Point( y1,x1), ST_Point(y2, x2))` is changed to `ST_Distance(ST_Point(x1, y1), ST_Point(x1, y2))` for geography
## Release Notes
The sequence of latitude, longitude is changed for the points in ST_Distance
---
.../pinot/common/utils/request/RequestUtils.java | 10 ++++++++
.../pinot/core/geospatial/GeometryUtils.java | 16 +++++++++++++
.../transform/function/ScalarFunctions.java | 18 +++++++++++++++
.../transform/function/StContainsFunction.java | 12 +++++-----
.../transform/function/StDistanceFunction.java | 11 +++++----
.../transform/function/StPointFunction.java | 18 +++++++++------
.../function/LiteralTransformFunction.java | 8 ++++++-
.../transform/StDistanceFunctionTest.java | 8 +++----
.../geospatial/transform/StPointFunctionTest.java | 27 +++++++++++++++++++---
.../meetupRsvp_realtime_table_config.json | 4 +++-
10 files changed, 105 insertions(+), 27 deletions(-)
diff --git a/pinot-common/src/main/java/org/apache/pinot/common/utils/request/RequestUtils.java b/pinot-common/src/main/java/org/apache/pinot/common/utils/request/RequestUtils.java
index f7863cb..7e330b9 100644
--- a/pinot-common/src/main/java/org/apache/pinot/common/utils/request/RequestUtils.java
+++ b/pinot-common/src/main/java/org/apache/pinot/common/utils/request/RequestUtils.java
@@ -41,6 +41,7 @@ import org.apache.pinot.pql.parsers.pql2.ast.IntegerLiteralAstNode;
import org.apache.pinot.pql.parsers.pql2.ast.LiteralAstNode;
import org.apache.pinot.pql.parsers.pql2.ast.PredicateAstNode;
import org.apache.pinot.pql.parsers.pql2.ast.StringLiteralAstNode;
+import org.apache.pinot.spi.utils.BytesUtils;
import org.apache.pinot.sql.parsers.SqlCompilationException;
@@ -131,6 +132,12 @@ public class RequestUtils {
return expression;
}
+ public static Expression getLiteralExpression(byte[] value) {
+ Expression expression = createNewLiteralExpression();
+ expression.getLiteral().setStringValue(BytesUtils.toHexString(value));
+ return expression;
+ }
+
public static Expression getLiteralExpression(Integer value) {
return getLiteralExpression(value.longValue());
}
@@ -170,6 +177,9 @@ public class RequestUtils {
if (object instanceof SqlLiteral) {
return RequestUtils.getLiteralExpression((SqlLiteral) object);
}
+ if (object instanceof byte[]) {
+ return RequestUtils.getLiteralExpression((byte[]) object);
+ }
throw new SqlCompilationException(
new IllegalArgumentException("Unsupported Literal value type - " + object.getClass()));
}
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/GeometryUtils.java b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/GeometryUtils.java
index 309d4dd..b382dcd 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/GeometryUtils.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/GeometryUtils.java
@@ -53,4 +53,20 @@ public class GeometryUtils {
public static boolean isGeography(Geometry geometry) {
return geometry.getSRID() == GEOGRAPHY_SRID;
}
+
+ /**
+ * Sets the geometry to geography.
+ * @param geometry the geometry to set
+ */
+ public static void setGeography(Geometry geometry) {
+ geometry.setSRID(GEOGRAPHY_SRID);
+ }
+
+ /**
+ * Sets to geometry.
+ * @param geometry the geometry to set
+ */
+ public static void setGeometry(Geometry geometry) {
+ geometry.setSRID(0);
+ }
}
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/ScalarFunctions.java b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/ScalarFunctions.java
index 59e4e40..523842b 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/ScalarFunctions.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/ScalarFunctions.java
@@ -22,6 +22,7 @@ import org.apache.pinot.core.geospatial.GeometryUtils;
import org.apache.pinot.core.geospatial.serde.GeometrySerializer;
import org.apache.pinot.spi.annotations.ScalarFunction;
import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Point;
import org.locationtech.jts.io.WKTWriter;
@@ -44,6 +45,23 @@ public class ScalarFunctions {
}
/**
+ * Creates a point.
+ *
+ * @param x x
+ * @param y y
+ * @param isGeography if it's geography
+ * @return the created point
+ */
+ @ScalarFunction
+ public static byte[] stPoint(double x, double y, int isGeography) {
+ Point point = GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate(x, y));
+ if (isGeography > 0) {
+ GeometryUtils.setGeography(point);
+ }
+ return GeometrySerializer.serialize(point);
+ }
+
+ /**
* Saves the geometry object as WKT format.
*
* @param bytes the serialized geometry object
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StContainsFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StContainsFunction.java
index ef4f3d5..c693e65 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StContainsFunction.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StContainsFunction.java
@@ -25,6 +25,7 @@ import org.apache.pinot.core.geospatial.serde.GeometrySerializer;
import org.apache.pinot.core.operator.blocks.ProjectionBlock;
import org.apache.pinot.core.operator.transform.TransformResultMetadata;
import org.apache.pinot.core.operator.transform.function.BaseTransformFunction;
+import org.apache.pinot.core.operator.transform.function.LiteralTransformFunction;
import org.apache.pinot.core.operator.transform.function.TransformFunction;
import org.apache.pinot.core.plan.DocIdSetPlanNode;
import org.apache.pinot.spi.data.FieldSpec;
@@ -57,14 +58,14 @@ public class StContainsFunction extends BaseTransformFunction {
TransformFunction transformFunction = arguments.get(0);
Preconditions.checkArgument(transformFunction.getResultMetadata().isSingleValue(),
"First argument must be single-valued for transform function: %s", getName());
- Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES,
- "The first argument must be of bytes type");
+ Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES
+ || transformFunction instanceof LiteralTransformFunction, "The first argument must be of bytes type");
_firstArgument = transformFunction;
transformFunction = arguments.get(1);
Preconditions.checkArgument(transformFunction.getResultMetadata().isSingleValue(),
"Second argument must be single-valued for transform function: %s", getName());
- Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES,
- "The second argument must be of bytes type");
+ Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES
+ || transformFunction instanceof LiteralTransformFunction, "The second argument must be of bytes type");
_secondArgument = transformFunction;
}
@@ -84,8 +85,7 @@ public class StContainsFunction extends BaseTransformFunction {
Geometry firstGeometry = GeometrySerializer.deserialize(firstValues[i]);
Geometry secondGeometry = GeometrySerializer.deserialize(secondValues[i]);
if (GeometryUtils.isGeography(firstGeometry) || GeometryUtils.isGeography(secondGeometry)) {
- throw new RuntimeException(
- String.format("%s is available for Geometry objects only", FUNCTION_NAME));
+ throw new RuntimeException(String.format("%s is available for Geometry objects only", FUNCTION_NAME));
}
_results[i] = firstGeometry.contains(secondGeometry) ? 1 : 0;
}
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StDistanceFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StDistanceFunction.java
index 0b9066f..d79fa6c 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StDistanceFunction.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StDistanceFunction.java
@@ -26,6 +26,7 @@ import org.apache.pinot.core.geospatial.serde.GeometrySerializer;
import org.apache.pinot.core.operator.blocks.ProjectionBlock;
import org.apache.pinot.core.operator.transform.TransformResultMetadata;
import org.apache.pinot.core.operator.transform.function.BaseTransformFunction;
+import org.apache.pinot.core.operator.transform.function.LiteralTransformFunction;
import org.apache.pinot.core.operator.transform.function.TransformFunction;
import org.apache.pinot.core.plan.DocIdSetPlanNode;
import org.apache.pinot.spi.data.FieldSpec;
@@ -71,14 +72,14 @@ public class StDistanceFunction extends BaseTransformFunction {
TransformFunction transformFunction = arguments.get(0);
Preconditions.checkArgument(transformFunction.getResultMetadata().isSingleValue(),
"First argument must be single-valued for transform function: %s", getName());
- Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES,
- "The first argument must be of bytes type");
+ Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES
+ || transformFunction instanceof LiteralTransformFunction, "The first argument must be of bytes type");
_firstArgument = transformFunction;
transformFunction = arguments.get(1);
Preconditions.checkArgument(transformFunction.getResultMetadata().isSingleValue(),
"Second argument must be single-valued for transform function: %s", getName());
- Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES,
- "The second argument must be of bytes type");
+ Preconditions.checkArgument(transformFunction.getResultMetadata().getDataType() == FieldSpec.DataType.BYTES
+ || transformFunction instanceof LiteralTransformFunction, "The second argument must be of bytes type");
_secondArgument = transformFunction;
}
@@ -126,7 +127,7 @@ public class StDistanceFunction extends BaseTransformFunction {
Point leftPoint = (Point) leftGeometry;
Point rightPoint = (Point) rightGeometry;
- return greatCircleDistance(leftPoint.getY(), leftPoint.getX(), rightPoint.getY(), rightPoint.getX());
+ return greatCircleDistance(leftPoint.getX(), leftPoint.getY(), rightPoint.getX(), rightPoint.getY());
}
/**
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StPointFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StPointFunction.java
index 9fe93dc..2c09102 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StPointFunction.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/geospatial/transform/function/StPointFunction.java
@@ -20,15 +20,12 @@ package org.apache.pinot.core.geospatial.transform.function;
import com.google.common.base.Preconditions;
import org.apache.pinot.core.common.DataSource;
-import org.apache.pinot.core.geospatial.GeometryUtils;
-import org.apache.pinot.core.geospatial.serde.GeometrySerializer;
import org.apache.pinot.core.operator.blocks.ProjectionBlock;
import org.apache.pinot.core.operator.transform.TransformResultMetadata;
import org.apache.pinot.core.operator.transform.function.BaseTransformFunction;
+import org.apache.pinot.core.operator.transform.function.LiteralTransformFunction;
import org.apache.pinot.core.operator.transform.function.TransformFunction;
import org.apache.pinot.core.plan.DocIdSetPlanNode;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,6 +43,7 @@ public class StPointFunction extends BaseTransformFunction {
private TransformFunction _firstArgument;
private TransformFunction _secondArgument;
private byte[][] _results;
+ private int _isGeography = 0;
@Override
public String getName() {
@@ -54,8 +52,8 @@ public class StPointFunction extends BaseTransformFunction {
@Override
public void init(List<TransformFunction> arguments, Map<String, DataSource> dataSourceMap) {
- Preconditions
- .checkArgument(arguments.size() == 2, "2 arguments are required for transform function: %s", getName());
+ Preconditions.checkArgument(arguments.size() == 2 || arguments.size() == 3,
+ "2 or 3 arguments are required for transform function: %s", getName());
TransformFunction transformFunction = arguments.get(0);
Preconditions.checkArgument(transformFunction.getResultMetadata().isSingleValue(),
"First argument must be single-valued for transform function: %s", getName());
@@ -64,6 +62,12 @@ public class StPointFunction extends BaseTransformFunction {
Preconditions.checkArgument(transformFunction.getResultMetadata().isSingleValue(),
"Second argument must be single-valued for transform function: %s", getName());
_secondArgument = transformFunction;
+ if (arguments.size() == 3) {
+ transformFunction = arguments.get(2);
+ Preconditions.checkArgument(transformFunction instanceof LiteralTransformFunction,
+ "Third argument must be a literal of integer: %s", getName());
+ _isGeography = Integer.parseInt(((LiteralTransformFunction) transformFunction).getLiteral());
+ }
}
@Override
@@ -79,7 +83,7 @@ public class StPointFunction extends BaseTransformFunction {
double[] firstValues = _firstArgument.transformToDoubleValuesSV(projectionBlock);
double[] secondValues = _secondArgument.transformToDoubleValuesSV(projectionBlock);
for (int i = 0; i < projectionBlock.getNumDocs(); i++) {
- _results[i] = ScalarFunctions.stPoint(firstValues[i], secondValues[i]);
+ _results[i] = ScalarFunctions.stPoint(firstValues[i], secondValues[i], _isGeography);
}
return _results;
}
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/LiteralTransformFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/LiteralTransformFunction.java
index e8f93a7..1b02887 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/LiteralTransformFunction.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/LiteralTransformFunction.java
@@ -29,6 +29,7 @@ import org.apache.pinot.core.operator.transform.TransformResultMetadata;
import org.apache.pinot.core.plan.DocIdSetPlanNode;
import org.apache.pinot.core.segment.index.readers.Dictionary;
import org.apache.pinot.spi.data.FieldSpec;
+import org.apache.pinot.spi.utils.BytesUtils;
/**
@@ -42,6 +43,7 @@ public class LiteralTransformFunction implements TransformFunction {
private float[] _floatResult;
private double[] _doubleResult;
private String[] _stringResult;
+ private byte[][] _bytesResult;
public LiteralTransformFunction(String literal) {
_literal = literal;
@@ -145,7 +147,11 @@ public class LiteralTransformFunction implements TransformFunction {
@Override
public byte[][] transformToBytesValuesSV(ProjectionBlock projectionBlock) {
- throw new UnsupportedOperationException();
+ if (_bytesResult == null) {
+ _bytesResult = new byte[DocIdSetPlanNode.MAX_DOC_PER_CALL][];
+ Arrays.fill(_bytesResult, BytesUtils.toBytes(_literal));
+ }
+ return _bytesResult;
}
@Override
diff --git a/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StDistanceFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StDistanceFunctionTest.java
index f21205d..bdaeaaf 100644
--- a/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StDistanceFunctionTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StDistanceFunctionTest.java
@@ -48,10 +48,10 @@ public class StDistanceFunctionTest extends GeoFunctionTest {
@Test
public void testGeogDistance()
throws Exception {
- assertDistance("POINT(-86.67 36.12)", "POINT(-118.40 33.94)", 2886448.9734367016, false);
- assertDistance("POINT(-118.40 33.94)", "POINT(-86.67 36.12)", 2886448.9734367016, false);
- assertDistance("POINT(-71.0589 42.3601)", "POINT(-71.2290 42.4430)", 16734.69743457383, false);
- assertDistance("POINT(-86.67 36.12)", "POINT(-86.67 36.12)", 0.0, false);
+ assertDistance("POINT(36.12 -86.67)", "POINT(33.94 -118.40)", 2886448.9734367016, false);
+ assertDistance("POINT(33.94 -118.40)", "POINT(36.12 -86.67)", 2886448.9734367016, false);
+ assertDistance("POINT(42.3601 -71.0589)", "POINT(42.4430 -71.2290)", 16734.69743457383, false);
+ assertDistance("POINT(36.12 -86.67)", "POINT(36.12 -86.67)", 0.0, false);
// (FIXME): the follow testings require null handling
// assertDistance("POINT EMPTY", "POINT (40 30)", null);
diff --git a/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StPointFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StPointFunctionTest.java
index 08c5225..e0fee8e 100644
--- a/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StPointFunctionTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/core/geospatial/transform/StPointFunctionTest.java
@@ -36,15 +36,36 @@ import org.testng.annotations.Test;
public class StPointFunctionTest extends BaseTransformFunctionTest {
@Test
- public void testStPointFunction() {
- ExpressionContext expression =
- QueryContextConverterUtils.getExpression(String.format("ST_Point(%s,%s)", DOUBLE_SV_COLUMN, DOUBLE_SV_COLUMN));
+ public void testStPointGeogFunction() {
+ testStPointFunction(0);
+ testStPointFunction(1);
+ }
+
+ @Test
+ public void testStPointLiteralFunction() {
+ ExpressionContext expression = QueryContextConverterUtils.getExpression(String.format("ST_Point(20,10, 1)"));
+ TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap);
+ byte[][] expectedValues = new byte[NUM_ROWS][];
+ for (int i = 0; i < NUM_ROWS; i++) {
+ Point point = GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate(20, 10));
+ GeometryUtils.setGeography(point);
+ expectedValues[i] = GeometrySerializer.serialize(point);
+ }
+ testTransformFunction(transformFunction, expectedValues);
+ }
+
+ private void testStPointFunction(int isGeography) {
+ ExpressionContext expression = QueryContextConverterUtils
+ .getExpression(String.format("ST_Point(%s,%s, %d)", DOUBLE_SV_COLUMN, DOUBLE_SV_COLUMN, isGeography));
TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap);
Assert.assertTrue(transformFunction instanceof StPointFunction);
Assert.assertEquals(transformFunction.getName(), StPointFunction.FUNCTION_NAME);
byte[][] expectedValues = new byte[NUM_ROWS][];
for (int i = 0; i < NUM_ROWS; i++) {
Point point = GeometryUtils.GEOMETRY_FACTORY.createPoint(new Coordinate(_doubleSVValues[i], _doubleSVValues[i]));
+ if (isGeography > 0) {
+ GeometryUtils.setGeography(point);
+ }
expectedValues[i] = GeometrySerializer.serialize(point);
}
testTransformFunction(transformFunction, expectedValues);
diff --git a/pinot-tools/src/main/resources/examples/stream/meetupRsvp/meetupRsvp_realtime_table_config.json b/pinot-tools/src/main/resources/examples/stream/meetupRsvp/meetupRsvp_realtime_table_config.json
index bc9e972..0014b3a 100644
--- a/pinot-tools/src/main/resources/examples/stream/meetupRsvp/meetupRsvp_realtime_table_config.json
+++ b/pinot-tools/src/main/resources/examples/stream/meetupRsvp/meetupRsvp_realtime_table_config.json
@@ -7,7 +7,9 @@
"segmentPushType": "APPEND",
"segmentAssignmentStrategy": "BalanceNumSegmentAssignmentStrategy",
"schemaName": "meetupRsvp",
- "replication": "1"
+ "replication": "1",
+ "retentionTimeUnit": "DAYS",
+ "retentionTimeValue": "1"
},
"tenants": {},
"tableIndexConfig": {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org