5
5
*/
6
6
package org .elasticsearch .xpack .spatial .index .query ;
7
7
8
- import org .apache .lucene .document .ShapeField ;
9
8
import 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 ;
15
10
import org .apache .lucene .search .MatchNoDocsQuery ;
16
11
import org .apache .lucene .search .Query ;
17
12
import org .elasticsearch .Version ;
33
28
import org .elasticsearch .index .query .QueryShardContext ;
34
29
import org .elasticsearch .index .query .QueryShardException ;
35
30
import 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 ;
36
35
37
- import static org .elasticsearch .xpack .spatial .index .mapper .ShapeIndexer .toLucenePolygon ;
38
36
39
37
public class ShapeQueryProcessor implements AbstractSearchableGeometryFieldType .QueryProcessor {
40
38
41
39
@ Override
42
40
public Query process (Geometry shape , String fieldName , ShapeRelation relation , QueryShardContext context ) {
43
41
validateIsShapeFieldType (fieldName , context );
44
- if (shape == null ) {
45
- return new MatchNoDocsQuery ();
46
- }
47
42
// CONTAINS queries are not supported by VECTOR strategy for indices created before version 7.5.0 (Lucene 8.3.0);
48
43
if (relation == ShapeRelation .CONTAINS && context .indexVersionCreated ().before (Version .V_7_5_0 )) {
49
44
throw new QueryShardException (context ,
50
45
ShapeRelation .CONTAINS + " query relation not supported for Field [" + fieldName + "]." );
51
46
}
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 );
54
51
}
55
52
56
53
private void validateIsShapeFieldType (String fieldName , QueryShardContext context ) {
@@ -61,115 +58,107 @@ private void validateIsShapeFieldType(String fieldName, QueryShardContext contex
61
58
}
62
59
}
63
60
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 ;
68
76
69
- ShapeVisitor (QueryShardContext context , String fieldName , ShapeRelation relation ) {
77
+ private LuceneGeometryCollector (String name , QueryShardContext context ) {
78
+ this .name = name ;
70
79
this .context = context ;
71
- this .fieldName = fieldName ;
72
- this .relation = relation ;
73
80
}
74
81
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 ;
78
84
}
79
85
80
86
@ 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 ));
95
90
}
91
+ return null ;
92
+ }
93
+
94
+ @ Override
95
+ public Void visit (GeometryCollection <?> collection ) {
96
96
for (Geometry shape : collection ) {
97
- bqb . add ( shape .visit (this ), occur );
97
+ shape .visit (this );
98
98
}
99
+ return null ;
99
100
}
100
101
101
102
@ 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 ;
105
108
}
106
109
107
110
@ 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" );
110
113
}
111
114
112
115
@ 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 );
118
119
}
119
- return XYShape . newLineQuery ( fieldName , relation . getLuceneRelation (), lines ) ;
120
+ return null ;
120
121
}
121
122
122
123
@ 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 );
127
127
}
128
- return XYShape . newPointQuery ( fieldName , relation . getLuceneRelation (), points ) ;
128
+ return null ;
129
129
}
130
130
131
131
@ 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 );
136
135
}
137
- return visitMultiPolygon (polygons );
138
- }
139
-
140
- private Query visitMultiPolygon (XYPolygon ... polygons ) {
141
- return XYShape .newPolygonQuery (fieldName , relation .getLuceneRelation (), polygons );
136
+ return null ;
142
137
}
143
138
144
139
@ 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 ));
151
143
}
152
- float [][] pointArray = new float [][] {{(float )point .getX (), (float )point .getY ()}};
153
- return XYShape .newPointQuery (fieldName , luceneRelation , pointArray );
154
- }
144
+ return null ;
155
145
156
- @ Override
157
- public Query visit (Polygon polygon ) {
158
- return XYShape .newPolygonQuery (fieldName , relation .getLuceneRelation (), toLucenePolygon (polygon ));
159
146
}
160
147
161
148
@ 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 ;
165
154
}
166
- }
167
155
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 ;
172
162
}
173
- return result ;
174
163
}
175
164
}
0 commit comments