19
19
package org .elasticsearch .index .query ;
20
20
21
21
import org .apache .lucene .index .Term ;
22
+ import org .apache .lucene .index .IndexReader ;
23
+ import org .apache .lucene .index .TermContext ;
24
+ import org .apache .lucene .search .BooleanQuery ;
22
25
import org .apache .lucene .search .BoostQuery ;
23
26
import org .apache .lucene .search .ConstantScoreQuery ;
24
27
import org .apache .lucene .search .MultiTermQuery ;
25
28
import org .apache .lucene .search .PrefixQuery ;
26
29
import org .apache .lucene .search .Query ;
27
30
import org .apache .lucene .search .TermQuery ;
28
31
import org .apache .lucene .search .spans .FieldMaskingSpanQuery ;
32
+ import org .apache .lucene .search .ScoringRewrite ;
33
+ import org .apache .lucene .search .TopTermsRewrite ;
29
34
import org .apache .lucene .search .spans .SpanBoostQuery ;
30
35
import org .apache .lucene .search .spans .SpanMultiTermQueryWrapper ;
36
+ import org .apache .lucene .search .spans .SpanOrQuery ;
31
37
import org .apache .lucene .search .spans .SpanQuery ;
32
38
import org .apache .lucene .search .spans .SpanTermQuery ;
33
39
import org .elasticsearch .Version ;
40
+ import org .elasticsearch .ElasticsearchException ;
34
41
import org .elasticsearch .common .ParseField ;
35
42
import org .elasticsearch .common .ParsingException ;
36
43
import org .elasticsearch .common .io .stream .StreamInput ;
42
49
import org .elasticsearch .index .query .support .QueryParsers ;
43
50
44
51
import java .io .IOException ;
52
+ import java .util .ArrayList ;
53
+ import java .util .List ;
45
54
import java .util .Objects ;
46
55
47
56
/**
48
57
* Query that allows wrapping a {@link MultiTermQueryBuilder} (one of wildcard, fuzzy, prefix, term, range or regexp query)
49
58
* as a {@link SpanQueryBuilder} so it can be nested.
50
59
*/
51
60
public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder <SpanMultiTermQueryBuilder >
52
- implements SpanQueryBuilder {
61
+ implements SpanQueryBuilder {
53
62
54
63
public static final String NAME = "span_multi" ;
55
-
56
64
private static final ParseField MATCH_FIELD = new ParseField ("match" );
57
-
58
65
private final MultiTermQueryBuilder multiTermQueryBuilder ;
59
66
60
67
public SpanMultiTermQueryBuilder (MultiTermQueryBuilder multiTermQueryBuilder ) {
@@ -83,7 +90,7 @@ public MultiTermQueryBuilder innerQuery() {
83
90
84
91
@ Override
85
92
protected void doXContent (XContentBuilder builder , Params params )
86
- throws IOException {
93
+ throws IOException {
87
94
builder .startObject (NAME );
88
95
builder .field (MATCH_FIELD .getPreferredName ());
89
96
multiTermQueryBuilder .toXContent (builder , params );
@@ -105,7 +112,7 @@ public static SpanMultiTermQueryBuilder fromXContent(XContentParser parser) thro
105
112
QueryBuilder query = parseInnerQueryBuilder (parser );
106
113
if (query instanceof MultiTermQueryBuilder == false ) {
107
114
throw new ParsingException (parser .getTokenLocation (),
108
- "[span_multi] [" + MATCH_FIELD .getPreferredName () + "] must be of type multi term query" );
115
+ "[span_multi] [" + MATCH_FIELD .getPreferredName () + "] must be of type multi term query" );
109
116
}
110
117
subQuery = (MultiTermQueryBuilder ) query ;
111
118
} else {
@@ -124,12 +131,55 @@ public static SpanMultiTermQueryBuilder fromXContent(XContentParser parser) thro
124
131
125
132
if (subQuery == null ) {
126
133
throw new ParsingException (parser .getTokenLocation (),
127
- "[span_multi] must have [" + MATCH_FIELD .getPreferredName () + "] multi term query clause" );
134
+ "[span_multi] must have [" + MATCH_FIELD .getPreferredName () + "] multi term query clause" );
128
135
}
129
136
130
137
return new SpanMultiTermQueryBuilder (subQuery ).queryName (queryName ).boost (boost );
131
138
}
132
139
140
+ public static class TopTermSpanBooleanQueryRewriteWithMaxClause extends SpanMultiTermQueryWrapper .SpanRewriteMethod {
141
+
142
+ private MultiTermQuery multiTermQuery ;
143
+ private final long maxExpansions ;
144
+
145
+ TopTermSpanBooleanQueryRewriteWithMaxClause (long max ) {
146
+ maxExpansions = max ;
147
+ }
148
+
149
+ @ Override
150
+ public SpanQuery rewrite (IndexReader reader , MultiTermQuery query ) throws IOException {
151
+ multiTermQuery = query ;
152
+ return (SpanQuery ) this .delegate .rewrite (reader , multiTermQuery );
153
+ }
154
+
155
+ final ScoringRewrite <List <SpanQuery >> delegate = new ScoringRewrite <List <SpanQuery >>() {
156
+
157
+ @ Override
158
+ protected List <SpanQuery > getTopLevelBuilder () {
159
+ return new ArrayList ();
160
+ }
161
+
162
+ @ Override
163
+ protected Query build (List <SpanQuery > builder ) {
164
+ return new SpanOrQuery ((SpanQuery []) builder .toArray (new SpanQuery [builder .size ()]));
165
+ }
166
+
167
+ @ Override
168
+ protected void checkMaxClauseCount (int count ) {
169
+ if (count > maxExpansions ) {
170
+ throw new ElasticsearchException ("[" + multiTermQuery .toString () + " ] " +
171
+ "exceeds maxClauseCount [ Boolean maxClauseCount is set to " + BooleanQuery .getMaxClauseCount () + "]" );
172
+ }
173
+ }
174
+
175
+ @ Override
176
+ protected void addClause (List <SpanQuery > topLevel , Term term , int docCount , float boost , TermContext states ) {
177
+ SpanTermQuery q = new SpanTermQuery (term , states );
178
+ topLevel .add (q );
179
+ }
180
+ };
181
+ }
182
+
133
183
@ Override
134
184
protected Query doToQuery (QueryShardContext context ) throws IOException {
135
185
Query subQuery = multiTermQueryBuilder .toQuery (context );
@@ -190,10 +240,15 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
190
240
+ MultiTermQuery .class .getName () + " but was " + subQuery .getClass ().getName ());
191
241
}
192
242
spanQuery = new SpanMultiTermQueryWrapper <>((MultiTermQuery ) subQuery );
243
+ if (((MultiTermQuery ) subQuery ).getRewriteMethod () instanceof TopTermsRewrite == false ) {
244
+ ((SpanMultiTermQueryWrapper <MultiTermQuery >) spanQuery ).setRewriteMethod (new
245
+ TopTermSpanBooleanQueryRewriteWithMaxClause (BooleanQuery .getMaxClauseCount ()));
246
+ }
193
247
}
194
248
if (boost != AbstractQueryBuilder .DEFAULT_BOOST ) {
195
249
return new SpanBoostQuery (spanQuery , boost );
196
250
}
251
+
197
252
return spanQuery ;
198
253
}
199
254
0 commit comments