Skip to content

Commit 9cead37

Browse files
Implement dis_max and combined_fields
1 parent 44a18cd commit 9cead37

File tree

1 file changed

+18
-110
lines changed

1 file changed

+18
-110
lines changed

server/src/main/java/org/elasticsearch/index/query/MultiFieldMatchQueryBuilder.java

Lines changed: 18 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,9 @@
1010
package org.elasticsearch.index.query;
1111

1212
import org.apache.lucene.analysis.Analyzer;
13-
import org.apache.lucene.analysis.TokenStream;
14-
import org.apache.lucene.index.Term;
15-
import org.apache.lucene.sandbox.search.CombinedFieldQuery;
16-
import org.apache.lucene.search.BooleanClause;
17-
import org.apache.lucene.search.BooleanQuery;
18-
import org.apache.lucene.search.BoostAttribute;
19-
import org.apache.lucene.search.BoostQuery;
2013
import org.apache.lucene.search.Query;
2114
import org.apache.lucene.search.similarities.BM25Similarity;
2215
import org.apache.lucene.search.similarities.Similarity;
23-
import org.apache.lucene.util.BytesRef;
24-
import org.apache.lucene.util.QueryBuilder;
2516
import org.elasticsearch.TransportVersion;
2617
import org.elasticsearch.TransportVersions;
2718
import org.elasticsearch.common.Strings;
@@ -30,9 +21,7 @@
3021
import org.elasticsearch.common.lucene.search.Queries;
3122
import org.elasticsearch.index.mapper.MappedFieldType;
3223
import org.elasticsearch.index.mapper.TextFieldMapper;
33-
import org.elasticsearch.index.mapper.TextSearchInfo;
3424
import org.elasticsearch.index.search.QueryParserHelper;
35-
import org.elasticsearch.lucene.analysis.miscellaneous.DisableGraphAttribute;
3625
import org.elasticsearch.lucene.similarity.LegacyBM25Similarity;
3726
import org.elasticsearch.xcontent.ConstructingObjectParser;
3827
import org.elasticsearch.xcontent.ObjectParser;
@@ -293,7 +282,7 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException {
293282

294283
validateSimilarity(context, fields);
295284

296-
Map<Analyzer, List<FieldAndBoost>> groups = new HashMap<>();
285+
Map<Analyzer, List<String>> groups = new HashMap<>();
297286
for (Map.Entry<String, Float> entry : fields.entrySet()) {
298287
String name = entry.getKey();
299288
MappedFieldType fieldType = context.getFieldType(name);
@@ -307,41 +296,43 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException {
307296
);
308297
}
309298

310-
float boost = entry.getValue() == null ? 1.0f : entry.getValue();
299+
// TODO: handle per-field boosts.
311300

312301
Analyzer analyzer = fieldType.getTextSearchInfo().searchAnalyzer();
313302
if (groups.containsKey(analyzer) == false) {
314303
groups.put(analyzer, new ArrayList<>());
315304
}
316-
groups.get(analyzer).add(new FieldAndBoost(fieldType, boost));
305+
groups.get(analyzer).add(name);
317306
}
318307

319308
// TODO: For now assume we have one group.
320309
assert groups.size() == 1;
321310

322-
List<Query> queries = new ArrayList<>();
323-
for (Map.Entry<Analyzer, List<FieldAndBoost>> group : groups.entrySet()) {
324-
var fieldsAndBoosts = group.getValue();
325-
311+
var disMax = new DisMaxQueryBuilder();
312+
for (Map.Entry<Analyzer, List<String>> group : groups.entrySet()) {
313+
/*
314+
TODO
326315
String placeholderFieldName = fieldsAndBoosts.get(0).fieldType.name();
327316
boolean canGenerateSynonymsPhraseQuery = autoGenerateSynonymsPhraseQuery;
328317
for (FieldAndBoost fieldAndBoost : fieldsAndBoosts) {
329318
TextSearchInfo textSearchInfo = fieldAndBoost.fieldType.getTextSearchInfo();
330319
canGenerateSynonymsPhraseQuery &= textSearchInfo.hasPositions();
331320
}
321+
*/
332322

333-
var builder = new CombinedFieldsBuilder(fieldsAndBoosts, group.getKey(), canGenerateSynonymsPhraseQuery, context);
334-
Query query = builder.createBooleanQuery(placeholderFieldName, value.toString(), operator.toBooleanClauseOccur());
323+
disMax.add(new CombinedFieldsQueryBuilder(value, group.getValue().toArray(new String[0])));
324+
}
335325

336-
query = Queries.maybeApplyMinimumShouldMatch(query, minimumShouldMatch);
337-
if (query == null) {
338-
query = zeroTermsQuery.asQuery();
339-
}
340-
queries.add(query);
326+
/*
327+
TODO
328+
Query query = disMax.createBooleanQuery(placeholderFieldName, value.toString(), operator.toBooleanClauseOccur());
329+
query = Queries.maybeApplyMinimumShouldMatch(query, minimumShouldMatch);
330+
if (query == null) {
331+
query = zeroTermsQuery.asQuery();
341332
}
342333
343-
// TODO: combine queries.
344-
return queries.getFirst();
334+
*/
335+
return disMax.doToQuery(context);
345336
}
346337

347338
private static void validateSimilarity(SearchExecutionContext context, Map<String, Float> fields) {
@@ -359,89 +350,6 @@ private static void validateSimilarity(SearchExecutionContext context, Map<Strin
359350
}
360351
}
361352

362-
private static final class FieldAndBoost {
363-
final MappedFieldType fieldType;
364-
final float boost;
365-
366-
FieldAndBoost(MappedFieldType fieldType, float boost) {
367-
this.fieldType = Objects.requireNonNull(fieldType);
368-
this.boost = boost;
369-
}
370-
}
371-
372-
private static class CombinedFieldsBuilder extends QueryBuilder {
373-
private final List<FieldAndBoost> fields;
374-
private final SearchExecutionContext context;
375-
376-
CombinedFieldsBuilder(
377-
List<FieldAndBoost> fields,
378-
Analyzer analyzer,
379-
boolean autoGenerateSynonymsPhraseQuery,
380-
SearchExecutionContext context
381-
) {
382-
super(analyzer);
383-
this.fields = fields;
384-
setAutoGenerateMultiTermSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
385-
this.context = context;
386-
}
387-
388-
@Override
389-
protected Query createFieldQuery(TokenStream source, BooleanClause.Occur operator, String field, boolean quoted, int phraseSlop) {
390-
if (source.hasAttribute(DisableGraphAttribute.class)) {
391-
/*
392-
* A {@link TokenFilter} in this {@link TokenStream} disabled the graph analysis to avoid
393-
* paths explosion. See {@link org.elasticsearch.index.analysis.ShingleTokenFilterFactory} for details.
394-
*/
395-
setEnableGraphQueries(false);
396-
}
397-
try {
398-
return super.createFieldQuery(source, operator, field, quoted, phraseSlop);
399-
} finally {
400-
setEnableGraphQueries(true);
401-
}
402-
}
403-
404-
@Override
405-
public Query createPhraseQuery(String field, String queryText, int phraseSlop) {
406-
throw new IllegalArgumentException("[multi_field_match] queries don't support phrases");
407-
}
408-
409-
@Override
410-
protected Query newSynonymQuery(String field, TermAndBoost[] terms) {
411-
CombinedFieldQuery.Builder query = new CombinedFieldQuery.Builder();
412-
for (TermAndBoost termAndBoost : terms) {
413-
assert termAndBoost.boost() == BoostAttribute.DEFAULT_BOOST;
414-
BytesRef bytes = termAndBoost.term();
415-
query.addTerm(bytes);
416-
}
417-
for (FieldAndBoost fieldAndBoost : fields) {
418-
MappedFieldType fieldType = fieldAndBoost.fieldType;
419-
float fieldBoost = fieldAndBoost.boost;
420-
query.addField(fieldType.name(), fieldBoost);
421-
}
422-
return query.build();
423-
}
424-
425-
@Override
426-
protected Query newTermQuery(Term term, float boost) {
427-
TermAndBoost termAndBoost = new TermAndBoost(term.bytes(), boost);
428-
return newSynonymQuery(term.field(), new TermAndBoost[] { termAndBoost });
429-
}
430-
431-
@Override
432-
protected Query analyzePhrase(String field, TokenStream stream, int slop) throws IOException {
433-
BooleanQuery.Builder builder = new BooleanQuery.Builder();
434-
for (FieldAndBoost fieldAndBoost : fields) {
435-
Query query = fieldAndBoost.fieldType.phraseQuery(stream, slop, enablePositionIncrements, context);
436-
if (fieldAndBoost.boost != 1f) {
437-
query = new BoostQuery(query, fieldAndBoost.boost);
438-
}
439-
builder.add(query, BooleanClause.Occur.SHOULD);
440-
}
441-
return builder.build();
442-
}
443-
}
444-
445353
@Override
446354
protected int doHashCode() {
447355
return Objects.hash(value, fieldsAndBoosts, operator, minimumShouldMatch, zeroTermsQuery, autoGenerateSynonymsPhraseQuery);

0 commit comments

Comments
 (0)