From 10ddd691a36fa3a8199fac8da43da540af19a697 Mon Sep 17 00:00:00 2001 From: javanna Date: Fri, 23 Oct 2015 11:55:28 +0200 Subject: [PATCH] Internal: move to lucene BoostQuery Latest version of lucene deprecated Query#setBoost and Query#getBoost which made queries effectively immutable. Those methods need to be replaced with `BoostQuery` that wraps any query that needs boosting. This commit replaces usages of setBoost with BoostQuery and adds it to forbidden-apis for prod code. Usages of `getBoost` are only partially removed, as some will have to stay for backwards compatibility. Closes #14264 --- .../resources/forbidden/core-signatures.txt | 3 + .../lucene/queries/BlendedTermQuery.java | 67 ++-- .../apache/lucene/queries/MinDocQuery.java | 3 +- .../classic/MapperQueryParser.java | 70 ++--- .../vectorhighlight/CustomFieldQuery.java | 9 +- .../common/lucene/all/AllTermQuery.java | 13 +- .../lucene/search/MoreLikeThisQuery.java | 36 +-- .../lucene/search/MultiPhrasePrefixQuery.java | 18 +- .../common/lucene/search/Queries.java | 13 +- .../common/lucene/search/XMoreLikeThis.java | 4 +- .../function/FiltersFunctionScoreQuery.java | 5 +- .../search/function/FunctionScoreQuery.java | 5 +- .../index/mapper/core/DateFieldMapper.java | 15 +- .../index/query/AbstractQueryBuilder.java | 25 +- .../index/query/BoolQueryBuilder.java | 4 +- .../index/query/HasChildQueryBuilder.java | 18 +- .../index/query/HasParentQueryBuilder.java | 1 - .../index/query/IndicesQueryBuilder.java | 8 - .../index/query/MatchQueryBuilder.java | 3 +- .../index/query/MultiMatchQueryBuilder.java | 6 - .../index/query/QueryStringQueryBuilder.java | 27 +- .../index/query/ScriptQueryBuilder.java | 5 +- .../index/query/SimpleQueryParser.java | 28 +- .../index/query/SimpleQueryStringBuilder.java | 5 - .../query/SpanMultiTermQueryBuilder.java | 17 +- .../index/query/TemplateQueryBuilder.java | 5 - .../index/query/WrapperQueryBuilder.java | 5 - .../index/search/MultiMatchQuery.java | 14 +- .../geo/InMemoryGeoBoundingBoxQuery.java | 7 +- .../search/nested/IncludeNestedDocsQuery.java | 295 ------------------ .../search/internal/DefaultSearchContext.java | 7 +- .../search/MultiPhrasePrefixQueryTests.java | 6 +- .../index/query/AbstractQueryTestCase.java | 47 ++- .../index/query/DisMaxQueryBuilderTests.java | 19 +- .../index/query/FuzzyQueryBuilderTests.java | 13 +- .../index/query/IndicesQueryBuilderTests.java | 10 +- .../index/query/MatchQueryBuilderTests.java | 16 +- .../query/MultiMatchQueryBuilderTests.java | 33 +- .../query/QueryStringQueryBuilderTests.java | 82 +++-- .../index/query/RandomQueryBuilder.java | 23 +- .../query/SimpleQueryStringBuilderTests.java | 60 ++-- .../query/SpanMultiTermQueryBuilderTests.java | 20 ++ .../query/TemplateQueryBuilderTests.java | 5 - .../index/query/WrapperQueryBuilderTests.java | 5 - 44 files changed, 380 insertions(+), 700 deletions(-) delete mode 100644 core/src/main/java/org/elasticsearch/index/search/nested/IncludeNestedDocsQuery.java diff --git a/buildSrc/src/main/resources/forbidden/core-signatures.txt b/buildSrc/src/main/resources/forbidden/core-signatures.txt index 08c548f1dcc98..0f54946ea3703 100644 --- a/buildSrc/src/main/resources/forbidden/core-signatures.txt +++ b/buildSrc/src/main/resources/forbidden/core-signatures.txt @@ -87,3 +87,6 @@ java.util.concurrent.Future#cancel(boolean) @defaultMessage Don't try reading from paths that are not configured in Environment, resolve from Environment instead org.elasticsearch.common.io.PathUtils#get(java.lang.String, java.lang.String[]) org.elasticsearch.common.io.PathUtils#get(java.net.URI) + +@defaultMessage Don't use deprecated Query#setBoost, wrap the query into a BoostQuery instead +org.apache.lucene.search.Query#setBoost(float) diff --git a/core/src/main/java/org/apache/lucene/queries/BlendedTermQuery.java b/core/src/main/java/org/apache/lucene/queries/BlendedTermQuery.java index e411139bab075..81f49055223ab 100644 --- a/core/src/main/java/org/apache/lucene/queries/BlendedTermQuery.java +++ b/core/src/main/java/org/apache/lucene/queries/BlendedTermQuery.java @@ -18,18 +18,9 @@ */ package org.apache.lucene.queries; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.IndexReaderContext; -import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermContext; -import org.apache.lucene.index.TermState; -import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.index.*; +import org.apache.lucene.search.*; import org.apache.lucene.search.BooleanClause.Occur; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.DisjunctionMaxQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermQuery; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.InPlaceMergeSorter; import org.apache.lucene.util.ToStringUtils; @@ -37,6 +28,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * BlendedTermQuery can be used to unify term statistics across @@ -77,6 +69,10 @@ public BlendedTermQuery(Term[] terms, float[] boosts) { @Override public Query rewrite(IndexReader reader) throws IOException { + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; + } IndexReaderContext context = reader.getContext(); TermContext[] ctx = new TermContext[terms.length]; int[] docFreqs = new int[ctx.length]; @@ -87,9 +83,7 @@ public Query rewrite(IndexReader reader) throws IOException { final int maxDoc = reader.maxDoc(); blend(ctx, maxDoc, reader); - Query query = topLevelQuery(terms, ctx, docFreqs, maxDoc); - query.setBoost(getBoost()); - return query; + return topLevelQuery(terms, ctx, docFreqs, maxDoc); } protected abstract Query topLevelQuery(Term[] terms, TermContext[] ctx, int[] docFreqs, int maxDoc); @@ -274,20 +268,15 @@ private Term[] equalsTerms() { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; BlendedTermQuery that = (BlendedTermQuery) o; - if (!Arrays.equals(equalsTerms(), that.equalsTerms())) return false; - - return true; + return Arrays.equals(equalsTerms(), that.equalsTerms()); } @Override public int hashCode() { - int result = super.hashCode(); - result = 31 * result + Arrays.hashCode(equalsTerms()); - return result; + return Objects.hash(super.hashCode(), Arrays.hashCode(equalsTerms())); } public static BlendedTermQuery booleanBlendedQuery(Term[] terms, final boolean disableCoord) { @@ -298,16 +287,16 @@ public static BlendedTermQuery booleanBlendedQuery(Term[] terms, final float[] b return new BlendedTermQuery(terms, boosts) { @Override protected Query topLevelQuery(Term[] terms, TermContext[] ctx, int[] docFreqs, int maxDoc) { - BooleanQuery.Builder query = new BooleanQuery.Builder(); - query.setDisableCoord(disableCoord); + BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder(); + booleanQueryBuilder.setDisableCoord(disableCoord); for (int i = 0; i < terms.length; i++) { - TermQuery termQuery = new TermQuery(terms[i], ctx[i]); - if (boosts != null) { - termQuery.setBoost(boosts[i]); + Query query = new TermQuery(terms[i], ctx[i]); + if (boosts != null && boosts[i] != 1f) { + query = new BoostQuery(query, boosts[i]); } - query.add(termQuery, BooleanClause.Occur.SHOULD); + booleanQueryBuilder.add(query, BooleanClause.Occur.SHOULD); } - return query.build(); + return booleanQueryBuilder.build(); } }; } @@ -321,16 +310,16 @@ protected Query topLevelQuery(Term[] terms, TermContext[] ctx, int[] docFreqs, i BooleanQuery.Builder lowBuilder = new BooleanQuery.Builder(); lowBuilder.setDisableCoord(disableCoord); for (int i = 0; i < terms.length; i++) { - TermQuery termQuery = new TermQuery(terms[i], ctx[i]); - if (boosts != null) { - termQuery.setBoost(boosts[i]); + Query query = new TermQuery(terms[i], ctx[i]); + if (boosts != null && boosts[i] != 1f) { + query = new BoostQuery(query, boosts[i]); } if ((maxTermFrequency >= 1f && docFreqs[i] > maxTermFrequency) || (docFreqs[i] > (int) Math.ceil(maxTermFrequency * (float) maxDoc))) { - highBuilder.add(termQuery, BooleanClause.Occur.SHOULD); + highBuilder.add(query, BooleanClause.Occur.SHOULD); } else { - lowBuilder.add(termQuery, BooleanClause.Occur.SHOULD); + lowBuilder.add(query, BooleanClause.Occur.SHOULD); } } BooleanQuery high = highBuilder.build(); @@ -363,15 +352,15 @@ public static BlendedTermQuery dismaxBlendedQuery(Term[] terms, final float[] bo return new BlendedTermQuery(terms, boosts) { @Override protected Query topLevelQuery(Term[] terms, TermContext[] ctx, int[] docFreqs, int maxDoc) { - DisjunctionMaxQuery query = new DisjunctionMaxQuery(tieBreakerMultiplier); + DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreakerMultiplier); for (int i = 0; i < terms.length; i++) { - TermQuery termQuery = new TermQuery(terms[i], ctx[i]); - if (boosts != null) { - termQuery.setBoost(boosts[i]); + Query query = new TermQuery(terms[i], ctx[i]); + if (boosts != null && boosts[i] != 1f) { + query = new BoostQuery(query, boosts[i]); } - query.add(termQuery); + disMaxQuery.add(query); } - return query; + return disMaxQuery; } }; } diff --git a/core/src/main/java/org/apache/lucene/queries/MinDocQuery.java b/core/src/main/java/org/apache/lucene/queries/MinDocQuery.java index 1e9ecf7ae6f77..86982bfc949cd 100644 --- a/core/src/main/java/org/apache/lucene/queries/MinDocQuery.java +++ b/core/src/main/java/org/apache/lucene/queries/MinDocQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.Weight; import java.io.IOException; +import java.util.Objects; /** A {@link Query} that only matches documents that are greater than or equal * to a configured doc ID. */ @@ -43,7 +44,7 @@ public MinDocQuery(int minDoc) { @Override public int hashCode() { - return 31 * super.hashCode() + minDoc; + return Objects.hash(super.hashCode(), minDoc); } @Override diff --git a/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java b/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java index 3ef6e5a2c6d32..fce58d2f88f35 100644 --- a/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java +++ b/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java @@ -23,13 +23,7 @@ import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.index.Term; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.DisjunctionMaxQuery; -import org.apache.lucene.search.FuzzyQuery; -import org.apache.lucene.search.MatchNoDocsQuery; -import org.apache.lucene.search.MultiPhraseQuery; -import org.apache.lucene.search.PhraseQuery; -import org.apache.lucene.search.Query; +import org.apache.lucene.search.*; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.automaton.RegExp; import org.elasticsearch.common.lucene.search.Queries; @@ -41,12 +35,7 @@ import org.elasticsearch.index.query.support.QueryParsers; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import static java.util.Collections.unmodifiableMap; import static org.elasticsearch.common.lucene.search.Queries.fixNegativeQueryIfNeeded; @@ -148,8 +137,7 @@ public Query getFieldQuery(String field, String queryText, boolean quoted) throw Query q = getFieldQuerySingle(mField, queryText, quoted); if (q != null) { added = true; - applyBoost(mField, q); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -161,8 +149,7 @@ public Query getFieldQuery(String field, String queryText, boolean quoted) throw for (String mField : fields) { Query q = getFieldQuerySingle(mField, queryText, quoted); if (q != null) { - applyBoost(mField, q); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); } } if (clauses.size() == 0) // happens for stopwords @@ -250,9 +237,8 @@ protected Query getFieldQuery(String field, String queryText, int slop) throws P Query q = super.getFieldQuery(mField, queryText, slop); if (q != null) { added = true; - applyBoost(mField, q); q = applySlop(q, slop); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -264,9 +250,8 @@ protected Query getFieldQuery(String field, String queryText, int slop) throws P for (String mField : fields) { Query q = super.getFieldQuery(mField, queryText, slop); if (q != null) { - applyBoost(mField, q); q = applySlop(q, slop); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); } } if (clauses.size() == 0) // happens for stopwords @@ -305,8 +290,7 @@ protected Query getRangeQuery(String field, String part1, String part2, boolean Query q = getRangeQuerySingle(mField, part1, part2, startInclusive, endInclusive); if (q != null) { added = true; - applyBoost(mField, q); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -318,8 +302,7 @@ protected Query getRangeQuery(String field, String part1, String part2, boolean for (String mField : fields) { Query q = getRangeQuerySingle(mField, part1, part2, startInclusive, endInclusive); if (q != null) { - applyBoost(mField, q); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); } } if (clauses.size() == 0) // happens for stopwords @@ -371,8 +354,7 @@ protected Query getFuzzyQuery(String field, String termStr, String minSimilarity Query q = getFuzzyQuerySingle(mField, termStr, minSimilarity); if (q != null) { added = true; - applyBoost(mField, q); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -383,8 +365,9 @@ protected Query getFuzzyQuery(String field, String termStr, String minSimilarity List clauses = new ArrayList<>(); for (String mField : fields) { Query q = getFuzzyQuerySingle(mField, termStr, minSimilarity); - applyBoost(mField, q); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + if (q != null) { + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); + } } return getBooleanQuery(clauses, true); } @@ -434,8 +417,7 @@ protected Query getPrefixQuery(String field, String termStr) throws ParseExcepti Query q = getPrefixQuerySingle(mField, termStr); if (q != null) { added = true; - applyBoost(mField, q); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -447,8 +429,7 @@ protected Query getPrefixQuery(String field, String termStr) throws ParseExcepti for (String mField : fields) { Query q = getPrefixQuerySingle(mField, termStr); if (q != null) { - applyBoost(mField, q); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); } } if (clauses.size() == 0) // happens for stopwords @@ -566,8 +547,7 @@ protected Query getWildcardQuery(String field, String termStr) throws ParseExcep Query q = getWildcardQuerySingle(mField, termStr); if (q != null) { added = true; - applyBoost(mField, q); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -579,8 +559,7 @@ protected Query getWildcardQuery(String field, String termStr) throws ParseExcep for (String mField : fields) { Query q = getWildcardQuerySingle(mField, termStr); if (q != null) { - applyBoost(mField, q); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); } } if (clauses.size() == 0) // happens for stopwords @@ -697,8 +676,7 @@ protected Query getRegexpQuery(String field, String termStr) throws ParseExcepti Query q = getRegexpQuerySingle(mField, termStr); if (q != null) { added = true; - applyBoost(mField, q); - disMaxQuery.add(q); + disMaxQuery.add(applyBoost(mField, q)); } } if (!added) { @@ -710,8 +688,7 @@ protected Query getRegexpQuery(String field, String termStr) throws ParseExcepti for (String mField : fields) { Query q = getRegexpQuerySingle(mField, termStr); if (q != null) { - applyBoost(mField, q); - clauses.add(new BooleanClause(q, BooleanClause.Occur.SHOULD)); + clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD)); } } if (clauses.size() == 0) // happens for stopwords @@ -761,11 +738,12 @@ protected Query getBooleanQuery(List clauses, boolean disableCoor return fixNegativeQueryIfNeeded(q); } - private void applyBoost(String field, Query q) { + private Query applyBoost(String field, Query q) { Float fieldBoost = settings.fieldsAndWeights().get(field); - if (fieldBoost != null) { - q.setBoost(fieldBoost); + if (fieldBoost != null && fieldBoost != 1f) { + return new BoostQuery(q, fieldBoost); } + return q; } private Query applySlop(Query q, int slop) { @@ -779,7 +757,9 @@ private Query applySlop(Query q, int slop) { builder.add(terms[i], positions[i]); } pq = builder.build(); - pq.setBoost(q.getBoost()); + //make sure that the boost hasn't been set beforehand, otherwise we'd lose it + assert q.getBoost() == 1f; + assert q instanceof BoostQuery == false; return pq; } else if (q instanceof MultiPhraseQuery) { ((MultiPhraseQuery) q).setSlop(slop); diff --git a/core/src/main/java/org/apache/lucene/search/vectorhighlight/CustomFieldQuery.java b/core/src/main/java/org/apache/lucene/search/vectorhighlight/CustomFieldQuery.java index 97b5b71617982..95657de515877 100644 --- a/core/src/main/java/org/apache/lucene/search/vectorhighlight/CustomFieldQuery.java +++ b/core/src/main/java/org/apache/lucene/search/vectorhighlight/CustomFieldQuery.java @@ -22,11 +22,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.queries.BlendedTermQuery; -import org.apache.lucene.search.ConstantScoreQuery; -import org.apache.lucene.search.MultiPhraseQuery; -import org.apache.lucene.search.PhraseQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.*; import org.apache.lucene.search.spans.SpanTermQuery; import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery; import org.elasticsearch.common.lucene.search.function.FiltersFunctionScoreQuery; @@ -103,8 +99,7 @@ private void convertMultiPhraseQuery(int currentPos, int[] termsIdx, MultiPhrase for (int i = 0; i < termsIdx.length; i++) { queryBuilder.add(terms.get(i)[termsIdx[i]], pos[i]); } - PhraseQuery query = queryBuilder.build(); - query.setBoost(orig.getBoost()); + Query query = queryBuilder.build(); this.flatten(query, reader, flatQueries, orig.getBoost()); } else { Term[] t = terms.get(currentPos); diff --git a/core/src/main/java/org/elasticsearch/common/lucene/all/AllTermQuery.java b/core/src/main/java/org/elasticsearch/common/lucene/all/AllTermQuery.java index a59af2c7f51d4..7191c96e33e37 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/all/AllTermQuery.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/all/AllTermQuery.java @@ -64,8 +64,9 @@ public AllTermQuery(Term term) { @Override public Query rewrite(IndexReader reader) throws IOException { - if (getBoost() != 1f) { - return super.rewrite(reader); + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; } boolean fieldExists = false; boolean hasPayloads = false; @@ -80,14 +81,10 @@ public Query rewrite(IndexReader reader) throws IOException { } } if (fieldExists == false) { - Query rewritten = new MatchNoDocsQuery(); - rewritten.setBoost(getBoost()); - return rewritten; + return new MatchNoDocsQuery(); } if (hasPayloads == false) { - TermQuery rewritten = new TermQuery(term); - rewritten.setBoost(getBoost()); - return rewritten; + return new TermQuery(term); } return this; } diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/MoreLikeThisQuery.java b/core/src/main/java/org/elasticsearch/common/lucene/search/MoreLikeThisQuery.java index 410796497d5a7..8b1dcd9dfcfed 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/MoreLikeThisQuery.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/MoreLikeThisQuery.java @@ -35,10 +35,7 @@ import java.io.IOException; import java.io.Reader; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @@ -79,29 +76,17 @@ public MoreLikeThisQuery(String likeText, String[] moreLikeFields, Analyzer anal @Override public int hashCode() { - int result = boostTerms ? 1 : 0; - result = 31 * result + Float.floatToIntBits(boostTermsFactor); - result = 31 * result + Arrays.hashCode(likeText); - result = 31 * result + maxDocFreq; - result = 31 * result + maxQueryTerms; - result = 31 * result + maxWordLen; - result = 31 * result + minDocFreq; - result = 31 * result + minTermFrequency; - result = 31 * result + minWordLen; - result = 31 * result + Arrays.hashCode(moreLikeFields); - result = 31 * result + minimumShouldMatch.hashCode(); - result = 31 * result + (stopWords == null ? 0 : stopWords.hashCode()); - result = 31 * result + Float.floatToIntBits(getBoost()); - return result; + return Objects.hash(super.hashCode(), boostTerms, boostTermsFactor, Arrays.hashCode(likeText), + maxDocFreq, maxQueryTerms, maxWordLen, minDocFreq, minTermFrequency, minWordLen, + Arrays.hashCode(moreLikeFields), minimumShouldMatch, stopWords); } @Override public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) + if (super.equals(obj) == false) { return false; + } MoreLikeThisQuery other = (MoreLikeThisQuery) obj; - if (getBoost() != other.getBoost()) - return false; if (!analyzer.equals(other.analyzer)) return false; if (boostTerms != other.boostTerms) @@ -141,6 +126,10 @@ public boolean equals(Object obj) { @Override public Query rewrite(IndexReader reader) throws IOException { + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; + } XMoreLikeThis mlt = new XMoreLikeThis(reader, similarity == null ? new DefaultSimilarity() : similarity); mlt.setFieldNames(moreLikeFields); @@ -179,10 +168,7 @@ private Query createQuery(XMoreLikeThis mlt) throws IOException { mltQuery = Queries.applyMinimumShouldMatch((BooleanQuery) mltQuery, minimumShouldMatch); bqBuilder.add(mltQuery, BooleanClause.Occur.SHOULD); } - - BooleanQuery bq = bqBuilder.build(); - bq.setBoost(getBoost()); - return bq; + return bqBuilder.build(); } private void handleUnlike(XMoreLikeThis mlt, String[] unlikeText, Fields[] unlikeFields) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQuery.java b/core/src/main/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQuery.java index 3d870bc079479..662c329415130 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQuery.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQuery.java @@ -120,8 +120,9 @@ public int[] getPositions() { @Override public Query rewrite(IndexReader reader) throws IOException { - if (getBoost() != 1.0F) { - return super.rewrite(reader); + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; } if (termArrays.isEmpty()) { return new MatchNoDocsQuery(); @@ -145,7 +146,6 @@ public Query rewrite(IndexReader reader) throws IOException { return Queries.newMatchNoDocsQuery(); } query.add(terms.toArray(Term.class), position); - query.setBoost(getBoost()); return query.rewrite(reader); } @@ -233,10 +233,11 @@ public final String toString(String f) { */ @Override public boolean equals(Object o) { - if (!(o instanceof MultiPhrasePrefixQuery)) return false; + if (super.equals(o) == false) { + return false; + } MultiPhrasePrefixQuery other = (MultiPhrasePrefixQuery) o; - return this.getBoost() == other.getBoost() - && this.slop == other.slop + return this.slop == other.slop && termArraysEquals(this.termArrays, other.termArrays) && this.positions.equals(other.positions); } @@ -246,11 +247,10 @@ && termArraysEquals(this.termArrays, other.termArrays) */ @Override public int hashCode() { - return Float.floatToIntBits(getBoost()) + return super.hashCode() ^ slop ^ termArraysHashCode() - ^ positions.hashCode() - ^ 0x4AC65113; + ^ positions.hashCode(); } // Breakout calculation of the termArrays hashcode diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java b/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java index ad1f97eb9cb2f..b7f534d2124a8 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/Queries.java @@ -70,7 +70,7 @@ public static Query not(Query q) { .build(); } - public static boolean isNegativeQuery(Query q) { + private static boolean isNegativeQuery(Query q) { if (!(q instanceof BooleanQuery)) { return false; } @@ -107,7 +107,7 @@ public static boolean isConstantMatchAllQuery(Query query) { return false; } - public static BooleanQuery applyMinimumShouldMatch(BooleanQuery query, @Nullable String minimumShouldMatch) { + public static Query applyMinimumShouldMatch(BooleanQuery query, @Nullable String minimumShouldMatch) { if (minimumShouldMatch == null) { return query; } @@ -127,10 +127,13 @@ public static BooleanQuery applyMinimumShouldMatch(BooleanQuery query, @Nullable } builder.setMinimumNumberShouldMatch(msm); BooleanQuery bq = builder.build(); - bq.setBoost(query.getBoost()); - query = bq; + if (query.getBoost() != 1f) { + return new BoostQuery(bq, query.getBoost()); + } + return bq; + } else { + return query; } - return query; } private static Pattern spaceAroundLessThanPattern = Pattern.compile("(\\s+<\\s*)|(\\s*<\\s+)"); diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/XMoreLikeThis.java b/core/src/main/java/org/elasticsearch/common/lucene/search/XMoreLikeThis.java index 85e1899582c81..5315966008964 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/XMoreLikeThis.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/XMoreLikeThis.java @@ -670,14 +670,14 @@ private void addToQuery(PriorityQueue q, BooleanQuery query) { float bestScore = -1; while ((scoreTerm = q.pop()) != null) { - TermQuery tq = new TermQuery(new Term(scoreTerm.topField, scoreTerm.word)); + Query tq = new TermQuery(new Term(scoreTerm.topField, scoreTerm.word)); if (boost) { if (bestScore == -1) { bestScore = (scoreTerm.score); } float myScore = (scoreTerm.score); - tq.setBoost(boostFactor * myScore / bestScore); + tq = new BoostQuery(tq, boostFactor * myScore / bestScore); } try { diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java index 210b32d5e42bd..3da5ae0e4ab31 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java @@ -123,8 +123,9 @@ public FilterFunction[] getFilterFunctions() { @Override public Query rewrite(IndexReader reader) throws IOException { - if (getBoost() != 1.0F) { - return super.rewrite(reader); + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; } Query newQ = subQuery.rewrite(reader); if (newQ == subQuery) diff --git a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FunctionScoreQuery.java b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FunctionScoreQuery.java index 907d66957aca2..972fb794fb508 100644 --- a/core/src/main/java/org/elasticsearch/common/lucene/search/function/FunctionScoreQuery.java +++ b/core/src/main/java/org/elasticsearch/common/lucene/search/function/FunctionScoreQuery.java @@ -71,8 +71,9 @@ public ScoreFunction getFunction() { @Override public Query rewrite(IndexReader reader) throws IOException { - if (getBoost() != 1.0F) { - return super.rewrite(reader); + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; } Query newQ = subQuery.rewrite(reader); if (newQ == subQuery) { diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java index 686cfcfe6e26c..27b96b27a44e7 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java @@ -219,8 +219,9 @@ public LateParsingQuery(Object lowerTerm, Object upperTerm, boolean includeLower @Override public Query rewrite(IndexReader reader) throws IOException { - if (getBoost() != 1.0F) { - return super.rewrite(reader); + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; } return innerRangeQuery(lowerTerm, upperTerm, includeLower, includeUpper, timeZone, forcedDateParser); } @@ -229,11 +230,9 @@ public Query rewrite(IndexReader reader) throws IOException { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; LateParsingQuery that = (LateParsingQuery) o; - if (includeLower != that.includeLower) return false; if (includeUpper != that.includeUpper) return false; if (lowerTerm != null ? !lowerTerm.equals(that.lowerTerm) : that.lowerTerm != null) return false; @@ -245,13 +244,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (lowerTerm != null ? lowerTerm.hashCode() : 0); - result = 31 * result + (upperTerm != null ? upperTerm.hashCode() : 0); - result = 31 * result + (includeLower ? 1 : 0); - result = 31 * result + (includeUpper ? 1 : 0); - result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0); - return result; + return Objects.hash(super.hashCode(), lowerTerm, upperTerm, includeLower, includeUpper, timeZone); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/AbstractQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/AbstractQueryBuilder.java index 560476a69d8fb..1f92f53ec07b6 100644 --- a/core/src/main/java/org/elasticsearch/index/query/AbstractQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/AbstractQueryBuilder.java @@ -19,7 +19,10 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.spans.SpanBoostQuery; +import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.util.BytesRef; import org.elasticsearch.action.support.ToXContentToBytes; import org.elasticsearch.common.ParseField; @@ -74,7 +77,13 @@ protected void printBoostAndQueryName(XContentBuilder builder) throws IOExceptio public final Query toQuery(QueryShardContext context) throws IOException { Query query = doToQuery(context); if (query != null) { - setFinalBoost(query); + if (boost != DEFAULT_BOOST) { + if (query instanceof SpanQuery) { + query = new SpanBoostQuery((SpanQuery) query, boost); + } else { + query = new BoostQuery(query, boost); + } + } if (queryName != null) { context.addNamedQuery(queryName, query); } @@ -82,20 +91,6 @@ public final Query toQuery(QueryShardContext context) throws IOException { return query; } - /** - * Sets the main boost to the query obtained by converting the current query into a lucene query. - * The default behaviour is to set the main boost, after verifying that we are not overriding any non default boost - * value that was previously set to the lucene query. That case would require some manual decision on how to combine - * the main boost with the boost coming from lucene by overriding this method. - * @throws IllegalStateException if the lucene query boost has already been set - */ - protected void setFinalBoost(Query query) { - if (query.getBoost() != AbstractQueryBuilder.DEFAULT_BOOST) { - throw new IllegalStateException("lucene query boost is already set, override setFinalBoost to define how to combine lucene boost with main boost"); - } - query.setBoost(boost); - } - @Override public final Query toFilter(QueryShardContext context) throws IOException { Query result = null; diff --git a/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java index 43b23778d5677..9ed1623f66a99 100644 --- a/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java @@ -279,8 +279,8 @@ protected Query doToQuery(QueryShardContext context) throws IOException { } else { minimumShouldMatch = this.minimumShouldMatch; } - booleanQuery = Queries.applyMinimumShouldMatch(booleanQuery, minimumShouldMatch); - return adjustPureNegative ? fixNegativeQueryIfNeeded(booleanQuery) : booleanQuery; + Query query = Queries.applyMinimumShouldMatch(booleanQuery, minimumShouldMatch); + return adjustPureNegative ? fixNegativeQueryIfNeeded(query) : query; } private static void addBooleanClauses(QueryShardContext context, BooleanQuery.Builder booleanQueryBuilder, List clauses, Occur occurs) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java index f07fba8234beb..a78cb6c4fd766 100644 --- a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java @@ -215,8 +215,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException { if (innerQuery == null) { return null; } - innerQuery.setBoost(boost); - DocumentMapper childDocMapper = context.getMapperService().documentMapper(type); if (childDocMapper == null) { throw new QueryShardException(context, "[" + NAME + "] no mapping found for type [" + type + "]"); @@ -286,8 +284,9 @@ final static class LateParsingQuery extends Query { @Override public Query rewrite(IndexReader reader) throws IOException { - if (getBoost() != 1.0F) { - return super.rewrite(reader); + Query rewritten = super.rewrite(reader); + if (rewritten != this) { + return rewritten; } if (reader instanceof DirectoryReader) { String joinField = ParentFieldMapper.joinField(parentType); @@ -310,8 +309,6 @@ public Query rewrite(IndexReader reader) throws IOException { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; LateParsingQuery that = (LateParsingQuery) o; @@ -326,14 +323,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = super.hashCode(); - result = 31 * result + toQuery.hashCode(); - result = 31 * result + innerQuery.hashCode(); - result = 31 * result + minChildren; - result = 31 * result + maxChildren; - result = 31 * result + parentType.hashCode(); - result = 31 * result + scoreMode.hashCode(); - return result; + return Objects.hash(super.hashCode(), toQuery, innerQuery, minChildren, maxChildren, parentType, scoreMode); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java index d23fc6d06aa6b..5ac64163dd9ad 100644 --- a/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java @@ -129,7 +129,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException { if (innerQuery == null) { return null; } - innerQuery.setBoost(boost); DocumentMapper parentDocMapper = context.getMapperService().documentMapper(type); if (parentDocMapper == null) { throw new QueryShardException(context, "[has_parent] query configured 'parent_type' [" + type diff --git a/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java index b4c7b53a99ee0..1445823ac47b0 100644 --- a/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java @@ -115,14 +115,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException { return noMatchQuery.toQuery(context); } - @Override - protected void setFinalBoost(Query query) { - if (boost != DEFAULT_BOOST) { - //if both the wrapped query and the wrapper hold a boost, the main one coming from the wrapper wins - query.setBoost(boost); - } - } - @Override protected IndicesQueryBuilder doReadFrom(StreamInput in) throws IOException { IndicesQueryBuilder indicesQueryBuilder = new IndicesQueryBuilder(in.readQuery(), in.readStringArray()); diff --git a/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java index 84449d204688b..e66c1cf3dfde0 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java @@ -301,8 +301,7 @@ public MatchQueryBuilder zeroTermsQuery(MatchQuery.ZeroTermsQuery zeroTermsQuery } /** - * Get the setting for handling zero terms queries. - * @see #zeroTermsQuery(ZeroTermsQuery) + * Returns the setting for handling zero terms queries. */ public MatchQuery.ZeroTermsQuery zeroTermsQuery() { return this.zeroTermsQuery; diff --git a/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java index 57e00a2dc2bcb..be05333a8eb44 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java @@ -548,12 +548,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException { return query; } - @Override - protected void setFinalBoost(Query query) { - // we need to preserve the boost that came out of the parsing phase - query.setBoost(boost * query.getBoost()); - } - private static Map handleFieldsMatchPattern(MapperService mapperService, Map fieldsBoosts) { Map newFieldsBoosts = new TreeMap<>(); for (Map.Entry fieldBoost : fieldsBoosts.entrySet()) { diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java index d0aa8dff9a04c..393ff1e59a777 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java @@ -22,6 +22,7 @@ import org.apache.lucene.queryparser.classic.MapperQueryParser; import org.apache.lucene.queryparser.classic.QueryParserSettings; import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.automaton.Operations; @@ -36,10 +37,7 @@ import org.joda.time.DateTimeZone; import java.io.IOException; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; +import java.util.*; /** * A query that parses a query string and runs it. There are two modes that this operates. The first, @@ -722,16 +720,25 @@ protected Query doToQuery(QueryShardContext context) throws IOException { if (query == null) { return null; } + + //save the BoostQuery wrapped structure if present + List boosts = new ArrayList<>(); + while(query instanceof BoostQuery) { + BoostQuery boostQuery = (BoostQuery) query; + boosts.add(boostQuery.getBoost()); + query = boostQuery.getQuery(); + } + query = Queries.fixNegativeQueryIfNeeded(query); if (query instanceof BooleanQuery) { query = Queries.applyMinimumShouldMatch((BooleanQuery) query, this.minimumShouldMatch()); } - return query; - } - @Override - protected void setFinalBoost(Query query) { - //we need to preserve the boost that came out of the parsing phase - query.setBoost(query.getBoost() * boost); + //restore the previous BoostQuery wrapping + for (int i = boosts.size() - 1; i >= 0; i--) { + query = new BoostQuery(query, boosts.get(i)); + } + + return query; } } diff --git a/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java index 10407a2ba5f42..f69ac8c054829 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java @@ -104,10 +104,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Objects.hashCode(script); - return result; + return Objects.hash(super.hashCode(), script); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SimpleQueryParser.java b/core/src/main/java/org/elasticsearch/index/query/SimpleQueryParser.java index f8b0deaf9be18..7627644e750af 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SimpleQueryParser.java +++ b/core/src/main/java/org/elasticsearch/index/query/SimpleQueryParser.java @@ -63,8 +63,7 @@ public Query newDefaultQuery(String text) { try { Query q = createBooleanQuery(entry.getKey(), text, super.getDefaultOperator()); if (q != null) { - q.setBoost(entry.getValue()); - bq.add(q, BooleanClause.Occur.SHOULD); + bq.add(wrapWithBoost(q, entry.getValue()), BooleanClause.Occur.SHOULD); } } catch (RuntimeException e) { rethrowUnlessLenient(e); @@ -86,9 +85,8 @@ public Query newFuzzyQuery(String text, int fuzziness) { bq.setDisableCoord(true); for (Map.Entry entry : weights.entrySet()) { try { - Query q = new FuzzyQuery(new Term(entry.getKey(), text), fuzziness); - q.setBoost(entry.getValue()); - bq.add(q, BooleanClause.Occur.SHOULD); + Query query = new FuzzyQuery(new Term(entry.getKey(), text), fuzziness); + bq.add(wrapWithBoost(query, entry.getValue()), BooleanClause.Occur.SHOULD); } catch (RuntimeException e) { rethrowUnlessLenient(e); } @@ -104,8 +102,7 @@ public Query newPhraseQuery(String text, int slop) { try { Query q = createPhraseQuery(entry.getKey(), text, slop); if (q != null) { - q.setBoost(entry.getValue()); - bq.add(q, BooleanClause.Occur.SHOULD); + bq.add(wrapWithBoost(q, entry.getValue()), BooleanClause.Occur.SHOULD); } } catch (RuntimeException e) { rethrowUnlessLenient(e); @@ -129,12 +126,12 @@ public Query newPrefixQuery(String text) { try { if (settings.analyzeWildcard()) { Query analyzedQuery = newPossiblyAnalyzedQuery(entry.getKey(), text); - analyzedQuery.setBoost(entry.getValue()); - bq.add(analyzedQuery, BooleanClause.Occur.SHOULD); + if (analyzedQuery != null) { + bq.add(wrapWithBoost(analyzedQuery, entry.getValue()), BooleanClause.Occur.SHOULD); + } } else { - PrefixQuery prefix = new PrefixQuery(new Term(entry.getKey(), text)); - prefix.setBoost(entry.getValue()); - bq.add(prefix, BooleanClause.Occur.SHOULD); + Query query = new PrefixQuery(new Term(entry.getKey(), text)); + bq.add(wrapWithBoost(query, entry.getValue()), BooleanClause.Occur.SHOULD); } } catch (RuntimeException e) { return rethrowUnlessLenient(e); @@ -143,6 +140,13 @@ public Query newPrefixQuery(String text) { return super.simplify(bq.build()); } + private static Query wrapWithBoost(Query query, float boost) { + if (boost != AbstractQueryBuilder.DEFAULT_BOOST) { + return new BoostQuery(query, boost); + } + return query; + } + /** * Analyze the given string using its analyzer, constructing either a * {@code PrefixQuery} or a {@code BooleanQuery} made up diff --git a/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java index 78d3bffd228fc..29720195c8365 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java @@ -299,11 +299,6 @@ private static String resolveIndexName(String fieldName, QueryShardContext conte return fieldName; } - @Override - protected void setFinalBoost(Query query) { - query.setBoost(boost * query.getBoost()); - } - @Override protected void doXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(NAME); diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java index eac2e6a0a7a99..1d7a5c7e412f0 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java @@ -18,9 +18,12 @@ */ package org.elasticsearch.index.query; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.spans.SpanBoostQuery; import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; +import org.apache.lucene.search.spans.SpanQuery; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -62,11 +65,23 @@ protected void doXContent(XContentBuilder builder, Params params) @Override protected Query doToQuery(QueryShardContext context) throws IOException { Query subQuery = multiTermQueryBuilder.toQuery(context); + float boost = AbstractQueryBuilder.DEFAULT_BOOST; + if (subQuery instanceof BoostQuery) { + BoostQuery boostQuery = (BoostQuery) subQuery; + subQuery = boostQuery.getQuery(); + boost = boostQuery.getBoost(); + } + //no MultiTermQuery extends SpanQuery, so SpanBoostQuery is not supported here + assert subQuery instanceof SpanBoostQuery == false; if (subQuery instanceof MultiTermQuery == false) { throw new UnsupportedOperationException("unsupported inner query, should be " + MultiTermQuery.class.getName() +" but was " + subQuery.getClass().getName()); } - return new SpanMultiTermQueryWrapper<>((MultiTermQuery) subQuery); + SpanQuery wrapper = new SpanMultiTermQueryWrapper<>((MultiTermQuery) subQuery); + if (boost != AbstractQueryBuilder.DEFAULT_BOOST) { + wrapper = new SpanBoostQuery(wrapper, boost); + } + return wrapper; } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java index 2cecc4e2b0dfd..59ff19748af5d 100644 --- a/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java @@ -110,11 +110,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException { } } - @Override - protected void setFinalBoost(Query query) { - //no-op this query doesn't support boost - } - @Override protected TemplateQueryBuilder doReadFrom(StreamInput in) throws IOException { TemplateQueryBuilder templateQueryBuilder = new TemplateQueryBuilder(Template.readTemplate(in)); diff --git a/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java index 8ba8431f0b6e7..e87b17831d192 100644 --- a/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java @@ -115,11 +115,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException { } } - @Override - protected void setFinalBoost(Query query) { - //no-op this query doesn't support boost - } - @Override protected WrapperQueryBuilder doReadFrom(StreamInput in) throws IOException { return new WrapperQueryBuilder(in.readByteArray()); diff --git a/core/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java b/core/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java index 5fb2db0aa109a..02b3c9ad1ac7a 100644 --- a/core/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java +++ b/core/src/main/java/org/elasticsearch/index/search/MultiMatchQuery.java @@ -22,14 +22,12 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.Term; import org.apache.lucene.queries.BlendedTermQuery; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.DisjunctionMaxQuery; -import org.apache.lucene.search.Query; +import org.apache.lucene.search.*; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.query.AbstractQueryBuilder; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import org.elasticsearch.index.query.QueryShardContext; @@ -56,8 +54,8 @@ private Query parseAndApply(Type type, String fieldName, Object value, String mi if (query instanceof BooleanQuery) { query = Queries.applyMinimumShouldMatch((BooleanQuery) query, minimumShouldMatch); } - if (boostValue != null && query != null) { - query.setBoost(boostValue); + if (query != null && boostValue != null && boostValue != AbstractQueryBuilder.DEFAULT_BOOST) { + query = new BoostQuery(query, boostValue); } return query; } @@ -167,13 +165,13 @@ public List buildGroupedQueries(MultiMatchQueryBuilder.Type type, Map()); + groups.put(actualAnalyzer, new ArrayList<>()); } Float boost = entry.getValue(); boost = boost == null ? Float.valueOf(1.0f) : boost; groups.get(actualAnalyzer).add(new FieldAndFieldType(name, fieldType, boost)); } else { - missing.add(new Tuple(name, entry.getValue())); + missing.add(new Tuple<>(name, entry.getValue())); } } diff --git a/core/src/main/java/org/elasticsearch/index/search/geo/InMemoryGeoBoundingBoxQuery.java b/core/src/main/java/org/elasticsearch/index/search/geo/InMemoryGeoBoundingBoxQuery.java index 8d7dba292f468..a2e9e1b689db9 100644 --- a/core/src/main/java/org/elasticsearch/index/search/geo/InMemoryGeoBoundingBoxQuery.java +++ b/core/src/main/java/org/elasticsearch/index/search/geo/InMemoryGeoBoundingBoxQuery.java @@ -30,6 +30,7 @@ import org.elasticsearch.index.fielddata.MultiGeoPointValues; import java.io.IOException; +import java.util.Objects; /** * @@ -94,11 +95,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - int h = super.hashCode(); - h = 31 * h + fieldName().hashCode(); - h = 31 * h + topLeft.hashCode(); - h = 31 * h + bottomRight.hashCode(); - return h; + return Objects.hash(super.hashCode(), fieldName(), topLeft, bottomRight); } private static class Meridian180GeoBoundingBoxBits implements Bits { diff --git a/core/src/main/java/org/elasticsearch/index/search/nested/IncludeNestedDocsQuery.java b/core/src/main/java/org/elasticsearch/index/search/nested/IncludeNestedDocsQuery.java deleted file mode 100644 index e3631269fbec4..0000000000000 --- a/core/src/main/java/org/elasticsearch/index/search/nested/IncludeNestedDocsQuery.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.index.search.nested; - -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; -import org.apache.lucene.search.DocIdSetIterator; -import org.apache.lucene.search.Explanation; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.Scorer; -import org.apache.lucene.search.Weight; -import org.apache.lucene.search.join.BitSetProducer; -import org.apache.lucene.util.BitSet; - -import java.io.IOException; -import java.util.Collection; -import java.util.Set; - -/** - * A special query that accepts a top level parent matching query, and returns the nested docs of the matching parent - * doc as well. This is handy when deleting by query, don't use it for other purposes. - * - * @elasticsearch.internal - */ -public class IncludeNestedDocsQuery extends Query { - - private final BitSetProducer parentFilter; - private final Query parentQuery; - - // If we are rewritten, this is the original childQuery we - // were passed; we use this for .equals() and - // .hashCode(). This makes rewritten query equal the - // original, so that user does not have to .rewrite() their - // query before searching: - private final Query origParentQuery; - - - public IncludeNestedDocsQuery(Query parentQuery, BitSetProducer parentFilter) { - this.origParentQuery = parentQuery; - this.parentQuery = parentQuery; - this.parentFilter = parentFilter; - } - - // For rewriting - IncludeNestedDocsQuery(Query rewrite, Query originalQuery, IncludeNestedDocsQuery previousInstance) { - this.origParentQuery = originalQuery; - this.parentQuery = rewrite; - this.parentFilter = previousInstance.parentFilter; - setBoost(previousInstance.getBoost()); - } - - // For cloning - IncludeNestedDocsQuery(Query originalQuery, IncludeNestedDocsQuery previousInstance) { - this.origParentQuery = originalQuery; - this.parentQuery = originalQuery; - this.parentFilter = previousInstance.parentFilter; - } - - @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException { - return new IncludeNestedDocsWeight(this, parentQuery, parentQuery.createWeight(searcher, needsScores), parentFilter); - } - - static class IncludeNestedDocsWeight extends Weight { - - private final Query parentQuery; - private final Weight parentWeight; - private final BitSetProducer parentsFilter; - - IncludeNestedDocsWeight(Query query, Query parentQuery, Weight parentWeight, BitSetProducer parentsFilter) { - super(query); - this.parentQuery = parentQuery; - this.parentWeight = parentWeight; - this.parentsFilter = parentsFilter; - } - - @Override - public void extractTerms(Set terms) { - parentWeight.extractTerms(terms); - } - - @Override - public void normalize(float norm, float topLevelBoost) { - parentWeight.normalize(norm, topLevelBoost); - } - - @Override - public float getValueForNormalization() throws IOException { - return parentWeight.getValueForNormalization(); // this query is never boosted so just delegate... - } - - @Override - public Scorer scorer(LeafReaderContext context) throws IOException { - final Scorer parentScorer = parentWeight.scorer(context); - - // no matches - if (parentScorer == null) { - return null; - } - - BitSet parents = parentsFilter.getBitSet(context); - if (parents == null) { - // No matches - return null; - } - - int firstParentDoc = parentScorer.nextDoc(); - if (firstParentDoc == DocIdSetIterator.NO_MORE_DOCS) { - // No matches - return null; - } - return new IncludeNestedDocsScorer(this, parentScorer, parents, firstParentDoc); - } - - @Override - public Explanation explain(LeafReaderContext context, int doc) throws IOException { - return null; //Query is used internally and not by users, so explain can be empty - } - } - - static class IncludeNestedDocsScorer extends Scorer { - - final Scorer parentScorer; - final BitSet parentBits; - - int currentChildPointer = -1; - int currentParentPointer = -1; - int currentDoc = -1; - - IncludeNestedDocsScorer(Weight weight, Scorer parentScorer, BitSet parentBits, int currentParentPointer) { - super(weight); - this.parentScorer = parentScorer; - this.parentBits = parentBits; - this.currentParentPointer = currentParentPointer; - if (currentParentPointer == 0) { - currentChildPointer = 0; - } else { - this.currentChildPointer = this.parentBits.prevSetBit(currentParentPointer - 1); - if (currentChildPointer == -1) { - // no previous set parent, we delete from doc 0 - currentChildPointer = 0; - } else { - currentChildPointer++; // we only care about children - } - } - - currentDoc = currentChildPointer; - } - - @Override - public Collection getChildren() { - return parentScorer.getChildren(); - } - - @Override - public int nextDoc() throws IOException { - if (currentParentPointer == NO_MORE_DOCS) { - return (currentDoc = NO_MORE_DOCS); - } - - if (currentChildPointer == currentParentPointer) { - // we need to return the current parent as well, but prepare to return - // the next set of children - currentDoc = currentParentPointer; - currentParentPointer = parentScorer.nextDoc(); - if (currentParentPointer != NO_MORE_DOCS) { - currentChildPointer = parentBits.prevSetBit(currentParentPointer - 1); - if (currentChildPointer == -1) { - // no previous set parent, just set the child to the current parent - currentChildPointer = currentParentPointer; - } else { - currentChildPointer++; // we only care about children - } - } - } else { - currentDoc = currentChildPointer++; - } - - assert currentDoc != -1; - return currentDoc; - } - - @Override - public int advance(int target) throws IOException { - if (target == NO_MORE_DOCS) { - return (currentDoc = NO_MORE_DOCS); - } - - if (target == 0) { - return nextDoc(); - } - - if (target < currentParentPointer) { - currentDoc = currentParentPointer = parentScorer.advance(target); - if (currentParentPointer == NO_MORE_DOCS) { - return (currentDoc = NO_MORE_DOCS); - } - if (currentParentPointer == 0) { - currentChildPointer = 0; - } else { - currentChildPointer = parentBits.prevSetBit(currentParentPointer - 1); - if (currentChildPointer == -1) { - // no previous set parent, just set the child to 0 to delete all up to the parent - currentChildPointer = 0; - } else { - currentChildPointer++; // we only care about children - } - } - } else { - currentDoc = currentChildPointer++; - } - - return currentDoc; - } - - @Override - public float score() throws IOException { - return parentScorer.score(); - } - - @Override - public int freq() throws IOException { - return parentScorer.freq(); - } - - @Override - public int docID() { - return currentDoc; - } - - @Override - public long cost() { - return parentScorer.cost(); - } - } - - @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query parentRewrite = parentQuery.rewrite(reader); - if (parentRewrite != parentQuery) { - return new IncludeNestedDocsQuery(parentRewrite, parentQuery, this); - } else { - return this; - } - } - - @Override - public String toString(String field) { - return "IncludeNestedDocsQuery (" + parentQuery.toString() + ")"; - } - - @Override - public boolean equals(Object _other) { - if (_other instanceof IncludeNestedDocsQuery) { - final IncludeNestedDocsQuery other = (IncludeNestedDocsQuery) _other; - return origParentQuery.equals(other.origParentQuery) && parentFilter.equals(other.parentFilter); - } else { - return false; - } - } - - @Override - public int hashCode() { - final int prime = 31; - int hash = 1; - hash = prime * hash + origParentQuery.hashCode(); - hash = prime * hash + parentFilter.hashCode(); - return hash; - } - - @Override - public Query clone() { - Query clonedQuery = origParentQuery.clone(); - return new IncludeNestedDocsQuery(clonedQuery, this); - } -} diff --git a/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java b/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java index e69ca5a3fce67..1174fcdd8a982 100644 --- a/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java +++ b/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java @@ -41,6 +41,7 @@ import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.object.ObjectMapper; +import org.elasticsearch.index.query.AbstractQueryBuilder; import org.elasticsearch.index.query.ParsedQuery; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.similarity.SimilarityService; @@ -196,14 +197,16 @@ public void preProcess() { if (query() == null) { parsedQuery(ParsedQuery.parsedMatchAllQuery()); } - if (queryBoost() != 1.0f) { + if (queryBoost() != AbstractQueryBuilder.DEFAULT_BOOST) { parsedQuery(new ParsedQuery(new FunctionScoreQuery(query(), new WeightFactorFunction(queryBoost)), parsedQuery())); } Query searchFilter = searchFilter(types()); if (searchFilter != null) { if (Queries.isConstantMatchAllQuery(query())) { Query q = new ConstantScoreQuery(searchFilter); - q.setBoost(query().getBoost()); + if (query().getBoost() != AbstractQueryBuilder.DEFAULT_BOOST) { + q = new BoostQuery(q, query().getBoost()); + } parsedQuery(new ParsedQuery(q, parsedQuery())); } else { BooleanQuery filtered = new BooleanQuery.Builder() diff --git a/core/src/test/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQueryTests.java b/core/src/test/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQueryTests.java index 5cb80607115d0..9098289847ea2 100644 --- a/core/src/test/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQueryTests.java +++ b/core/src/test/java/org/elasticsearch/common/lucene/search/MultiPhrasePrefixQueryTests.java @@ -27,6 +27,7 @@ import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.Term; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.store.RAMDirectory; @@ -34,6 +35,7 @@ import org.elasticsearch.test.ESTestCase; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; public class MultiPhrasePrefixQueryTests extends ESTestCase { public void testSimple() throws Exception { @@ -78,6 +80,8 @@ public void testBoost() throws Exception { multiPhrasePrefixQuery.add(new Term[]{new Term("field", "aaa"), new Term("field", "bb")}); multiPhrasePrefixQuery.setBoost(randomFloat()); Query query = multiPhrasePrefixQuery.rewrite(reader); - assertThat(query.getBoost(), equalTo(multiPhrasePrefixQuery.getBoost())); + assertThat(query, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(multiPhrasePrefixQuery.getBoost())); } } \ No newline at end of file diff --git a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java index f38199648939b..3df3b9c3b18aa 100644 --- a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java +++ b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java @@ -23,8 +23,12 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.io.JsonStringEncoder; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.Accountable; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.spans.SpanBoostQuery; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; @@ -104,9 +108,7 @@ import java.util.*; import java.util.concurrent.ExecutionException; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.*; public abstract class AbstractQueryTestCase> extends ESTestCase { @@ -501,26 +503,45 @@ protected final void assertLuceneQuery(QB queryBuilder, Query query, QueryShardC assertThat(namedQuery, equalTo(query)); } if (query != null) { - assertBoost(queryBuilder, query); + if (queryBuilder.boost() != AbstractQueryBuilder.DEFAULT_BOOST) { + assertThat(query, either(instanceOf(BoostQuery.class)).or(instanceOf(SpanBoostQuery.class))); + if (query instanceof SpanBoostQuery) { + SpanBoostQuery spanBoostQuery = (SpanBoostQuery) query; + assertThat(spanBoostQuery.getBoost(), equalTo(queryBuilder.boost())); + query = spanBoostQuery.getQuery(); + } else { + BoostQuery boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(queryBuilder.boost())); + query = boostQuery.getQuery(); + } + } } doAssertLuceneQuery(queryBuilder, query, context); } - /** - * Allows to override boost assertions for queries that don't have the default behaviour - */ - protected void assertBoost(QB queryBuilder, Query query) throws IOException { - // workaround https://bugs.openjdk.java.net/browse/JDK-8056984 - float boost = queryBuilder.boost(); - assertThat(query.getBoost(), equalTo(boost)); - } - /** * Checks the result of {@link QueryBuilder#toQuery(QueryShardContext)} given the original {@link QueryBuilder} and {@link QueryShardContext}. * Contains the query specific checks to be implemented by subclasses. */ protected abstract void doAssertLuceneQuery(QB queryBuilder, Query query, QueryShardContext context) throws IOException; + protected static void assertTermOrBoostQuery(Query query, String field, String value, float fieldBoost) { + if (fieldBoost != AbstractQueryBuilder.DEFAULT_BOOST) { + assertThat(query, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(fieldBoost)); + query = boostQuery.getQuery(); + } + assertTermQuery(query, field, value); + } + + protected static void assertTermQuery(Query query, String field, String value) { + assertThat(query, instanceOf(TermQuery.class)); + TermQuery termQuery = (TermQuery) query; + assertThat(termQuery.getTerm().field(), equalTo(field)); + assertThat(termQuery.getTerm().text().toLowerCase(Locale.ROOT), equalTo(value.toLowerCase(Locale.ROOT))); + } + /** * Test serialization and deserialization of the test query. */ diff --git a/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java index 3c6efd493582d..4a523f6add731 100644 --- a/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java @@ -20,21 +20,16 @@ package org.elasticsearch.index.query; import org.apache.lucene.index.Term; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.DisjunctionMaxQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.Matchers.closeTo; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.*; public class DisMaxQueryBuilderTests extends AbstractQueryTestCase { /** @@ -138,9 +133,13 @@ public void testToQueryInnerPrefixQuery() throws Exception { List disjuncts = disjunctionMaxQuery.getDisjuncts(); assertThat(disjuncts.size(), equalTo(1)); - PrefixQuery firstQ = (PrefixQuery) disjuncts.get(0); + assertThat(disjuncts.get(0), instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) disjuncts.get(0); + assertThat((double) boostQuery.getBoost(), closeTo(1.2, 0.00001)); + assertThat(boostQuery.getQuery(), instanceOf(PrefixQuery.class)); + PrefixQuery firstQ = (PrefixQuery) boostQuery.getQuery(); // since age is automatically registered in data, we encode it as numeric assertThat(firstQ.getPrefix(), equalTo(new Term(STRING_FIELD_NAME, "sh"))); - assertThat((double) firstQ.getBoost(), closeTo(1.2, 0.00001)); + } } diff --git a/core/src/test/java/org/elasticsearch/index/query/FuzzyQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/FuzzyQueryBuilderTests.java index c7787860c011e..f1511bc3909b7 100644 --- a/core/src/test/java/org/elasticsearch/index/query/FuzzyQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/FuzzyQueryBuilderTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.index.query; import org.apache.lucene.index.Term; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.Query; @@ -116,12 +117,15 @@ public void testToQueryWithStringField() throws IOException { " }\n" + "}"; Query parsedQuery = parseQuery(query).toQuery(createShardContext()); - assertThat(parsedQuery, instanceOf(FuzzyQuery.class)); - FuzzyQuery fuzzyQuery = (FuzzyQuery) parsedQuery; + assertThat(parsedQuery, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) parsedQuery; + assertThat(boostQuery.getBoost(), equalTo(2.0f)); + assertThat(boostQuery.getQuery(), instanceOf(FuzzyQuery.class)); + FuzzyQuery fuzzyQuery = (FuzzyQuery) boostQuery.getQuery(); assertThat(fuzzyQuery.getTerm(), equalTo(new Term(STRING_FIELD_NAME, "sh"))); assertThat(fuzzyQuery.getMaxEdits(), equalTo(Fuzziness.AUTO.asDistance("sh"))); assertThat(fuzzyQuery.getPrefixLength(), equalTo(1)); - assertThat(fuzzyQuery.getBoost(), equalTo(2.0f)); + } public void testToQueryWithNumericField() throws IOException { @@ -130,8 +134,7 @@ public void testToQueryWithNumericField() throws IOException { " \"fuzzy\":{\n" + " \"" + INT_FIELD_NAME + "\":{\n" + " \"value\":12,\n" + - " \"fuzziness\":5,\n" + - " \"boost\":2.0\n" + + " \"fuzziness\":5\n" + " }\n" + " }\n" + "}\n"; diff --git a/core/src/test/java/org/elasticsearch/index/query/IndicesQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/IndicesQueryBuilderTests.java index 6be5cce953c31..6b7318d72739b 100644 --- a/core/src/test/java/org/elasticsearch/index/query/IndicesQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/IndicesQueryBuilderTests.java @@ -56,15 +56,7 @@ protected void doAssertLuceneQuery(IndicesQueryBuilder queryBuilder, Query query } else { expected = queryBuilder.noMatchQuery().toQuery(context); } - if (expected != null && queryBuilder.boost() != AbstractQueryBuilder.DEFAULT_BOOST) { - expected.setBoost(queryBuilder.boost()); - } - assertEquals(query, expected); - } - - @Override - protected void assertBoost(IndicesQueryBuilder queryBuilder, Query query) throws IOException { - //nothing to do here, boost check is already included in equality check done as part of doAssertLuceneQuery above + assertEquals(expected, query); } public void testIllegalArguments() { diff --git a/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java index 45b508b1517d6..6dc44b73d5b19 100644 --- a/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java @@ -20,13 +20,7 @@ package org.elasticsearch.index.query; import org.apache.lucene.queries.ExtendedCommonTermsQuery; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.FuzzyQuery; -import org.apache.lucene.search.MatchAllDocsQuery; -import org.apache.lucene.search.PhraseQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.*; import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.index.mapper.MappedFieldType; @@ -50,12 +44,12 @@ protected MatchQueryBuilder doCreateTestQueryBuilder() { if (fieldName.equals(DATE_FIELD_NAME)) { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); } - Object value = ""; + Object value; if (fieldName.equals(STRING_FIELD_NAME)) { int terms = randomIntBetween(0, 3); StringBuilder builder = new StringBuilder(); for (int i = 0; i < terms; i++) { - builder.append(randomAsciiOfLengthBetween(1, 10) + " "); + builder.append(randomAsciiOfLengthBetween(1, 10)).append(" "); } value = builder.toString().trim(); } else { @@ -139,8 +133,6 @@ protected void doAssertLuceneQuery(MatchQueryBuilder queryBuilder, Query query, queryValue = queryValue.toLowerCase(Locale.ROOT); } Query expectedTermQuery = fieldType.termQuery(queryValue, context); - // the real query will have boost applied, so we set it to our expeced as well - expectedTermQuery.setBoost(queryBuilder.boost()); assertEquals(expectedTermQuery, query); } @@ -174,7 +166,7 @@ protected void doAssertLuceneQuery(MatchQueryBuilder queryBuilder, Query query, // depending on analyzer being set or not we can have term lowercased along the way, so to simplify test we just // compare lowercased terms here String originalTermLc = queryBuilder.value().toString().toLowerCase(Locale.ROOT); - String actualTermLc = fuzzyQuery.getTerm().text().toString().toLowerCase(Locale.ROOT); + String actualTermLc = fuzzyQuery.getTerm().text().toLowerCase(Locale.ROOT); assertThat(actualTermLc, equalTo(originalTermLc)); assertThat(queryBuilder.prefixLength(), equalTo(fuzzyQuery.getPrefixLength())); assertThat(queryBuilder.fuzzyTranspositions(), equalTo(fuzzyQuery.getTranspositions())); diff --git a/core/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java index 796ac225c999c..9cf590a3cddc0 100644 --- a/core/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java @@ -21,14 +21,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.queries.ExtendedCommonTermsQuery; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.DisjunctionMaxQuery; -import org.apache.lucene.search.FuzzyQuery; -import org.apache.lucene.search.MatchAllDocsQuery; -import org.apache.lucene.search.MatchNoDocsQuery; -import org.apache.lucene.search.PhraseQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.*; import org.elasticsearch.common.lucene.all.AllTermQuery; import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery; import org.elasticsearch.index.search.MatchQuery; @@ -127,7 +120,7 @@ protected Map getAlternateVersions() { @Override protected void doAssertLuceneQuery(MultiMatchQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException { // we rely on integration tests for deeper checks here - assertThat(query, either(instanceOf(TermQuery.class)).or(instanceOf(AllTermQuery.class)) + assertThat(query, either(instanceOf(BoostQuery.class)).or(instanceOf(TermQuery.class)).or(instanceOf(AllTermQuery.class)) .or(instanceOf(BooleanQuery.class)).or(instanceOf(DisjunctionMaxQuery.class)) .or(instanceOf(FuzzyQuery.class)).or(instanceOf(MultiPhrasePrefixQuery.class)) .or(instanceOf(MatchAllDocsQuery.class)).or(instanceOf(ExtendedCommonTermsQuery.class)) @@ -164,26 +157,22 @@ public void testIllegaArguments() { } } - @Override - protected void assertBoost(MultiMatchQueryBuilder queryBuilder, Query query) throws IOException { - //we delegate boost checks to specific boost tests below - } - public void testToQueryBoost() throws IOException { assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); QueryShardContext shardContext = createShardContext(); MultiMatchQueryBuilder multiMatchQueryBuilder = new MultiMatchQueryBuilder("test"); - multiMatchQueryBuilder.field(STRING_FIELD_NAME, 5); + multiMatchQueryBuilder.field(STRING_FIELD_NAME, 5f); Query query = multiMatchQueryBuilder.toQuery(shardContext); - assertThat(query, instanceOf(TermQuery.class)); - assertThat(query.getBoost(), equalTo(5f)); + assertTermOrBoostQuery(query, STRING_FIELD_NAME, "test", 5f); multiMatchQueryBuilder = new MultiMatchQueryBuilder("test"); - multiMatchQueryBuilder.field(STRING_FIELD_NAME, 5); - multiMatchQueryBuilder.boost(2); + multiMatchQueryBuilder.field(STRING_FIELD_NAME, 5f); + multiMatchQueryBuilder.boost(2f); query = multiMatchQueryBuilder.toQuery(shardContext); - assertThat(query, instanceOf(TermQuery.class)); - assertThat(query.getBoost(), equalTo(10f)); + assertThat(query, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(2f)); + assertTermOrBoostQuery(boostQuery.getQuery(), STRING_FIELD_NAME, "test", 5f); } public void testToQueryMultipleTermsBooleanQuery() throws Exception { @@ -212,7 +201,9 @@ public void testToQueryMultipleFieldsDisMaxQuery() throws Exception { assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query; List disjuncts = disMaxQuery.getDisjuncts(); + assertThat(disjuncts.get(0), instanceOf(TermQuery.class)); assertThat(((TermQuery) disjuncts.get(0)).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test"))); + assertThat(disjuncts.get(1), instanceOf(TermQuery.class)); assertThat(((TermQuery) disjuncts.get(1)).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test"))); } diff --git a/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java index 00b139039cf52..2f2fdd406e138 100644 --- a/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java @@ -20,16 +20,7 @@ package org.elasticsearch.index.query; import org.apache.lucene.index.Term; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.BoostQuery; -import org.apache.lucene.search.DisjunctionMaxQuery; -import org.apache.lucene.search.MatchAllDocsQuery; -import org.apache.lucene.search.MatchNoDocsQuery; -import org.apache.lucene.search.NumericRangeQuery; -import org.apache.lucene.search.PhraseQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.RegexpQuery; -import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.*; import org.apache.lucene.util.automaton.TooComplexToDeterminizeException; import org.elasticsearch.common.lucene.all.AllTermQuery; import org.hamcrest.Matchers; @@ -42,9 +33,8 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery; import static org.hamcrest.CoreMatchers.either; import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; public class QueryStringQueryBuilderTests extends AbstractQueryTestCase { @@ -197,13 +187,17 @@ public void testToQueryBoosts() throws Exception { Query query = queryStringQuery.toQuery(shardContext); assertThat(query, instanceOf(BoostQuery.class)); BoostQuery boostQuery = (BoostQuery) query; - assertThat(boostQuery.getBoost(), Matchers.equalTo(2.0f)); + assertThat(boostQuery.getBoost(), equalTo(2.0f)); assertThat(boostQuery.getQuery(), instanceOf(TermQuery.class)); assertThat(((TermQuery) boostQuery.getQuery()).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "boosted"))); queryStringQuery.boost(2.0f); query = queryStringQuery.toQuery(shardContext); assertThat(query, instanceOf(BoostQuery.class)); - assertThat(((BoostQuery) query).getBoost(), Matchers.equalTo(4.0f)); + boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(2.0f)); + assertThat(boostQuery .getQuery(), instanceOf(BoostQuery.class)); + boostQuery = (BoostQuery) boostQuery.getQuery(); + assertThat(boostQuery.getBoost(), equalTo(2.0f)); queryStringQuery = queryStringQuery("((" + STRING_FIELD_NAME + ":boosted^2) AND (" + STRING_FIELD_NAME + ":foo^1.5))^3"); query = queryStringQuery.toQuery(shardContext); @@ -222,7 +216,7 @@ public void testToQueryBoosts() throws Exception { query = queryStringQuery.toQuery(shardContext); assertThat(query, instanceOf(BoostQuery.class)); boostQuery = (BoostQuery) query; - assertThat(boostQuery.getBoost(), equalTo(6.0f)); + assertThat(boostQuery.getBoost(), equalTo(2.0f)); } public void testToQueryMultipleTermsBooleanQuery() throws Exception { @@ -271,10 +265,8 @@ public void testToQueryDisMaxQuery() throws Exception { assertThat(query, instanceOf(DisjunctionMaxQuery.class)); DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query; List disjuncts = disMaxQuery.getDisjuncts(); - assertThat(((TermQuery) disjuncts.get(0)).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test"))); - assertThat((double) disjuncts.get(0).getBoost(), closeTo(2.2, 0.01)); - assertThat(((TermQuery) disjuncts.get(1)).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test"))); - assertThat((double) disjuncts.get(1).getBoost(), closeTo(1, 0.01)); + assertTermOrBoostQuery(disjuncts.get(0), STRING_FIELD_NAME, "test", 2.2f); + assertTermOrBoostQuery(disjuncts.get(1), STRING_FIELD_NAME_2, "test", 1.0f); } public void testToQueryRegExpQuery() throws Exception { @@ -330,4 +322,56 @@ public void testTimezone() throws Exception { // We expect this one } } + + public void testToQueryBooleanQueryMultipleBoosts() throws Exception { + assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); + int numBoosts = randomIntBetween(2, 10); + float[] boosts = new float[numBoosts + 1]; + String queryStringPrefix = ""; + String queryStringSuffix = ""; + for (int i = 0; i < boosts.length - 1; i++) { + float boost = 2.0f / randomIntBetween(3, 20); + boosts[i] = boost; + queryStringPrefix += "("; + queryStringSuffix += ")^" + boost; + } + String queryString = queryStringPrefix + "foo bar" + queryStringSuffix; + + float mainBoost = 2.0f / randomIntBetween(3, 20); + boosts[boosts.length - 1] = mainBoost; + QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(queryString).field(STRING_FIELD_NAME) + .minimumShouldMatch("2").boost(mainBoost); + Query query = queryStringQueryBuilder.toQuery(createShardContext()); + + for (int i = boosts.length - 1; i >= 0; i--) { + assertThat(query, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(boosts[i])); + query = boostQuery.getQuery(); + } + + assertThat(query, instanceOf(BooleanQuery.class)); + BooleanQuery booleanQuery = (BooleanQuery) query; + assertThat(booleanQuery.getMinimumNumberShouldMatch(), equalTo(2)); + assertThat(booleanQuery.clauses().get(0).getOccur(), equalTo(BooleanClause.Occur.SHOULD)); + assertThat(booleanQuery.clauses().get(0).getQuery(), equalTo(new TermQuery(new Term(STRING_FIELD_NAME, "foo")))); + assertThat(booleanQuery.clauses().get(1).getOccur(), equalTo(BooleanClause.Occur.SHOULD)); + assertThat(booleanQuery.clauses().get(1).getQuery(), equalTo(new TermQuery(new Term(STRING_FIELD_NAME, "bar")))); + } + + public void testToQueryPhraseQueryBoostAndSlop() throws IOException { + assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0); + QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder("\"test phrase\"~2").field(STRING_FIELD_NAME, 5f); + Query query = queryStringQueryBuilder.toQuery(createShardContext()); + assertThat(query, instanceOf(DisjunctionMaxQuery.class)); + DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query; + assertThat(disjunctionMaxQuery.getDisjuncts().size(), equalTo(1)); + assertThat(disjunctionMaxQuery.getDisjuncts().get(0), instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) disjunctionMaxQuery.getDisjuncts().get(0); + assertThat(boostQuery.getBoost(), equalTo(5f)); + assertThat(boostQuery.getQuery(), instanceOf(PhraseQuery.class)); + PhraseQuery phraseQuery = (PhraseQuery) boostQuery.getQuery(); + assertThat(phraseQuery.getSlop(), Matchers.equalTo(2)); + assertThat(phraseQuery.getTerms().length, equalTo(2)); + } } diff --git a/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java b/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java index 2b173bdb1fe5f..147d21576c637 100644 --- a/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java +++ b/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java @@ -61,27 +61,38 @@ public static QueryBuilder createQuery(Random r) { public static MultiTermQueryBuilder createMultiTermQuery(Random r) { // for now, only use String Rangequeries for MultiTerm test, numeric and date makes little sense // see issue #12123 for discussion + MultiTermQueryBuilder multiTermQueryBuilder; switch(RandomInts.randomIntBetween(r, 0, 5)) { case 0: RangeQueryBuilder stringRangeQuery = new RangeQueryBuilder(AbstractQueryTestCase.STRING_FIELD_NAME); stringRangeQuery.from("a" + RandomStrings.randomAsciiOfLengthBetween(r, 1, 10)); stringRangeQuery.to("z" + RandomStrings.randomAsciiOfLengthBetween(r, 1, 10)); - return stringRangeQuery; + multiTermQueryBuilder = stringRangeQuery; + break; case 1: RangeQueryBuilder numericRangeQuery = new RangeQueryBuilder(AbstractQueryTestCase.INT_FIELD_NAME); numericRangeQuery.from(RandomInts.randomIntBetween(r, 1, 100)); numericRangeQuery.to(RandomInts.randomIntBetween(r, 101, 200)); - return numericRangeQuery; + multiTermQueryBuilder = numericRangeQuery; + break; case 2: - return new FuzzyQueryBuilder(AbstractQueryTestCase.INT_FIELD_NAME, RandomInts.randomInt(r, 1000)); + multiTermQueryBuilder = new FuzzyQueryBuilder(AbstractQueryTestCase.INT_FIELD_NAME, RandomInts.randomInt(r, 1000)); + break; case 3: - return new FuzzyQueryBuilder(AbstractQueryTestCase.STRING_FIELD_NAME, RandomStrings.randomAsciiOfLengthBetween(r, 1, 10)); + multiTermQueryBuilder = new FuzzyQueryBuilder(AbstractQueryTestCase.STRING_FIELD_NAME, RandomStrings.randomAsciiOfLengthBetween(r, 1, 10)); + break; case 4: - return new PrefixQueryBuilderTests().createTestQueryBuilder(); + multiTermQueryBuilder = new PrefixQueryBuilderTests().createTestQueryBuilder(); + break; case 5: - return new WildcardQueryBuilderTests().createTestQueryBuilder(); + multiTermQueryBuilder = new WildcardQueryBuilderTests().createTestQueryBuilder(); + break; default: throw new UnsupportedOperationException(); } + if (r.nextBoolean()) { + multiTermQueryBuilder.boost(2.0f / RandomInts.randomIntBetween(r, 1, 20)); + } + return multiTermQueryBuilder; } } diff --git a/core/src/test/java/org/elasticsearch/index/query/SimpleQueryStringBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/SimpleQueryStringBuilderTests.java index 85f1c1d5f0a6f..6cfcb7f2083cf 100644 --- a/core/src/test/java/org/elasticsearch/index/query/SimpleQueryStringBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/SimpleQueryStringBuilderTests.java @@ -20,11 +20,7 @@ package org.elasticsearch.index.query; import org.apache.lucene.index.Term; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.MatchNoDocsQuery; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.*; import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.ParseFieldMatcher; @@ -276,10 +272,9 @@ protected void doAssertLuceneQuery(SimpleQueryStringBuilder queryBuilder, Query assertThat(query, notNullValue()); if ("".equals(queryBuilder.value())) { - assertTrue("Query should have been MatchNoDocsQuery but was " + query.getClass().getName(), query instanceof MatchNoDocsQuery); + assertThat(query, instanceOf(MatchNoDocsQuery.class)); } else if (queryBuilder.fields().size() > 1) { - assertTrue("Query should have been BooleanQuery but was " + query.getClass().getName(), query instanceof BooleanQuery); - + assertThat(query, instanceOf(BooleanQuery.class)); BooleanQuery boolQuery = (BooleanQuery) query; if (queryBuilder.lowercaseExpandedTerms()) { for (BooleanClause clause : boolQuery.clauses()) { @@ -289,43 +284,26 @@ protected void doAssertLuceneQuery(SimpleQueryStringBuilder queryBuilder, Query } } } - assertThat(boolQuery.clauses().size(), equalTo(queryBuilder.fields().size())); - Iterator fields = queryBuilder.fields().keySet().iterator(); + Iterator> fieldsIterator = queryBuilder.fields().entrySet().iterator(); for (BooleanClause booleanClause : boolQuery) { - assertThat(booleanClause.getQuery(), instanceOf(TermQuery.class)); - TermQuery termQuery = (TermQuery) booleanClause.getQuery(); - assertThat(termQuery.getTerm().field(), equalTo(fields.next())); - assertThat(termQuery.getTerm().text().toLowerCase(Locale.ROOT), equalTo(queryBuilder.value().toLowerCase(Locale.ROOT))); + Map.Entry field = fieldsIterator.next(); + assertTermOrBoostQuery(booleanClause.getQuery(), field.getKey(), queryBuilder.value(), field.getValue()); } - if (queryBuilder.minimumShouldMatch() != null) { assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0)); } - } else if (queryBuilder.fields().size() <= 1) { - assertTrue("Query should have been TermQuery but was " + query.getClass().getName(), query instanceof TermQuery); - - TermQuery termQuery = (TermQuery) query; - String field; - if (queryBuilder.fields().size() == 0) { - field = MetaData.ALL; - } else { - field = queryBuilder.fields().keySet().iterator().next(); - } - assertThat(termQuery.getTerm().field(), equalTo(field)); - assertThat(termQuery.getTerm().text().toLowerCase(Locale.ROOT), equalTo(queryBuilder.value().toLowerCase(Locale.ROOT))); + } else if (queryBuilder.fields().size() == 1) { + Map.Entry field = queryBuilder.fields().entrySet().iterator().next(); + assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue()); + } else if (queryBuilder.fields().size() == 0) { + assertTermQuery(query, MetaData.ALL, queryBuilder.value()); } else { fail("Encountered lucene query type we do not have a validation implementation for in our " + SimpleQueryStringBuilderTests.class.getSimpleName()); } } - @Override - protected void assertBoost(SimpleQueryStringBuilder queryBuilder, Query query) throws IOException { - //boost may get parsed from the random query, we then combine the main boost with that one coming from lucene - //instead of trying to reparse the query and guess what the boost should be, we delegate boost checks to specific boost tests below - } - - private int shouldClauses(BooleanQuery query) { + private static int shouldClauses(BooleanQuery query) { int result = 0; for (BooleanClause c : query.clauses()) { if (c.getOccur() == BooleanClause.Occur.SHOULD) { @@ -341,15 +319,21 @@ public void testToQueryBoost() throws IOException { SimpleQueryStringBuilder simpleQueryStringBuilder = new SimpleQueryStringBuilder("test"); simpleQueryStringBuilder.field(STRING_FIELD_NAME, 5); Query query = simpleQueryStringBuilder.toQuery(shardContext); - assertThat(query, instanceOf(TermQuery.class)); - assertThat(query.getBoost(), equalTo(5f)); + assertThat(query, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(5f)); + assertThat(boostQuery.getQuery(), instanceOf(TermQuery.class)); simpleQueryStringBuilder = new SimpleQueryStringBuilder("test"); simpleQueryStringBuilder.field(STRING_FIELD_NAME, 5); simpleQueryStringBuilder.boost(2); query = simpleQueryStringBuilder.toQuery(shardContext); - assertThat(query, instanceOf(TermQuery.class)); - assertThat(query.getBoost(), equalTo(10f)); + boostQuery = (BoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(2f)); + assertThat(boostQuery.getQuery(), instanceOf(BoostQuery.class)); + boostQuery = (BoostQuery) boostQuery.getQuery(); + assertThat(boostQuery.getBoost(), equalTo(5f)); + assertThat(boostQuery.getQuery(), instanceOf(TermQuery.class)); } public void testNegativeFlags() throws IOException { diff --git a/core/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java index ba6030f280d62..4608981115045 100644 --- a/core/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilderTests.java @@ -19,9 +19,12 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.spans.SpanBoostQuery; import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; +import org.apache.lucene.search.spans.SpanQuery; import java.io.IOException; @@ -37,9 +40,20 @@ protected SpanMultiTermQueryBuilder doCreateTestQueryBuilder() { @Override protected void doAssertLuceneQuery(SpanMultiTermQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException { + if (queryBuilder.innerQuery().boost() != AbstractQueryBuilder.DEFAULT_BOOST) { + assertThat(query, instanceOf(SpanBoostQuery.class)); + SpanBoostQuery boostQuery = (SpanBoostQuery) query; + assertThat(boostQuery.getBoost(), equalTo(queryBuilder.innerQuery().boost())); + query = boostQuery.getQuery(); + } assertThat(query, instanceOf(SpanMultiTermQueryWrapper.class)); SpanMultiTermQueryWrapper spanMultiTermQueryWrapper = (SpanMultiTermQueryWrapper) query; Query multiTermQuery = queryBuilder.innerQuery().toQuery(context); + if (queryBuilder.innerQuery().boost() != AbstractQueryBuilder.DEFAULT_BOOST) { + assertThat(multiTermQuery, instanceOf(BoostQuery.class)); + BoostQuery boostQuery = (BoostQuery) multiTermQuery; + multiTermQuery = boostQuery.getQuery(); + } assertThat(multiTermQuery, instanceOf(MultiTermQuery.class)); assertThat(spanMultiTermQueryWrapper.getWrappedQuery(), equalTo(new SpanMultiTermQueryWrapper<>((MultiTermQuery)multiTermQuery).getWrappedQuery())); } @@ -72,4 +86,10 @@ public void testUnsupportedInnerQueryType() throws IOException { } } } + + public void testToQueryInnerSpanMultiTerm() throws IOException { + Query query = new SpanOrQueryBuilder(createTestQueryBuilder()).toQuery(createShardContext()); + //verify that the result is still a span query, despite the boost that might get set (SpanBoostQuery rather than BoostQuery) + assertThat(query, instanceOf(SpanQuery.class)); + } } diff --git a/core/src/test/java/org/elasticsearch/index/query/TemplateQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/TemplateQueryBuilderTests.java index 12ac7709bfd14..a7407eed407d5 100644 --- a/core/src/test/java/org/elasticsearch/index/query/TemplateQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/TemplateQueryBuilderTests.java @@ -68,11 +68,6 @@ public void testIllegalArgument() { } } - @Override - protected void assertBoost(TemplateQueryBuilder queryBuilder, Query query) throws IOException { - //no-op boost is checked already above as part of doAssertLuceneQuery as we rely on lucene equals impl - } - /** * Override superclass test since template query doesn't support boost and queryName, so * we need to mutate other existing field in the test query. diff --git a/core/src/test/java/org/elasticsearch/index/query/WrapperQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/WrapperQueryBuilderTests.java index 3771cd7152643..e2b6049edcca0 100644 --- a/core/src/test/java/org/elasticsearch/index/query/WrapperQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/WrapperQueryBuilderTests.java @@ -64,11 +64,6 @@ protected void doAssertLuceneQuery(WrapperQueryBuilder queryBuilder, Query query } } - @Override - protected void assertBoost(WrapperQueryBuilder queryBuilder, Query query) throws IOException { - //no-op boost is checked already above as part of doAssertLuceneQuery as we rely on lucene equals impl - } - public void testIllegalArgument() { try { if (randomBoolean()) {