1919package org .elasticsearch .index .query ;
2020
2121import 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 ;
2225import org .apache .lucene .search .BoostQuery ;
2326import org .apache .lucene .search .ConstantScoreQuery ;
2427import org .apache .lucene .search .MultiTermQuery ;
2528import org .apache .lucene .search .PrefixQuery ;
2629import org .apache .lucene .search .Query ;
2730import org .apache .lucene .search .TermQuery ;
2831import org .apache .lucene .search .spans .FieldMaskingSpanQuery ;
32+ import org .apache .lucene .search .ScoringRewrite ;
33+ import org .apache .lucene .search .TopTermsRewrite ;
2934import org .apache .lucene .search .spans .SpanBoostQuery ;
3035import org .apache .lucene .search .spans .SpanMultiTermQueryWrapper ;
36+ import org .apache .lucene .search .spans .SpanOrQuery ;
3137import org .apache .lucene .search .spans .SpanQuery ;
3238import org .apache .lucene .search .spans .SpanTermQuery ;
3339import org .elasticsearch .Version ;
40+ import org .elasticsearch .ElasticsearchException ;
3441import org .elasticsearch .common .ParseField ;
3542import org .elasticsearch .common .ParsingException ;
3643import org .elasticsearch .common .io .stream .StreamInput ;
4249import org .elasticsearch .index .query .support .QueryParsers ;
4350
4451import java .io .IOException ;
52+ import java .util .ArrayList ;
53+ import java .util .List ;
4554import java .util .Objects ;
4655
4756/**
4857 * Query that allows wrapping a {@link MultiTermQueryBuilder} (one of wildcard, fuzzy, prefix, term, range or regexp query)
4958 * as a {@link SpanQueryBuilder} so it can be nested.
5059 */
5160public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder <SpanMultiTermQueryBuilder >
52- implements SpanQueryBuilder {
61+ implements SpanQueryBuilder {
5362
5463 public static final String NAME = "span_multi" ;
55-
5664 private static final ParseField MATCH_FIELD = new ParseField ("match" );
57-
5865 private final MultiTermQueryBuilder multiTermQueryBuilder ;
5966
6067 public SpanMultiTermQueryBuilder (MultiTermQueryBuilder multiTermQueryBuilder ) {
@@ -83,7 +90,7 @@ public MultiTermQueryBuilder innerQuery() {
8390
8491 @ Override
8592 protected void doXContent (XContentBuilder builder , Params params )
86- throws IOException {
93+ throws IOException {
8794 builder .startObject (NAME );
8895 builder .field (MATCH_FIELD .getPreferredName ());
8996 multiTermQueryBuilder .toXContent (builder , params );
@@ -105,7 +112,7 @@ public static SpanMultiTermQueryBuilder fromXContent(XContentParser parser) thro
105112 QueryBuilder query = parseInnerQueryBuilder (parser );
106113 if (query instanceof MultiTermQueryBuilder == false ) {
107114 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" );
109116 }
110117 subQuery = (MultiTermQueryBuilder ) query ;
111118 } else {
@@ -124,12 +131,55 @@ public static SpanMultiTermQueryBuilder fromXContent(XContentParser parser) thro
124131
125132 if (subQuery == null ) {
126133 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" );
128135 }
129136
130137 return new SpanMultiTermQueryBuilder (subQuery ).queryName (queryName ).boost (boost );
131138 }
132139
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+
133183 @ Override
134184 protected Query doToQuery (QueryShardContext context ) throws IOException {
135185 Query subQuery = multiTermQueryBuilder .toQuery (context );
@@ -190,10 +240,15 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
190240 + MultiTermQuery .class .getName () + " but was " + subQuery .getClass ().getName ());
191241 }
192242 spanQuery = new SpanMultiTermQueryWrapper <>((MultiTermQuery ) subQuery );
243+ if (((MultiTermQuery ) subQuery ).getRewriteMethod () instanceof TopTermsRewrite == false ) {
244+ ((SpanMultiTermQueryWrapper <MultiTermQuery >) spanQuery ).setRewriteMethod (new
245+ TopTermSpanBooleanQueryRewriteWithMaxClause (BooleanQuery .getMaxClauseCount ()));
246+ }
193247 }
194248 if (boost != AbstractQueryBuilder .DEFAULT_BOOST ) {
195249 return new SpanBoostQuery (spanQuery , boost );
196250 }
251+
197252 return spanQuery ;
198253 }
199254
0 commit comments