org.opensearch.common.geo.GeoShapeDocValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of opensearch Show documentation
Show all versions of opensearch Show documentation
OpenSearch subproject :server
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
package org.opensearch.common.geo;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.LatLonShape;
import org.apache.lucene.document.LatLonShapeDocValues;
import org.apache.lucene.document.LatLonShapeDocValuesField;
import org.apache.lucene.geo.LatLonGeometry;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.util.BytesRef;
import org.opensearch.geometry.Geometry;
import org.opensearch.geometry.GeometryVisitor;
import org.opensearch.geometry.Rectangle;
import org.opensearch.index.mapper.GeoShapeIndexer;
import java.io.IOException;
import java.util.List;
/**
* This class is an OpenSearch Internal representation of lucene {@link LatLonShapeDocValuesField} for GeoShape.
*
* @opensearch.internal
*/
public class GeoShapeDocValue extends ShapeDocValue {
private static final String FIELD_NAME = "missingField";
private final LatLonShapeDocValues shapeDocValues;
public GeoShapeDocValue(final String fieldName, final BytesRef bytesRef) {
this(LatLonShape.createDocValueField(fieldName, bytesRef));
}
public GeoShapeDocValue(final LatLonShapeDocValuesField shapeDocValuesField) {
centroid = new Centroid(shapeDocValuesField.getCentroid().getLat(), shapeDocValuesField.getCentroid().getLon());
highestDimensionType = ShapeType.fromShapeFieldType(shapeDocValuesField.getHighestDimensionType());
boundingRectangle = new BoundingRectangle(
shapeDocValuesField.getBoundingBox().maxLon,
shapeDocValuesField.getBoundingBox().maxLat,
shapeDocValuesField.getBoundingBox().minLon,
shapeDocValuesField.getBoundingBox().minLat
);
this.shapeDocValues = LatLonShape.createLatLonShapeDocValues(shapeDocValuesField.binaryValue());
}
/**
* This function takes a {@link Geometry} and creates the {@link GeoShapeDocValue}. The function uses the
* {@link GeoShapeIndexer} to first convert the {@link Geometry} to {@link IndexableField}s and then convert it
* to the DocValue. This is very expensive function and should not be used on the Geometry Objects which are
* already converted to {@link IndexableField}s as it does the Tessellation internally which is already done on the
* {@link IndexableField}s.
*
* @param geometry {@link Geometry}
* @return {@link GeoShapeDocValue}
*/
public static GeoShapeDocValue createGeometryDocValue(final Geometry geometry) {
// Setting the orientation to CCW, which will make the holes to CW. This is the default value which we will
// be using. This is in conjunction with what we take as a default value for geoshape in WKT format.
final GeoShapeIndexer shapeIndex = new GeoShapeIndexer(true, FIELD_NAME);
final List indexableFields = shapeIndex.indexShape(null, shapeIndex.prepareForIndexing(geometry));
Field[] fieldsArray = new Field[indexableFields.size()];
fieldsArray = indexableFields.toArray(fieldsArray);
final LatLonShapeDocValuesField latLonShapeDocValuesField = LatLonShape.createDocValueField(FIELD_NAME, fieldsArray);
return new GeoShapeDocValue(latLonShapeDocValuesField);
}
public Centroid getCentroid() {
return (Centroid) centroid;
}
public BoundingRectangle getBoundingRectangle() {
return (BoundingRectangle) boundingRectangle;
}
@Override
public String toString() {
return "BoundingRectangle(" + boundingRectangle + "), Centroid(" + centroid + "), HighestDimension(" + highestDimensionType + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeoShapeDocValue object = (GeoShapeDocValue) o;
boolean isEqual = true;
if (boundingRectangle != null) {
isEqual = boundingRectangle.equals(object.getBoundingRectangle());
}
if (centroid != null) {
isEqual = isEqual && centroid.equals(object.getCentroid());
}
if (highestDimensionType != null) {
isEqual = isEqual && highestDimensionType == object.getHighestDimensionType();
}
return isEqual;
}
@Override
public int hashCode() {
int result;
long temp;
temp = boundingRectangle != null ? boundingRectangle.hashCode() : 0L;
result = Long.hashCode(temp);
temp = centroid != null ? centroid.hashCode() : 0L;
result = 31 * result + Long.hashCode(temp);
temp = highestDimensionType != null ? highestDimensionType.hashCode() : 0L;
result = 31 * result + Long.hashCode(temp);
return result;
}
/**
* An extension for {@link ShapeDocValue.Centroid} which make easy to read the values when centroid is on the
* EarthSurface
*/
public static final class Centroid extends ShapeDocValue.Centroid {
Centroid(final double lat, final double lon) {
super(lat, lon);
}
public double getLatitude() {
return getY();
}
public double getLongitude() {
return getX();
}
@Override
public String toString() {
return getY() + ", " + getX();
}
}
/**
* An extension for {@link ShapeDocValue.BoundingRectangle} which make easy to read the values when BB is on the
* EarthSurface
*/
public static final class BoundingRectangle extends ShapeDocValue.BoundingRectangle {
BoundingRectangle(final double maxLon, final double maxLat, final double minLon, final double minLat) {
super(maxLon, maxLat, minLon, minLat);
}
public double getMaxLongitude() {
return getMaxX();
}
public double getMaxLatitude() {
return getMaxY();
}
public double getMinLatitude() {
return getMinY();
}
public double getMinLongitude() {
return getMinX();
}
@Override
public String toString() {
return "maxLatitude: "
+ getMaxY()
+ ", minLatitude: "
+ getMinY()
+ ", maxLongitude: "
+ getMaxX()
+ ", minLongitude: "
+ getMinX();
}
}
/**
* Checks if the input {@link Rectangle} is intersecting with the shape represented as {@link GeoShapeDocValue}.
* We could have used the {@link GeometryVisitor} here and added the functionality to check the intersection with
* other {@link Geometry} also, but that will be an overkill for now, if required we can easily create a
* {@link GeometryVisitor} to check the intersection with this Shape represented as {@link GeoShapeDocValue}.
* @return boolean
*/
public boolean isIntersectingRectangle(final Rectangle rectangle) {
final org.apache.lucene.geo.Rectangle luceneRectangle = GeoShapeUtils.toLuceneRectangle(rectangle);
try {
final PointValues.Relation relation = shapeDocValues.relate(LatLonGeometry.create(luceneRectangle));
return relation != PointValues.Relation.CELL_OUTSIDE_QUERY;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}