Skip to content
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

GEOMESA-3409: Arrow: axis order request parameter #3224

Merged
7 changes: 7 additions & 0 deletions docs/user/datastores/analytic_queries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ following query hints:
+-------------------------------------+--------------------+------------------------------------+
| QueryHints.ARROW_FLATTEN_STRUCT | Boolean (optional) | flattenStruct |
+-------------------------------------+--------------------+------------------------------------+
| QueryHints.FLIP_AXIS_ORDER | Boolean (optional) | axisOrder:LatLon / axisOrder:LonLat|
+-------------------------------------+--------------------+------------------------------------+

Explanation of Hints
++++++++++++++++++++
Expand Down Expand Up @@ -336,6 +338,11 @@ ARROW_FLATTEN_STRUCT
This hint will remove the outer struct named after the feature type and will instead return the attribute fields directly
in the RecordBatch. Note that this hint is currently only supported for PostGIS and geoserver native stores.

FLIP_AXIS_ORDER
^^^^^^^^^^^^^^^

This hint allows the coordinate axis order to be specified as either Lat/Lon or Lon/Lat explicitly to be set for every geometry related field.
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved

Example Query
+++++++++++++

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ object ArrowAttributeWriter {
case ObjectType.LONG => new ArrowLongWriter(name, metadata, factory)
case ObjectType.FLOAT => new ArrowFloatWriter(name, metadata, factory)
case ObjectType.DOUBLE => new ArrowDoubleWriter(name, metadata, factory)
case ObjectType.GEOMETRY => geometry(name, bindings(1), encoding.geometry, metadata, factory)
case ObjectType.GEOMETRY => geometry(name, bindings(1), encoding, metadata, factory)
case ObjectType.BOOLEAN => new ArrowBooleanWriter(name, metadata, factory)
case ObjectType.LIST => new ArrowListWriter(name, bindings(1), encoding, metadata, factory)
case ObjectType.MAP => new ArrowMapWriter(name, bindings(1), bindings(2), encoding, metadata, factory)
Expand Down Expand Up @@ -234,11 +234,11 @@ object ArrowAttributeWriter {
private def geometry(
name: String,
binding: ObjectType,
encoding: Encoding,
encoding: SimpleFeatureEncoding,
metadata: Map[String, String],
factory: VectorFactory): ArrowGeometryWriter = {
val m = metadata.asJava
val vector = (binding, encoding, factory) match {
val vector = (binding, encoding.geometry, factory) match {
case (ObjectType.POINT, Encoding.Min, FromStruct(c)) => new PointFloatVector(name, c, m)
case (ObjectType.POINT, Encoding.Min, FromAllocator(c)) => new PointFloatVector(name, c, m)
case (ObjectType.POINT, Encoding.Max, FromStruct(c)) => new PointVector(name, c, m)
Expand Down Expand Up @@ -269,7 +269,10 @@ object ArrowAttributeWriter {
case (_, _, FromList(_)) => throw new NotImplementedError("Geometry lists are not supported")
case _ => throw new IllegalArgumentException(s"Unexpected geometry type $binding")
}
new ArrowGeometryWriter(name, vector.asInstanceOf[GeometryVector[Geometry, FieldVector]])
val geometryVector = vector.asInstanceOf[GeometryVector[Geometry, FieldVector]]
geometryVector.setFlipAxisOrder(encoding.flipAxisOrder)

new ArrowGeometryWriter(name, geometryVector)
}

trait ArrowDictionaryWriter extends ArrowAttributeWriter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,16 @@ object SimpleFeatureVector {
val DescriptorKey = "descriptor"
val OptionsKey = "options"

case class SimpleFeatureEncoding(fids: Option[Encoding], geometry: Encoding, date: Encoding)
case class SimpleFeatureEncoding(fids: Option[Encoding], geometry: Encoding, date: Encoding, flipAxisOrder: Boolean)

object SimpleFeatureEncoding {

val Min: SimpleFeatureEncoding = SimpleFeatureEncoding(Some(Encoding.Min), Encoding.Min, Encoding.Min)
val Max: SimpleFeatureEncoding = SimpleFeatureEncoding(Some(Encoding.Max), Encoding.Max, Encoding.Max)
val Min: SimpleFeatureEncoding = SimpleFeatureEncoding(Some(Encoding.Min), Encoding.Min, Encoding.Min, flipAxisOrder = false)
val Max: SimpleFeatureEncoding = SimpleFeatureEncoding(Some(Encoding.Max), Encoding.Max, Encoding.Max, flipAxisOrder = true)
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved

def min(includeFids: Boolean, proxyFids: Boolean = false): SimpleFeatureEncoding = {
def min(includeFids: Boolean, proxyFids: Boolean = false, flipAxisOrder: Boolean = false): SimpleFeatureEncoding = {
val fids = if (includeFids) { Some(if (proxyFids) { Encoding.Min } else { Encoding.Max }) } else { None }
SimpleFeatureEncoding(fids, Encoding.Min, Encoding.Min)
SimpleFeatureEncoding(fids, Encoding.Min, Encoding.Min, flipAxisOrder)
}

object Encoding extends Enumeration {
Expand Down Expand Up @@ -245,7 +245,7 @@ object SimpleFeatureVector {
val isLong = dateVector.exists(_.isInstanceOf[BigIntVector])
if (isLong) { Encoding.Max } else { Encoding.Min }
}
val encoding = SimpleFeatureEncoding(fidEncoding, geomPrecision, datePrecision)
val encoding = SimpleFeatureEncoding(fidEncoding, geomPrecision, datePrecision, flipAxisOrder = false)
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved

(sft, encoding)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ public interface GeometryVector<T extends Geometry, V extends FieldVector> exten
int getNullCount();

void transfer(int fromIndex, int toIndex, GeometryVector<T, V> to);

Boolean getFlipAxisOrder();
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved
void setFlipAxisOrder(Boolean flip);
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@

import javax.annotation.Nullable;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* Catch-all for storing instances of Geometry as WKB
*/
public class WKBGeometryVector implements GeometryVector<Geometry, VarBinaryVector> {
private VarBinaryVector vector;
private final VarBinaryVector vector;
private WKBWriter writer = null;
private WKBReader reader = null;
protected final AtomicBoolean flipAxisOrder = new AtomicBoolean();
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved

public static final Field field = Field.nullablePrimitive("wkb", ArrowType.Binary.INSTANCE);

Expand Down Expand Up @@ -104,6 +106,16 @@ public void transfer(int fromIndex, int toIndex, GeometryVector<Geometry, VarBin
to.set(toIndex, get(fromIndex));
}

@Override
public Boolean getFlipAxisOrder() {
return flipAxisOrder.get();
}

@Override
public void setFlipAxisOrder(Boolean flip) {
flipAxisOrder.set(flip);
}

@Override
public void close() throws Exception {
vector.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
import org.locationtech.jts.geom.Geometry;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public abstract class AbstractGeometryVector<T extends Geometry, U extends FieldVector, V extends FieldVector>
implements GeometryVector<T, U> {

private V ordinal;
protected U vector;
protected final AtomicBoolean flipAxisOrder = new AtomicBoolean();
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved

protected AbstractGeometryVector(U vector) {
this.vector = vector;
Expand Down Expand Up @@ -51,11 +53,35 @@ public int getNullCount() {
return Math.max(count, 0);
}

@Override
public Boolean getFlipAxisOrder() {
return flipAxisOrder.get();
}

@Override
public void setFlipAxisOrder(Boolean flip) {
flipAxisOrder.set(flip);
}

@Override
public void close() throws Exception {
vector.close();
}

/**
* Calculate the Y index
*/
protected int y(int index) {
return index * 2;
}

/**
* Calculate the X index
*/
protected int x(int index) {
return index * 2 + 1;
}

protected void setOrdinalVector(V ordinal) {
this.ordinal = ordinal;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@ public void set(int index, LineString geom) {
for (int i = 0; i < geom.getNumPoints(); i++) {
final Coordinate p = geom.getCoordinateN(i);
tuples.setNotNull(position + i);
writeOrdinal((position + i) * 2, p.y);
writeOrdinal((position + i) * 2 + 1, p.x);
if (getFlipAxisOrder()) {
elahrvivaz marked this conversation as resolved.
Show resolved Hide resolved
writeOrdinal(y(position + i), p.x);
writeOrdinal(x(position + i), p.y);
} else {
writeOrdinal(y(position + i), p.y);
writeOrdinal(x(position + i), p.x);
}
}
vector.endValue(index, geom.getNumPoints());
}
Expand All @@ -81,8 +86,14 @@ public LineString get(int index) {
final int offsetEnd = vector.getOffsetBuffer().getInt((index + 1) * ListVector.OFFSET_WIDTH);
final Coordinate[] coordinates = new Coordinate[offsetEnd - offsetStart];
for (int i = 0; i < coordinates.length; i++) {
final double y = readOrdinal((offsetStart + i) * 2);
final double x = readOrdinal((offsetStart + i) * 2 + 1);
final double y, x;
if (getFlipAxisOrder()) {
y = readOrdinal(x(offsetStart + i));
epyatkevich marked this conversation as resolved.
Show resolved Hide resolved
x = readOrdinal(y(offsetStart + i));
} else {
y = readOrdinal(y(offsetStart + i));
x = readOrdinal(x(offsetStart + i));
}
coordinates[i] = new Coordinate(x, y);
}
return factory.createLineString(coordinates);
Expand All @@ -98,10 +109,10 @@ public int getEndOffset(int index) {
}

public double getCoordinateY(int offset) {
return readOrdinal(offset * 2);
return readOrdinal(y(offset));
}

public double getCoordinateX(int offset) {
return readOrdinal(offset * 2 + 1);
return readOrdinal(x(offset));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,13 @@ public void set(int index, MultiLineString geom) {
for (int j = 0; j < line.getNumPoints(); j++) {
final Coordinate p = line.getCoordinateN(j);
tuples.setNotNull(position + j);
writeOrdinal((position + j) * 2, p.y);
writeOrdinal((position + j) * 2 + 1, p.x);
if (getFlipAxisOrder()) {
writeOrdinal(y(position + j), p.x);
writeOrdinal(x(position + j), p.y);
} else {
writeOrdinal(y(position + j), p.y);
writeOrdinal(x(position + j), p.x);
}
}
innerVector.endValue(innerIndex + i, line.getNumPoints());
}
Expand All @@ -94,8 +99,14 @@ public MultiLineString get(int index) {
final int offsetEnd = innerVector.getOffsetBuffer().getInt((outerOffsetStart + j + 1) * ListVector.OFFSET_WIDTH);
final Coordinate[] coordinates = new Coordinate[offsetEnd - offsetStart];
for (int i = 0; i < coordinates.length; i++) {
final double y = readOrdinal((offsetStart + i) * 2);
final double x = readOrdinal((offsetStart + i) * 2 + 1);
final double y, x;
if (getFlipAxisOrder()) {
y = readOrdinal(x(offsetStart + i));
x = readOrdinal(y(offsetStart + i));
} else {
y = readOrdinal(y(offsetStart + i));
x = readOrdinal(x(offsetStart + i));
}
coordinates[i] = new Coordinate(x, y);
}
lines[j] = factory.createLineString(coordinates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,13 @@ public void set(int index, MultiPoint geom) {
for (int i = 0; i < geom.getNumPoints(); i++) {
final Point p = (Point) geom.getGeometryN(i);
tuples.setNotNull(position + i);
writeOrdinal((position + i) * 2, p.getY());
writeOrdinal((position + i) * 2 + 1, p.getX());
if (getFlipAxisOrder()) {
writeOrdinal(y(position + i), p.getX());
writeOrdinal(x(position + i), p.getY());
} else {
writeOrdinal(y(position + i), p.getY());
writeOrdinal(x(position + i), p.getX());
}
}
vector.endValue(index, geom.getNumPoints());
}
Expand All @@ -82,8 +87,14 @@ public MultiPoint get(int index) {
final int offsetEnd = vector.getOffsetBuffer().getInt((index + 1) * ListVector.OFFSET_WIDTH);
final Coordinate[] coordinates = new Coordinate[offsetEnd - offsetStart];
for (int i = 0; i < coordinates.length; i++) {
final double y = readOrdinal((offsetStart + i) * 2);
final double x = readOrdinal((offsetStart + i) * 2 + 1);
final double y, x;
if (getFlipAxisOrder()) {
y = readOrdinal(x(offsetStart + i));
x = readOrdinal(y(offsetStart + i));
} else {
y = readOrdinal(y(offsetStart + i));
x = readOrdinal(x(offsetStart + i));
}
coordinates[i] = new Coordinate(x, y);
}
return factory.createMultiPointFromCoords(coordinates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,13 @@ public void set(int index, MultiPolygon geom) {
for (int k = 0; k < line.getNumPoints(); k++) {
Coordinate p = line.getCoordinateN(k);
tuples.setNotNull(position + k);
writeOrdinal((position + k) * 2, p.y);
writeOrdinal((position + k) * 2 + 1, p.x);
if (getFlipAxisOrder()) {
writeOrdinal(y(position + k), p.x);
writeOrdinal(x(position + k), p.y);
} else {
writeOrdinal(y(position + k), p.y);
writeOrdinal(x(position + k), p.x);
}
}
innerInnerVector.endValue(innerInnerIndex + j, line.getNumPoints());
}
Expand Down Expand Up @@ -109,8 +114,14 @@ public MultiPolygon get(int index) {
final int offsetEnd = innerInnerVector.getOffsetBuffer().getInt((outerOffsetStart + j + 1) * ListVector.OFFSET_WIDTH);
final Coordinate[] coordinates = new Coordinate[offsetEnd - offsetStart];
for (int i = 0; i < coordinates.length; i++) {
final double y = readOrdinal((offsetStart + i) * 2);
final double x = readOrdinal((offsetStart + i) * 2 + 1);
final double y, x;
if (getFlipAxisOrder()) {
y = readOrdinal(x(offsetStart + i));
x = readOrdinal(y(offsetStart + i));
} else {
y = readOrdinal(y(offsetStart + i));
x = readOrdinal(x(offsetStart + i));
}
coordinates[i] = new Coordinate(x, y);
}
final LinearRing ring = factory.createLinearRing(coordinates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,13 @@ public void set(int index, Point geom) {
vector.setNull(index);
} else {
vector.setNotNull(index);
writeOrdinal(index * 2, geom.getY());
writeOrdinal(index * 2 + 1, geom.getX());
if (getFlipAxisOrder()) {
writeOrdinal(y(index), geom.getX());
writeOrdinal(x(index), geom.getY());
} else {
writeOrdinal(y(index), geom.getY());
writeOrdinal(x(index), geom.getX());
}
}
}

Expand All @@ -63,8 +68,14 @@ public Point get(int index) {
if (vector.isNull(index)) {
return null;
} else {
final double y = readOrdinal(index * 2);
final double x = readOrdinal(index * 2 + 1);
final double y, x;
if (getFlipAxisOrder()) {
y = x(index);
x = y(index);
} else {
y = y(index);
x = x(index);
}
return factory.createPoint(new Coordinate(x, y));
}
}
Expand All @@ -76,8 +87,13 @@ public void transfer(int fromIndex, int toIndex, GeometryVector<Point, FixedSize
((FixedSizeListVector) typed.vector).setNull(toIndex);
} else {
((FixedSizeListVector) typed.vector).setNotNull(toIndex);
typed.writeOrdinal(toIndex * 2, readOrdinal(fromIndex * 2));
typed.writeOrdinal(toIndex * 2 + 1, readOrdinal(fromIndex * 2 + 1));
if (getFlipAxisOrder()) {
typed.writeOrdinal(y(toIndex), getCoordinateX(fromIndex));
typed.writeOrdinal(x(toIndex), getCoordinateY(fromIndex));
} else {
typed.writeOrdinal(y(toIndex), getCoordinateY(fromIndex));
typed.writeOrdinal(x(toIndex), getCoordinateX(fromIndex));
}
}
}

Expand All @@ -88,7 +104,7 @@ public void transfer(int fromIndex, int toIndex, GeometryVector<Point, FixedSize
* @return y ordinate
*/
public double getCoordinateY(int index) {
return readOrdinal(index * 2);
return readOrdinal(y(index));

}

Expand All @@ -99,6 +115,6 @@ public double getCoordinateY(int index) {
* @return x ordinate
*/
public double getCoordinateX(int index) {
return readOrdinal(index * 2 + 1);
return readOrdinal(x(index));
}
}
Loading
Loading