org.elasticsearch.search.runtime.GeoPointScriptFieldGeoShapeQuery Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.search.runtime;
import org.apache.lucene.geo.Component2D;
import org.apache.lucene.geo.GeoEncodingUtils;
import org.apache.lucene.geo.LatLonGeometry;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.script.GeoPointFieldScript;
import org.elasticsearch.script.Script;
import java.util.Arrays;
import java.util.Objects;
public class GeoPointScriptFieldGeoShapeQuery extends AbstractGeoPointScriptFieldQuery {
private final SpatialPredicate predicate;
private final LatLonGeometry[] geometries;
private final ShapeRelation relation;
public GeoPointScriptFieldGeoShapeQuery(
Script script,
GeoPointFieldScript.LeafFactory leafFactory,
String fieldName,
ShapeRelation relation,
LatLonGeometry... geometries
) {
super(script, leafFactory, fieldName);
this.geometries = geometries;
this.relation = relation;
this.predicate = getPredicate(relation, geometries);
}
@Override
protected boolean matches(double[] lats, double[] lons, int count) {
return predicate.matches(lats, lons, count);
}
@Override
public final String toString(String field) {
if (fieldName().contentEquals(field)) {
return getClass().getSimpleName();
}
return fieldName() + ":" + getClass().getSimpleName();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (super.equals(o) == false) return false;
GeoPointScriptFieldGeoShapeQuery that = (GeoPointScriptFieldGeoShapeQuery) o;
return relation == that.relation && Arrays.equals(geometries, that.geometries);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), relation, Arrays.hashCode(geometries));
}
@FunctionalInterface
private interface SpatialPredicate {
boolean matches(double[] lats, double[] lons, int count);
}
private static SpatialPredicate getPredicate(ShapeRelation relation, LatLonGeometry... geometries) {
switch (relation) {
case INTERSECTS -> {
final GeoEncodingUtils.Component2DPredicate predicate = GeoEncodingUtils.createComponentPredicate(
LatLonGeometry.create(geometries)
);
return (lats, lons, count) -> {
for (int i = 0; i < count; i++) {
final int lat = GeoEncodingUtils.encodeLatitude(lats[i]);
final int lon = GeoEncodingUtils.encodeLongitude(lons[i]);
if (predicate.test(lat, lon)) {
return true;
}
}
return false;
};
}
case DISJOINT -> {
final GeoEncodingUtils.Component2DPredicate predicate = GeoEncodingUtils.createComponentPredicate(
LatLonGeometry.create(geometries)
);
return (lats, lons, count) -> {
for (int i = 0; i < count; i++) {
final int lat = GeoEncodingUtils.encodeLatitude(lats[i]);
final int lon = GeoEncodingUtils.encodeLongitude(lons[i]);
if (predicate.test(lat, lon)) {
return false;
}
}
// return true iff there is at least one point
return count > 0;
};
}
case WITHIN -> {
final GeoEncodingUtils.Component2DPredicate predicate = GeoEncodingUtils.createComponentPredicate(
LatLonGeometry.create(geometries)
);
return (lats, lons, count) -> {
for (int i = 0; i < count; i++) {
final int lat = GeoEncodingUtils.encodeLatitude(lats[i]);
final int lon = GeoEncodingUtils.encodeLongitude(lons[i]);
if (predicate.test(lat, lon) == false) {
return false;
}
}
// return true iff there is at least one point
return count > 0;
};
}
case CONTAINS -> {
final Component2D[] component2DS = new Component2D[geometries.length];
for (int i = 0; i < geometries.length; i++) {
component2DS[i] = LatLonGeometry.create(geometries[i]);
}
return (lats, lons, count) -> {
Component2D.WithinRelation answer = Component2D.WithinRelation.DISJOINT;
for (int i = 0; i < count; i++) {
final int lat = GeoEncodingUtils.encodeLatitude(lats[i]);
final int lon = GeoEncodingUtils.encodeLongitude(lons[i]);
for (Component2D component2D : component2DS) {
Component2D.WithinRelation withinRelation = component2D.withinPoint(lon, lat);
if (withinRelation == Component2D.WithinRelation.NOTWITHIN) {
return false;
} else if (withinRelation != Component2D.WithinRelation.DISJOINT) {
answer = withinRelation;
}
}
}
return answer == Component2D.WithinRelation.CANDIDATE;
};
}
default -> throw new IllegalArgumentException("Unknown spatial relationship [" + relation.getRelationName() + "]");
}
}
}