Skip to content

Commit

Permalink
HSEARCH-3752 Support implicit nested geo predicates in ES
Browse files Browse the repository at this point in the history
  • Loading branch information
fax4ever committed Mar 18, 2020
1 parent 40f8fd3 commit 22fd361
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 24 deletions.
Expand Up @@ -151,23 +151,23 @@ public SpatialWithinCirclePredicateBuilder<ElasticsearchSearchPredicateBuilder>
String absoluteFieldPath) {
return scopeModel
.getSchemaNodeComponent( absoluteFieldPath, PREDICATE_BUILDER_FACTORY_RETRIEVAL_STRATEGY )
.getComponent().createSpatialWithinCirclePredicateBuilder( absoluteFieldPath );
.getComponent().createSpatialWithinCirclePredicateBuilder( absoluteFieldPath, scopeModel.getNestedPathHierarchy( absoluteFieldPath ) );
}

@Override
public SpatialWithinPolygonPredicateBuilder<ElasticsearchSearchPredicateBuilder> spatialWithinPolygon(
String absoluteFieldPath) {
return scopeModel
.getSchemaNodeComponent( absoluteFieldPath, PREDICATE_BUILDER_FACTORY_RETRIEVAL_STRATEGY )
.getComponent().createSpatialWithinPolygonPredicateBuilder( absoluteFieldPath );
.getComponent().createSpatialWithinPolygonPredicateBuilder( absoluteFieldPath, scopeModel.getNestedPathHierarchy( absoluteFieldPath ) );
}

@Override
public SpatialWithinBoundingBoxPredicateBuilder<ElasticsearchSearchPredicateBuilder> spatialWithinBoundingBox(
String absoluteFieldPath) {
return scopeModel
.getSchemaNodeComponent( absoluteFieldPath, PREDICATE_BUILDER_FACTORY_RETRIEVAL_STRATEGY )
.getComponent().createSpatialWithinBoundingBoxPredicateBuilder( absoluteFieldPath );
.getComponent().createSpatialWithinBoundingBoxPredicateBuilder( absoluteFieldPath, scopeModel.getNestedPathHierarchy( absoluteFieldPath ) );
}

@Override
Expand Down
Expand Up @@ -56,23 +56,23 @@ public ElasticsearchSimpleQueryStringPredicateBuilderFieldState createSimpleQuer

@Override
public SpatialWithinCirclePredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinCirclePredicateBuilder(
String absoluteFieldPath) {
String absoluteFieldPath, List<String> nestedPathHierarchy) {
throw log.spatialPredicatesNotSupportedByFieldType(
EventContexts.fromIndexFieldAbsolutePath( absoluteFieldPath )
);
}

@Override
public SpatialWithinPolygonPredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinPolygonPredicateBuilder(
String absoluteFieldPath) {
String absoluteFieldPath, List<String> nestedPathHierarchy) {
throw log.spatialPredicatesNotSupportedByFieldType(
EventContexts.fromIndexFieldAbsolutePath( absoluteFieldPath )
);
}

@Override
public SpatialWithinBoundingBoxPredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinBoundingBoxPredicateBuilder(
String absoluteFieldPath) {
String absoluteFieldPath, List<String> nestedPathHierarchy) {
throw log.spatialPredicatesNotSupportedByFieldType(
EventContexts.fromIndexFieldAbsolutePath( absoluteFieldPath )
);
Expand Down
Expand Up @@ -62,11 +62,11 @@ WildcardPredicateBuilder<ElasticsearchSearchPredicateBuilder> createWildcardPred
ElasticsearchSimpleQueryStringPredicateBuilderFieldState createSimpleQueryStringFieldContext(String absoluteFieldPath);

SpatialWithinCirclePredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinCirclePredicateBuilder(
String absoluteFieldPath);
String absoluteFieldPath, List<String> nestedPathHierarchy);

SpatialWithinPolygonPredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinPolygonPredicateBuilder(
String absoluteFieldPath);
String absoluteFieldPath, List<String> nestedPathHierarchy);

SpatialWithinBoundingBoxPredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinBoundingBoxPredicateBuilder(
String absoluteFieldPath);
String absoluteFieldPath, List<String> nestedPathHierarchy);
}
Expand Up @@ -70,23 +70,23 @@ public RangePredicateBuilder<ElasticsearchSearchPredicateBuilder> createRangePre

@Override
public SpatialWithinCirclePredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinCirclePredicateBuilder(
String absoluteFieldPath) {
String absoluteFieldPath, List<String> nestedPathHierarchy) {
checkSearchable( absoluteFieldPath );
return new ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder( absoluteFieldPath, CODEC );
return new ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder( absoluteFieldPath, nestedPathHierarchy, CODEC );
}

@Override
public SpatialWithinPolygonPredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinPolygonPredicateBuilder(
String absoluteFieldPath) {
String absoluteFieldPath, List<String> nestedPathHierarchy) {
checkSearchable( absoluteFieldPath );
return new ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder( absoluteFieldPath );
return new ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder( absoluteFieldPath, nestedPathHierarchy );
}

@Override
public SpatialWithinBoundingBoxPredicateBuilder<ElasticsearchSearchPredicateBuilder> createSpatialWithinBoundingBoxPredicateBuilder(
String absoluteFieldPath) {
String absoluteFieldPath, List<String> nestedPathHierarchy) {
checkSearchable( absoluteFieldPath );
return new ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder( absoluteFieldPath, CODEC );
return new ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder( absoluteFieldPath, nestedPathHierarchy, CODEC );
}

private void checkSearchable(String absoluteFieldPath) {
Expand Down
Expand Up @@ -6,9 +6,11 @@
*/
package org.hibernate.search.backend.elasticsearch.types.predicate.impl;

import java.util.List;

import org.hibernate.search.backend.elasticsearch.gson.impl.JsonAccessor;
import org.hibernate.search.backend.elasticsearch.gson.impl.JsonObjectAccessor;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchNestedPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateContext;
import org.hibernate.search.backend.elasticsearch.types.codec.impl.ElasticsearchFieldCodec;
Expand All @@ -19,7 +21,7 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

class ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder extends AbstractElasticsearchSearchPredicateBuilder
class ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder extends AbstractElasticsearchSearchNestedPredicateBuilder
implements SpatialWithinBoundingBoxPredicateBuilder<ElasticsearchSearchPredicateBuilder> {

private static final JsonObjectAccessor GEO_BOUNDING_BOX_ACCESSOR = JsonAccessor.root().property( "geo_bounding_box" ).asObject();
Expand All @@ -35,7 +37,8 @@ class ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder extends Abst
private JsonElement topLeft;
private JsonElement bottomRight;

ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder(String absoluteFieldPath, ElasticsearchFieldCodec<GeoPoint> codec) {
ElasticsearchGeoPointSpatialWithinBoundingBoxPredicateBuilder(String absoluteFieldPath, List<String> nestedPathHierarchy, ElasticsearchFieldCodec<GeoPoint> codec) {
super( nestedPathHierarchy );
this.absoluteFieldPath = absoluteFieldPath;
this.codec = codec;
}
Expand Down
Expand Up @@ -6,9 +6,11 @@
*/
package org.hibernate.search.backend.elasticsearch.types.predicate.impl;

import java.util.List;

import org.hibernate.search.backend.elasticsearch.gson.impl.JsonAccessor;
import org.hibernate.search.backend.elasticsearch.gson.impl.JsonObjectAccessor;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchNestedPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateContext;
import org.hibernate.search.backend.elasticsearch.types.codec.impl.ElasticsearchFieldCodec;
Expand All @@ -19,7 +21,7 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

class ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder extends AbstractElasticsearchSearchPredicateBuilder
class ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder extends AbstractElasticsearchSearchNestedPredicateBuilder
implements SpatialWithinCirclePredicateBuilder<ElasticsearchSearchPredicateBuilder> {

private static final JsonObjectAccessor GEO_DISTANCE_ACCESSOR = JsonAccessor.root().property( "geo_distance" ).asObject();
Expand All @@ -33,7 +35,9 @@ class ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder extends AbstractE
private double distanceInMeters;
private JsonElement center;

ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder(String absoluteFieldPath, ElasticsearchFieldCodec<GeoPoint> codec) {
ElasticsearchGeoPointSpatialWithinCirclePredicateBuilder(String absoluteFieldPath, List<String> nestedPathHierarchy,
ElasticsearchFieldCodec<GeoPoint> codec) {
super( nestedPathHierarchy );
this.absoluteFieldPath = absoluteFieldPath;
this.codec = codec;
}
Expand Down
Expand Up @@ -6,9 +6,11 @@
*/
package org.hibernate.search.backend.elasticsearch.types.predicate.impl;

import java.util.List;

import org.hibernate.search.backend.elasticsearch.gson.impl.JsonAccessor;
import org.hibernate.search.backend.elasticsearch.gson.impl.JsonObjectAccessor;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.AbstractElasticsearchSearchNestedPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateBuilder;
import org.hibernate.search.backend.elasticsearch.search.predicate.impl.ElasticsearchSearchPredicateContext;
import org.hibernate.search.engine.search.predicate.spi.SpatialWithinPolygonPredicateBuilder;
Expand All @@ -18,7 +20,7 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

class ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder extends AbstractElasticsearchSearchPredicateBuilder
class ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder extends AbstractElasticsearchSearchNestedPredicateBuilder
implements SpatialWithinPolygonPredicateBuilder<ElasticsearchSearchPredicateBuilder> {

private static final JsonObjectAccessor GEO_POLYGON_ACCESSOR = JsonAccessor.root().property( "geo_polygon" ).asObject();
Expand All @@ -29,7 +31,8 @@ class ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder extends Abstract

private JsonArray pointsArray;

ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder(String absoluteFieldPath) {
ElasticsearchGeoPointSpatialWithinPolygonPredicateBuilder(String absoluteFieldPath, List<String> nestedPathHierarchy) {
super( nestedPathHierarchy );
this.absoluteFieldPath = absoluteFieldPath;
}

Expand Down
Expand Up @@ -25,6 +25,9 @@
import org.hibernate.search.engine.search.predicate.SearchPredicate;
import org.hibernate.search.engine.search.predicate.dsl.PredicateFinalStep;
import org.hibernate.search.engine.search.predicate.dsl.SearchPredicateFactory;
import org.hibernate.search.engine.spatial.GeoBoundingBox;
import org.hibernate.search.engine.spatial.GeoPoint;
import org.hibernate.search.engine.spatial.GeoPolygon;
import org.hibernate.search.integrationtest.backend.tck.testsupport.configuration.DefaultAnalysisDefinitions;
import org.hibernate.search.integrationtest.backend.tck.testsupport.util.rule.SearchSetupHelper;
import org.hibernate.search.util.common.SearchException;
Expand All @@ -51,6 +54,12 @@ public class ImplicitNestedSearchPredicateIT {

private static final String SOME_SIMPLE_QUERY_STRING = "quick + fox";

private static final GeoPoint G00 = GeoPoint.of( 0, 0 );
private static final GeoPoint G20 = GeoPoint.of( 2, 0 );
private static final GeoPoint G02 = GeoPoint.of( 0, 2 );
private static final GeoPoint G22 = GeoPoint.of( 2, 2 );
private static final GeoPoint G11 = GeoPoint.of( 1, 1 );

@Rule
public SearchSetupHelper setupHelper = new SearchSetupHelper();

Expand Down Expand Up @@ -143,6 +152,21 @@ public void predicate_range() {
verify_implicit_nest( p -> p.range().field( "nested.numeric" ).atMost( ANY_INTEGER ) );
}

@Test
public void predicate_geoPoly() {
verify_implicit_nest( p -> p.spatial().within().field( "nested.geo" ).polygon( GeoPolygon.of( G00, G02, G22, G20, G00 ) ) );
}

@Test
public void predicate_geoBox() {
verify_implicit_nest( p -> p.spatial().within().field( "nested.geo" ).boundingBox( GeoBoundingBox.of( G20, G02 ) ) );
}

@Test
public void predicate_geoCircle() {
verify_implicit_nest( p -> p.spatial().within().field( "nested.geo" ).circle( G11, 1 ) );
}

@Test
public void predicate_simpleQueryString_multipleNestedPaths() {
SubTest.expectException( () -> indexManager.createScope()
Expand Down Expand Up @@ -181,6 +205,7 @@ private void initData() {
nestedDocument.addValue( indexMapping.nestedString, ANY_STRING );
nestedDocument.addValue( indexMapping.nestedNumeric, ANY_INTEGER );
nestedDocument.addValue( indexMapping.nestedText, SOME_PHRASE_TEXT );
nestedDocument.addValue( indexMapping.nestedGeo, G11 );

DocumentElement nestedDocumentX2 = nestedDocument.addObject( indexMapping.nestedX2 );
nestedDocumentX2.addValue( indexMapping.nestedX2Numeric, ANY_INTEGER );
Expand All @@ -195,6 +220,7 @@ private static class IndexMapping {
final IndexFieldReference<String> nestedString;
final IndexFieldReference<Integer> nestedNumeric;
final IndexFieldReference<String> nestedText;
final IndexFieldReference<GeoPoint> nestedGeo;

final IndexObjectFieldReference nestedX2;
final IndexFieldReference<Integer> nestedX2Numeric;
Expand All @@ -207,6 +233,7 @@ private static class IndexMapping {
this.nestedString = nestedObject.field( "string", f -> f.asString().projectable( Projectable.YES ).sortable( Sortable.YES ) ).toReference();
this.nestedNumeric = nestedObject.field( "numeric", f -> f.asInteger() ).toReference();
this.nestedText = nestedObject.field( "text", f -> f.asString().analyzer( DefaultAnalysisDefinitions.ANALYZER_STANDARD_ENGLISH.name ) ).toReference();
this.nestedGeo = nestedObject.field( "geo", f -> f.asGeoPoint() ).toReference();

IndexSchemaObjectField nestedObjectX2 = nestedObject.objectField( "nested", ObjectFieldStorage.NESTED );
this.nestedX2 = nestedObjectX2.toReference();
Expand Down

0 comments on commit 22fd361

Please sign in to comment.