55 */
66package org .elasticsearch .xpack .spatial .index .query ;
77
8- import org .apache .lucene .document .ShapeField ;
98import org .apache .lucene .document .XYShape ;
10- import org .apache .lucene .geo .XYLine ;
11- import org .apache .lucene .geo .XYPolygon ;
12- import org .apache .lucene .search .BooleanClause ;
13- import org .apache .lucene .search .BooleanQuery ;
14- import org .apache .lucene .search .ConstantScoreQuery ;
9+ import org .apache .lucene .geo .XYGeometry ;
1510import org .apache .lucene .search .MatchNoDocsQuery ;
1611import org .apache .lucene .search .Query ;
1712import org .elasticsearch .Version ;
3328import org .elasticsearch .index .query .QueryShardContext ;
3429import org .elasticsearch .index .query .QueryShardException ;
3530import org .elasticsearch .xpack .spatial .index .mapper .ShapeFieldMapper ;
31+ import org .elasticsearch .xpack .spatial .index .mapper .ShapeUtils ;
32+
33+ import java .util .ArrayList ;
34+ import java .util .List ;
3635
37- import static org .elasticsearch .xpack .spatial .index .mapper .ShapeIndexer .toLucenePolygon ;
3836
3937public class ShapeQueryProcessor implements AbstractSearchableGeometryFieldType .QueryProcessor {
4038
4139 @ Override
4240 public Query process (Geometry shape , String fieldName , ShapeRelation relation , QueryShardContext context ) {
4341 validateIsShapeFieldType (fieldName , context );
44- if (shape == null ) {
45- return new MatchNoDocsQuery ();
46- }
4742 // CONTAINS queries are not supported by VECTOR strategy for indices created before version 7.5.0 (Lucene 8.3.0);
4843 if (relation == ShapeRelation .CONTAINS && context .indexVersionCreated ().before (Version .V_7_5_0 )) {
4944 throw new QueryShardException (context ,
5045 ShapeRelation .CONTAINS + " query relation not supported for Field [" + fieldName + "]." );
5146 }
52- // wrap geometry Query as a ConstantScoreQuery
53- return new ConstantScoreQuery (shape .visit (new ShapeVisitor (context , fieldName , relation )));
47+ if (shape == null ) {
48+ return new MatchNoDocsQuery ();
49+ }
50+ return getVectorQueryFromShape (shape , fieldName , relation , context );
5451 }
5552
5653 private void validateIsShapeFieldType (String fieldName , QueryShardContext context ) {
@@ -61,115 +58,107 @@ private void validateIsShapeFieldType(String fieldName, QueryShardContext contex
6158 }
6259 }
6360
64- private class ShapeVisitor implements GeometryVisitor <Query , RuntimeException > {
65- QueryShardContext context ;
66- String fieldName ;
67- ShapeRelation relation ;
61+ private Query getVectorQueryFromShape (Geometry queryShape , String fieldName , ShapeRelation relation , QueryShardContext context ) {
62+ final LuceneGeometryCollector visitor = new LuceneGeometryCollector (fieldName , context );
63+ queryShape .visit (visitor );
64+ final List <XYGeometry > geometries = visitor .geometries ();
65+ if (geometries .size () == 0 ) {
66+ return new MatchNoDocsQuery ();
67+ }
68+ return XYShape .newGeometryQuery (fieldName , relation .getLuceneRelation (),
69+ geometries .toArray (new XYGeometry [geometries .size ()]));
70+ }
71+
72+ private static class LuceneGeometryCollector implements GeometryVisitor <Void , RuntimeException > {
73+ private final List <XYGeometry > geometries = new ArrayList <>();
74+ private final String name ;
75+ private final QueryShardContext context ;
6876
69- ShapeVisitor (QueryShardContext context , String fieldName , ShapeRelation relation ) {
77+ private LuceneGeometryCollector (String name , QueryShardContext context ) {
78+ this .name = name ;
7079 this .context = context ;
71- this .fieldName = fieldName ;
72- this .relation = relation ;
7380 }
7481
75- @ Override
76- public Query visit (Circle circle ) {
77- throw new QueryShardException (context , "Field [" + fieldName + "] found and unknown shape Circle" );
82+ List <XYGeometry > geometries () {
83+ return geometries ;
7884 }
7985
8086 @ Override
81- public Query visit (GeometryCollection <?> collection ) {
82- BooleanQuery .Builder bqb = new BooleanQuery .Builder ();
83- visit (bqb , collection );
84- return bqb .build ();
85- }
86-
87- private void visit (BooleanQuery .Builder bqb , GeometryCollection <?> collection ) {
88- BooleanClause .Occur occur ;
89- if (relation == ShapeRelation .CONTAINS || relation == ShapeRelation .DISJOINT ) {
90- // all shapes must be disjoint / must be contained in relation to the indexed shape.
91- occur = BooleanClause .Occur .MUST ;
92- } else {
93- // at least one shape must intersect / contain the indexed shape.
94- occur = BooleanClause .Occur .SHOULD ;
87+ public Void visit (Circle circle ) {
88+ if (circle .isEmpty () == false ) {
89+ geometries .add (ShapeUtils .toLuceneXYCircle (circle ));
9590 }
91+ return null ;
92+ }
93+
94+ @ Override
95+ public Void visit (GeometryCollection <?> collection ) {
9696 for (Geometry shape : collection ) {
97- bqb . add ( shape .visit (this ), occur );
97+ shape .visit (this );
9898 }
99+ return null ;
99100 }
100101
101102 @ Override
102- public Query visit (Line line ) {
103- return XYShape .newLineQuery (fieldName , relation .getLuceneRelation (),
104- new XYLine (doubleArrayToFloatArray (line .getX ()), doubleArrayToFloatArray (line .getY ())));
103+ public Void visit (Line line ) {
104+ if (line .isEmpty () == false ) {
105+ geometries .add (ShapeUtils .toLuceneXYLine (line ));
106+ }
107+ return null ;
105108 }
106109
107110 @ Override
108- public Query visit (LinearRing ring ) {
109- throw new QueryShardException (context , "Field [" + fieldName + "] found and unsupported shape LinearRing" );
111+ public Void visit (LinearRing ring ) {
112+ throw new QueryShardException (context , "Field [" + name + "] found and unsupported shape LinearRing" );
110113 }
111114
112115 @ Override
113- public Query visit (MultiLine multiLine ) {
114- XYLine [] lines = new XYLine [multiLine .size ()];
115- for (int i =0 ; i <multiLine .size (); i ++) {
116- lines [i ] = new XYLine (doubleArrayToFloatArray (multiLine .get (i ).getX ()),
117- doubleArrayToFloatArray (multiLine .get (i ).getY ()));
116+ public Void visit (MultiLine multiLine ) {
117+ for (Line line : multiLine ) {
118+ visit (line );
118119 }
119- return XYShape . newLineQuery ( fieldName , relation . getLuceneRelation (), lines ) ;
120+ return null ;
120121 }
121122
122123 @ Override
123- public Query visit (MultiPoint multiPoint ) {
124- float [][] points = new float [multiPoint .size ()][2 ];
125- for (int i = 0 ; i < multiPoint .size (); i ++) {
126- points [i ] = new float [] {(float ) multiPoint .get (i ).getX (), (float ) multiPoint .get (i ).getY ()};
124+ public Void visit (MultiPoint multiPoint ) {
125+ for (Point point : multiPoint ) {
126+ visit (point );
127127 }
128- return XYShape . newPointQuery ( fieldName , relation . getLuceneRelation (), points ) ;
128+ return null ;
129129 }
130130
131131 @ Override
132- public Query visit (MultiPolygon multiPolygon ) {
133- XYPolygon [] polygons = new XYPolygon [multiPolygon .size ()];
134- for (int i =0 ; i <multiPolygon .size (); i ++) {
135- polygons [i ] = toLucenePolygon (multiPolygon .get (i ));
132+ public Void visit (MultiPolygon multiPolygon ) {
133+ for (Polygon polygon : multiPolygon ) {
134+ visit (polygon );
136135 }
137- return visitMultiPolygon (polygons );
138- }
139-
140- private Query visitMultiPolygon (XYPolygon ... polygons ) {
141- return XYShape .newPolygonQuery (fieldName , relation .getLuceneRelation (), polygons );
136+ return null ;
142137 }
143138
144139 @ Override
145- public Query visit (Point point ) {
146- ShapeField .QueryRelation luceneRelation = relation .getLuceneRelation ();
147- if (luceneRelation == ShapeField .QueryRelation .CONTAINS ) {
148- // contains and intersects are equivalent but the implementation of
149- // intersects is more efficient.
150- luceneRelation = ShapeField .QueryRelation .INTERSECTS ;
140+ public Void visit (Point point ) {
141+ if (point .isEmpty () == false ) {
142+ geometries .add (ShapeUtils .toLuceneXYPoint (point ));
151143 }
152- float [][] pointArray = new float [][] {{(float )point .getX (), (float )point .getY ()}};
153- return XYShape .newPointQuery (fieldName , luceneRelation , pointArray );
154- }
144+ return null ;
155145
156- @ Override
157- public Query visit (Polygon polygon ) {
158- return XYShape .newPolygonQuery (fieldName , relation .getLuceneRelation (), toLucenePolygon (polygon ));
159146 }
160147
161148 @ Override
162- public Query visit (Rectangle r ) {
163- return XYShape .newBoxQuery (fieldName , relation .getLuceneRelation (),
164- (float )r .getMinX (), (float )r .getMaxX (), (float )r .getMinY (), (float )r .getMaxY ());
149+ public Void visit (Polygon polygon ) {
150+ if (polygon .isEmpty () == false ) {
151+ geometries .add (ShapeUtils .toLuceneXYPolygon (polygon ));
152+ }
153+ return null ;
165154 }
166- }
167155
168- private static float [] doubleArrayToFloatArray (double [] array ) {
169- float [] result = new float [array .length ];
170- for (int i = 0 ; i < array .length ; ++i ) {
171- result [i ] = (float ) array [i ];
156+ @ Override
157+ public Void visit (Rectangle r ) {
158+ if (r .isEmpty () == false ) {
159+ geometries .add (ShapeUtils .toLuceneXYRectangle (r ));
160+ }
161+ return null ;
172162 }
173- return result ;
174163 }
175164}
0 commit comments