Always use DisjunctionMaxQuery to build cross fields disjunction (#25115)
This commit modifies query_string, simple_query_string and multi_match queries to always use a DisjunctionMaxQuery when a disjunction over multiple fields is built. The tiebreaker is set to 1 in order to behave like the boolean query in terms of scoring. The removal of the coord factor in Lucene 7 made this change mandatory to correctly handle minimum_should_match. Closes #23966
This commit is contained in:
parent
d6d416cacc
commit
21a57c1494
|
@ -296,27 +296,6 @@ public abstract class BlendedTermQuery extends Query {
|
||||||
return Objects.hash(classHash(), Arrays.hashCode(equalsTerms()));
|
return Objects.hash(classHash(), Arrays.hashCode(equalsTerms()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendedTermQuery booleanBlendedQuery(Term[] terms) {
|
|
||||||
return booleanBlendedQuery(terms, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlendedTermQuery booleanBlendedQuery(Term[] terms, final float[] boosts) {
|
|
||||||
return new BlendedTermQuery(terms, boosts) {
|
|
||||||
@Override
|
|
||||||
protected Query topLevelQuery(Term[] terms, TermContext[] ctx, int[] docFreqs, int maxDoc) {
|
|
||||||
BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
|
|
||||||
for (int i = 0; i < terms.length; i++) {
|
|
||||||
Query query = new TermQuery(terms[i], ctx[i]);
|
|
||||||
if (boosts != null && boosts[i] != 1f) {
|
|
||||||
query = new BoostQuery(query, boosts[i]);
|
|
||||||
}
|
|
||||||
booleanQueryBuilder.add(query, BooleanClause.Occur.SHOULD);
|
|
||||||
}
|
|
||||||
return booleanQueryBuilder.build();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlendedTermQuery commonTermsBlendedQuery(Term[] terms, final float[] boosts, final float maxTermFrequency) {
|
public static BlendedTermQuery commonTermsBlendedQuery(Term[] terms, final float[] boosts, final float maxTermFrequency) {
|
||||||
return new BlendedTermQuery(terms, boosts) {
|
return new BlendedTermQuery(terms, boosts) {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||||
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
|
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.DisjunctionMaxQuery;
|
import org.apache.lucene.search.DisjunctionMaxQuery;
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
|
@ -155,31 +156,20 @@ public class MapperQueryParser extends QueryParser {
|
||||||
// if there is no match in the mappings.
|
// if there is no match in the mappings.
|
||||||
return new MatchNoDocsQuery("empty fields");
|
return new MatchNoDocsQuery("empty fields");
|
||||||
}
|
}
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = getFieldQuerySingle(mField, queryText, quoted);
|
Query q = getFieldQuerySingle(mField, queryText, quoted);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = getFieldQuerySingle(mField, queryText, quoted);
|
|
||||||
if (q != null) {
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clauses.isEmpty()) return null; // happens for stopwords
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
} else {
|
} else {
|
||||||
return getFieldQuerySingle(field, queryText, quoted);
|
return getFieldQuerySingle(field, queryText, quoted);
|
||||||
}
|
}
|
||||||
|
@ -255,33 +245,21 @@ public class MapperQueryParser extends QueryParser {
|
||||||
protected Query getFieldQuery(String field, String queryText, int slop) throws ParseException {
|
protected Query getFieldQuery(String field, String queryText, int slop) throws ParseException {
|
||||||
Collection<String> fields = extractMultiFields(field);
|
Collection<String> fields = extractMultiFields(field);
|
||||||
if (fields != null) {
|
if (fields != null) {
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = super.getFieldQuery(mField, queryText, slop);
|
Query q = super.getFieldQuery(mField, queryText, slop);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
q = applySlop(q, slop);
|
q = applySlop(q, slop);
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = super.getFieldQuery(mField, queryText, slop);
|
|
||||||
if (q != null) {
|
|
||||||
q = applySlop(q, slop);
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clauses.isEmpty()) return null; // happens for stopwords
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
} else {
|
} else {
|
||||||
return super.getFieldQuery(field, queryText, slop);
|
return super.getFieldQuery(field, queryText, slop);
|
||||||
}
|
}
|
||||||
|
@ -308,31 +286,20 @@ public class MapperQueryParser extends QueryParser {
|
||||||
return getRangeQuerySingle(fields.iterator().next(), part1, part2, startInclusive, endInclusive, context);
|
return getRangeQuerySingle(fields.iterator().next(), part1, part2, startInclusive, endInclusive, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = getRangeQuerySingle(mField, part1, part2, startInclusive, endInclusive, context);
|
Query q = getRangeQuerySingle(mField, part1, part2, startInclusive, endInclusive, context);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = getRangeQuerySingle(mField, part1, part2, startInclusive, endInclusive, context);
|
|
||||||
if (q != null) {
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clauses.isEmpty()) return null; // happens for stopwords
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Query getRangeQuerySingle(String field, String part1, String part2,
|
private Query getRangeQuerySingle(String field, String part1, String part2,
|
||||||
|
@ -367,30 +334,20 @@ public class MapperQueryParser extends QueryParser {
|
||||||
if (fields.size() == 1) {
|
if (fields.size() == 1) {
|
||||||
return getFuzzyQuerySingle(fields.iterator().next(), termStr, minSimilarity);
|
return getFuzzyQuerySingle(fields.iterator().next(), termStr, minSimilarity);
|
||||||
}
|
}
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = getFuzzyQuerySingle(mField, termStr, minSimilarity);
|
Query q = getFuzzyQuerySingle(mField, termStr, minSimilarity);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = getFuzzyQuerySingle(mField, termStr, minSimilarity);
|
|
||||||
if (q != null) {
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
} else {
|
} else {
|
||||||
return getFuzzyQuerySingle(field, termStr, minSimilarity);
|
return getFuzzyQuerySingle(field, termStr, minSimilarity);
|
||||||
}
|
}
|
||||||
|
@ -430,31 +387,20 @@ public class MapperQueryParser extends QueryParser {
|
||||||
if (fields.size() == 1) {
|
if (fields.size() == 1) {
|
||||||
return getPrefixQuerySingle(fields.iterator().next(), termStr);
|
return getPrefixQuerySingle(fields.iterator().next(), termStr);
|
||||||
}
|
}
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = getPrefixQuerySingle(mField, termStr);
|
Query q = getPrefixQuerySingle(mField, termStr);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = getPrefixQuerySingle(mField, termStr);
|
|
||||||
if (q != null) {
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clauses.isEmpty()) return null; // happens for stopwords
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
} else {
|
} else {
|
||||||
return getPrefixQuerySingle(field, termStr);
|
return getPrefixQuerySingle(field, termStr);
|
||||||
}
|
}
|
||||||
|
@ -592,31 +538,20 @@ public class MapperQueryParser extends QueryParser {
|
||||||
if (fields.size() == 1) {
|
if (fields.size() == 1) {
|
||||||
return getWildcardQuerySingle(fields.iterator().next(), termStr);
|
return getWildcardQuerySingle(fields.iterator().next(), termStr);
|
||||||
}
|
}
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = getWildcardQuerySingle(mField, termStr);
|
Query q = getWildcardQuerySingle(mField, termStr);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = getWildcardQuerySingle(mField, termStr);
|
|
||||||
if (q != null) {
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clauses.isEmpty()) return null; // happens for stopwords
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
} else {
|
} else {
|
||||||
return getWildcardQuerySingle(field, termStr);
|
return getWildcardQuerySingle(field, termStr);
|
||||||
}
|
}
|
||||||
|
@ -656,31 +591,20 @@ public class MapperQueryParser extends QueryParser {
|
||||||
if (fields.size() == 1) {
|
if (fields.size() == 1) {
|
||||||
return getRegexpQuerySingle(fields.iterator().next(), termStr);
|
return getRegexpQuerySingle(fields.iterator().next(), termStr);
|
||||||
}
|
}
|
||||||
if (settings.useDisMax()) {
|
float tiebreaker = settings.useDisMax() ? settings.tieBreaker() : 1.0f;
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
for (String mField : fields) {
|
for (String mField : fields) {
|
||||||
Query q = getRegexpQuerySingle(mField, termStr);
|
Query q = getRegexpQuerySingle(mField, termStr);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
added = true;
|
added = true;
|
||||||
queries.add(applyBoost(mField, q));
|
queries.add(applyBoost(mField, q));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!added) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, settings.tieBreaker());
|
|
||||||
} else {
|
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
|
||||||
for (String mField : fields) {
|
|
||||||
Query q = getRegexpQuerySingle(mField, termStr);
|
|
||||||
if (q != null) {
|
|
||||||
clauses.add(new BooleanClause(applyBoost(mField, q), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clauses.isEmpty()) return null; // happens for stopwords
|
|
||||||
return getBooleanQuery(clauses);
|
|
||||||
}
|
}
|
||||||
|
if (!added) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tiebreaker);
|
||||||
} else {
|
} else {
|
||||||
return getRegexpQuerySingle(field, termStr);
|
return getRegexpQuerySingle(field, termStr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
|
import org.apache.lucene.search.DisjunctionMaxQuery;
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
import org.apache.lucene.search.PrefixQuery;
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
@ -36,6 +37,7 @@ import org.elasticsearch.index.analysis.ShingleTokenFilterFactory;
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -79,18 +81,21 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query newDefaultQuery(String text) {
|
public Query newDefaultQuery(String text) {
|
||||||
BooleanQuery.Builder bq = new BooleanQuery.Builder();
|
List<Query> disjuncts = new ArrayList<>();
|
||||||
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
||||||
try {
|
try {
|
||||||
Query q = createBooleanQuery(entry.getKey(), text, super.getDefaultOperator());
|
Query q = createBooleanQuery(entry.getKey(), text, super.getDefaultOperator());
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
bq.add(wrapWithBoost(q, entry.getValue()), BooleanClause.Occur.SHOULD);
|
disjuncts.add(wrapWithBoost(q, entry.getValue()));
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
rethrowUnlessLenient(e);
|
rethrowUnlessLenient(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.simplify(bq.build());
|
if (disjuncts.size() == 1) {
|
||||||
|
return disjuncts.get(0);
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(disjuncts, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,23 +104,26 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Query newFuzzyQuery(String text, int fuzziness) {
|
public Query newFuzzyQuery(String text, int fuzziness) {
|
||||||
BooleanQuery.Builder bq = new BooleanQuery.Builder();
|
List<Query> disjuncts = new ArrayList<>();
|
||||||
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
||||||
final String fieldName = entry.getKey();
|
final String fieldName = entry.getKey();
|
||||||
try {
|
try {
|
||||||
final BytesRef term = getAnalyzer().normalize(fieldName, text);
|
final BytesRef term = getAnalyzer().normalize(fieldName, text);
|
||||||
Query query = new FuzzyQuery(new Term(fieldName, term), fuzziness);
|
Query query = new FuzzyQuery(new Term(fieldName, term), fuzziness);
|
||||||
bq.add(wrapWithBoost(query, entry.getValue()), BooleanClause.Occur.SHOULD);
|
disjuncts.add(wrapWithBoost(query, entry.getValue()));
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
rethrowUnlessLenient(e);
|
rethrowUnlessLenient(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.simplify(bq.build());
|
if (disjuncts.size() == 1) {
|
||||||
|
return disjuncts.get(0);
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(disjuncts, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query newPhraseQuery(String text, int slop) {
|
public Query newPhraseQuery(String text, int slop) {
|
||||||
BooleanQuery.Builder bq = new BooleanQuery.Builder();
|
List<Query> disjuncts = new ArrayList<>();
|
||||||
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
||||||
try {
|
try {
|
||||||
String field = entry.getKey();
|
String field = entry.getKey();
|
||||||
|
@ -129,13 +137,16 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
|
||||||
Float boost = entry.getValue();
|
Float boost = entry.getValue();
|
||||||
Query q = createPhraseQuery(field, text, slop);
|
Query q = createPhraseQuery(field, text, slop);
|
||||||
if (q != null) {
|
if (q != null) {
|
||||||
bq.add(wrapWithBoost(q, boost), BooleanClause.Occur.SHOULD);
|
disjuncts.add(wrapWithBoost(q, boost));
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
rethrowUnlessLenient(e);
|
rethrowUnlessLenient(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.simplify(bq.build());
|
if (disjuncts.size() == 1) {
|
||||||
|
return disjuncts.get(0);
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(disjuncts, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,25 +155,28 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Query newPrefixQuery(String text) {
|
public Query newPrefixQuery(String text) {
|
||||||
BooleanQuery.Builder bq = new BooleanQuery.Builder();
|
List<Query> disjuncts = new ArrayList<>();
|
||||||
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
for (Map.Entry<String,Float> entry : weights.entrySet()) {
|
||||||
final String fieldName = entry.getKey();
|
final String fieldName = entry.getKey();
|
||||||
try {
|
try {
|
||||||
if (settings.analyzeWildcard()) {
|
if (settings.analyzeWildcard()) {
|
||||||
Query analyzedQuery = newPossiblyAnalyzedQuery(fieldName, text);
|
Query analyzedQuery = newPossiblyAnalyzedQuery(fieldName, text);
|
||||||
if (analyzedQuery != null) {
|
if (analyzedQuery != null) {
|
||||||
bq.add(wrapWithBoost(analyzedQuery, entry.getValue()), BooleanClause.Occur.SHOULD);
|
disjuncts.add(wrapWithBoost(analyzedQuery, entry.getValue()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Term term = new Term(fieldName, getAnalyzer().normalize(fieldName, text));
|
Term term = new Term(fieldName, getAnalyzer().normalize(fieldName, text));
|
||||||
Query query = new PrefixQuery(term);
|
Query query = new PrefixQuery(term);
|
||||||
bq.add(wrapWithBoost(query, entry.getValue()), BooleanClause.Occur.SHOULD);
|
disjuncts.add(wrapWithBoost(query, entry.getValue()));
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
return rethrowUnlessLenient(e);
|
return rethrowUnlessLenient(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.simplify(bq.build());
|
if (disjuncts.size() == 1) {
|
||||||
|
return disjuncts.get(0);
|
||||||
|
}
|
||||||
|
return new DisjunctionMaxQuery(disjuncts, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,9 +22,6 @@ package org.elasticsearch.index.search;
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.queries.BlendedTermQuery;
|
import org.apache.lucene.queries.BlendedTermQuery;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
|
||||||
import org.apache.lucene.search.BooleanClause.Occur;
|
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.DisjunctionMaxQuery;
|
import org.apache.lucene.search.DisjunctionMaxQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
|
@ -84,7 +81,7 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
queryBuilder = new QueryBuilder(tieBreaker);
|
queryBuilder = new QueryBuilder(tieBreaker);
|
||||||
break;
|
break;
|
||||||
case CROSS_FIELDS:
|
case CROSS_FIELDS:
|
||||||
queryBuilder = new CrossFieldsQueryBuilder(tieBreaker);
|
queryBuilder = new CrossFieldsQueryBuilder();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("No such type: " + type);
|
throw new IllegalStateException("No such type: " + type);
|
||||||
|
@ -99,15 +96,9 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
private QueryBuilder queryBuilder;
|
private QueryBuilder queryBuilder;
|
||||||
|
|
||||||
public class QueryBuilder {
|
public class QueryBuilder {
|
||||||
protected final boolean groupDismax;
|
|
||||||
protected final float tieBreaker;
|
protected final float tieBreaker;
|
||||||
|
|
||||||
public QueryBuilder(float tieBreaker) {
|
public QueryBuilder(float tieBreaker) {
|
||||||
this(tieBreaker != 1.0f, tieBreaker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueryBuilder(boolean groupDismax, float tieBreaker) {
|
|
||||||
this.groupDismax = groupDismax;
|
|
||||||
this.tieBreaker = tieBreaker;
|
this.tieBreaker = tieBreaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,19 +125,11 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
if (groupQuery.size() == 1) {
|
if (groupQuery.size() == 1) {
|
||||||
return groupQuery.get(0);
|
return groupQuery.get(0);
|
||||||
}
|
}
|
||||||
if (groupDismax) {
|
List<Query> queries = new ArrayList<>();
|
||||||
List<Query> queries = new ArrayList<>();
|
for (Query query : groupQuery) {
|
||||||
for (Query query : groupQuery) {
|
queries.add(query);
|
||||||
queries.add(query);
|
|
||||||
}
|
|
||||||
return new DisjunctionMaxQuery(queries, tieBreaker);
|
|
||||||
} else {
|
|
||||||
final BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
|
|
||||||
for (Query query : groupQuery) {
|
|
||||||
booleanQuery.add(query, BooleanClause.Occur.SHOULD);
|
|
||||||
}
|
|
||||||
return booleanQuery.build();
|
|
||||||
}
|
}
|
||||||
|
return new DisjunctionMaxQuery(queries, tieBreaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query blendTerm(Term term, MappedFieldType fieldType) {
|
public Query blendTerm(Term term, MappedFieldType fieldType) {
|
||||||
|
@ -165,8 +148,8 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
final class CrossFieldsQueryBuilder extends QueryBuilder {
|
final class CrossFieldsQueryBuilder extends QueryBuilder {
|
||||||
private FieldAndFieldType[] blendedFields;
|
private FieldAndFieldType[] blendedFields;
|
||||||
|
|
||||||
CrossFieldsQueryBuilder(float tieBreaker) {
|
CrossFieldsQueryBuilder() {
|
||||||
super(false, tieBreaker);
|
super(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -306,8 +289,6 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
blendedBoost = Arrays.copyOf(blendedBoost, i);
|
blendedBoost = Arrays.copyOf(blendedBoost, i);
|
||||||
if (commonTermsCutoff != null) {
|
if (commonTermsCutoff != null) {
|
||||||
queries.add(BlendedTermQuery.commonTermsBlendedQuery(terms, blendedBoost, commonTermsCutoff));
|
queries.add(BlendedTermQuery.commonTermsBlendedQuery(terms, blendedBoost, commonTermsCutoff));
|
||||||
} else if (tieBreaker == 1.0f) {
|
|
||||||
queries.add(BlendedTermQuery.booleanBlendedQuery(terms, blendedBoost));
|
|
||||||
} else {
|
} else {
|
||||||
queries.add(BlendedTermQuery.dismaxBlendedQuery(terms, blendedBoost, tieBreaker));
|
queries.add(BlendedTermQuery.dismaxBlendedQuery(terms, blendedBoost, tieBreaker));
|
||||||
}
|
}
|
||||||
|
@ -318,11 +299,7 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
// best effort: add clauses that are not term queries so that they have an opportunity to match
|
// best effort: add clauses that are not term queries so that they have an opportunity to match
|
||||||
// however their score contribution will be different
|
// however their score contribution will be different
|
||||||
// TODO: can we improve this?
|
// TODO: can we improve this?
|
||||||
BooleanQuery.Builder bq = new BooleanQuery.Builder();
|
return new DisjunctionMaxQuery(queries, 1.0f);
|
||||||
for (Query query : queries) {
|
|
||||||
bq.add(query, Occur.SHOULD);
|
|
||||||
}
|
|
||||||
return bq.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,58 +54,6 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
public class BlendedTermQueryTests extends ESTestCase {
|
public class BlendedTermQueryTests extends ESTestCase {
|
||||||
public void testBooleanQuery() throws IOException {
|
|
||||||
Directory dir = newDirectory();
|
|
||||||
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(new MockAnalyzer(random())));
|
|
||||||
String[] firstNames = new String[]{
|
|
||||||
"simon", "paul"
|
|
||||||
};
|
|
||||||
String[] surNames = new String[]{
|
|
||||||
"willnauer", "simon"
|
|
||||||
};
|
|
||||||
for (int i = 0; i < surNames.length; i++) {
|
|
||||||
Document d = new Document();
|
|
||||||
d.add(new TextField("id", Integer.toString(i), Field.Store.YES));
|
|
||||||
d.add(new TextField("firstname", firstNames[i], Field.Store.NO));
|
|
||||||
d.add(new TextField("surname", surNames[i], Field.Store.NO));
|
|
||||||
w.addDocument(d);
|
|
||||||
}
|
|
||||||
int iters = scaledRandomIntBetween(25, 100);
|
|
||||||
for (int j = 0; j < iters; j++) {
|
|
||||||
Document d = new Document();
|
|
||||||
d.add(new TextField("id", Integer.toString(firstNames.length + j), Field.Store.YES));
|
|
||||||
d.add(new TextField("firstname", rarely() ? "some_other_name" :
|
|
||||||
"simon the sorcerer", Field.Store.NO)); // make sure length-norm is the tie-breaker
|
|
||||||
d.add(new TextField("surname", "bogus", Field.Store.NO));
|
|
||||||
w.addDocument(d);
|
|
||||||
}
|
|
||||||
w.commit();
|
|
||||||
DirectoryReader reader = DirectoryReader.open(w);
|
|
||||||
IndexSearcher searcher = setSimilarity(newSearcher(reader));
|
|
||||||
|
|
||||||
{
|
|
||||||
Term[] terms = new Term[]{new Term("firstname", "simon"), new Term("surname", "simon")};
|
|
||||||
BlendedTermQuery query = BlendedTermQuery.booleanBlendedQuery(terms);
|
|
||||||
TopDocs search = searcher.search(query, 3);
|
|
||||||
ScoreDoc[] scoreDocs = search.scoreDocs;
|
|
||||||
assertEquals(3, scoreDocs.length);
|
|
||||||
assertEquals(Integer.toString(0), reader.document(scoreDocs[0].doc).getField("id").stringValue());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
BooleanQuery.Builder query = new BooleanQuery.Builder();
|
|
||||||
query.add(new TermQuery(new Term("firstname", "simon")), BooleanClause.Occur.SHOULD);
|
|
||||||
query.add(new TermQuery(new Term("surname", "simon")), BooleanClause.Occur.SHOULD);
|
|
||||||
TopDocs search = searcher.search(query.build(), 1);
|
|
||||||
ScoreDoc[] scoreDocs = search.scoreDocs;
|
|
||||||
assertEquals(Integer.toString(1), reader.document(scoreDocs[0].doc).getField("id").stringValue());
|
|
||||||
|
|
||||||
}
|
|
||||||
reader.close();
|
|
||||||
w.close();
|
|
||||||
dir.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDismaxQuery() throws IOException {
|
public void testDismaxQuery() throws IOException {
|
||||||
Directory dir = newDirectory();
|
Directory dir = newDirectory();
|
||||||
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(new MockAnalyzer(random())));
|
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(new MockAnalyzer(random())));
|
||||||
|
@ -183,12 +131,11 @@ public class BlendedTermQueryTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
String term = TestUtil.randomRealisticUnicodeString(random(), 1, 10);
|
String term = TestUtil.randomRealisticUnicodeString(random(), 1, 10);
|
||||||
Term[] terms = toTerms(fields, term);
|
Term[] terms = toTerms(fields, term);
|
||||||
boolean useBoolean = random().nextBoolean();
|
|
||||||
float tieBreaker = random().nextFloat();
|
float tieBreaker = random().nextFloat();
|
||||||
BlendedTermQuery query = useBoolean ? BlendedTermQuery.booleanBlendedQuery(terms) : BlendedTermQuery.dismaxBlendedQuery(terms, tieBreaker);
|
BlendedTermQuery query = BlendedTermQuery.dismaxBlendedQuery(terms, tieBreaker);
|
||||||
QueryUtils.check(query);
|
QueryUtils.check(query);
|
||||||
terms = toTerms(fields, term);
|
terms = toTerms(fields, term);
|
||||||
BlendedTermQuery query2 = useBoolean ? BlendedTermQuery.booleanBlendedQuery(terms) : BlendedTermQuery.dismaxBlendedQuery(terms, tieBreaker);
|
BlendedTermQuery query2 = BlendedTermQuery.dismaxBlendedQuery(terms, tieBreaker);
|
||||||
assertEquals(query, query2);
|
assertEquals(query, query2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,8 +164,7 @@ public class BlendedTermQueryTests extends ESTestCase {
|
||||||
terms.add(new Term(TestUtil.randomRealisticUnicodeString(random(), 1, 10), TestUtil.randomRealisticUnicodeString(random(), 1, 10)));
|
terms.add(new Term(TestUtil.randomRealisticUnicodeString(random(), 1, 10), TestUtil.randomRealisticUnicodeString(random(), 1, 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BlendedTermQuery blendedTermQuery = random().nextBoolean() ? BlendedTermQuery.dismaxBlendedQuery(terms.toArray(new Term[0]), random().nextFloat()) :
|
BlendedTermQuery blendedTermQuery = BlendedTermQuery.dismaxBlendedQuery(terms.toArray(new Term[0]), random().nextFloat());
|
||||||
BlendedTermQuery.booleanBlendedQuery(terms.toArray(new Term[0]));
|
|
||||||
Set<Term> extracted = new HashSet<>();
|
Set<Term> extracted = new HashSet<>();
|
||||||
IndexSearcher searcher = new IndexSearcher(new MultiReader());
|
IndexSearcher searcher = new IndexSearcher(new MultiReader());
|
||||||
searcher.createNormalizedWeight(blendedTermQuery, false).extractTerms(extracted);
|
searcher.createNormalizedWeight(blendedTermQuery, false).extractTerms(extracted);
|
||||||
|
|
|
@ -47,6 +47,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
|
||||||
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertDisjunctionSubQuery;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.either;
|
import static org.hamcrest.CoreMatchers.either;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
@ -183,14 +184,15 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test2")));
|
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test2")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testToQueryMultipleFieldsBooleanQuery() throws Exception {
|
public void testToQueryMultipleFieldsDisableDismax() throws Exception {
|
||||||
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(false).toQuery(createShardContext());
|
Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(false).toQuery(createShardContext());
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
BooleanQuery bQuery = (BooleanQuery) query;
|
DisjunctionMaxQuery dQuery = (DisjunctionMaxQuery) query;
|
||||||
assertThat(bQuery.clauses().size(), equalTo(2));
|
assertThat(dQuery.getTieBreakerMultiplier(), equalTo(1.0f));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
|
assertThat(dQuery.getDisjuncts().size(), equalTo(2));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 0).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
|
||||||
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testToQueryMultipleFieldsDisMaxQuery() throws Exception {
|
public void testToQueryMultipleFieldsDisMaxQuery() throws Exception {
|
||||||
|
@ -198,6 +200,7 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
|
||||||
Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(true).toQuery(createShardContext());
|
Query query = multiMatchQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(true).toQuery(createShardContext());
|
||||||
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query;
|
DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query;
|
||||||
|
assertThat(disMaxQuery.getTieBreakerMultiplier(), equalTo(0.0f));
|
||||||
List<Query> disjuncts = disMaxQuery.getDisjuncts();
|
List<Query> disjuncts = disMaxQuery.getDisjuncts();
|
||||||
assertThat(disjuncts.get(0), instanceOf(TermQuery.class));
|
assertThat(disjuncts.get(0), instanceOf(TermQuery.class));
|
||||||
assertThat(((TermQuery) disjuncts.get(0)).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
|
assertThat(((TermQuery) disjuncts.get(0)).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
|
||||||
|
@ -208,11 +211,12 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
|
||||||
public void testToQueryFieldsWildcard() throws Exception {
|
public void testToQueryFieldsWildcard() throws Exception {
|
||||||
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
Query query = multiMatchQuery("test").field("mapped_str*").useDisMax(false).toQuery(createShardContext());
|
Query query = multiMatchQuery("test").field("mapped_str*").useDisMax(false).toQuery(createShardContext());
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
BooleanQuery bQuery = (BooleanQuery) query;
|
DisjunctionMaxQuery dQuery = (DisjunctionMaxQuery) query;
|
||||||
assertThat(bQuery.clauses().size(), equalTo(2));
|
assertThat(dQuery.getTieBreakerMultiplier(), equalTo(1.0f));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
|
assertThat(dQuery.getDisjuncts().size(), equalTo(2));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 0).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
|
||||||
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testToQueryFieldMissing() throws Exception {
|
public void testToQueryFieldMissing() throws Exception {
|
||||||
|
|
|
@ -61,11 +61,13 @@ import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery;
|
||||||
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertDisjunctionSubQuery;
|
||||||
import static org.hamcrest.CoreMatchers.either;
|
import static org.hamcrest.CoreMatchers.either;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
@ -270,12 +272,12 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
.field(STRING_FIELD_NAME_2)
|
.field(STRING_FIELD_NAME_2)
|
||||||
.useDisMax(false)
|
.useDisMax(false)
|
||||||
.toQuery(createShardContext());
|
.toQuery(createShardContext());
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
BooleanQuery bQuery = (BooleanQuery) query;
|
DisjunctionMaxQuery bQuery = (DisjunctionMaxQuery) query;
|
||||||
assertThat(bQuery.clauses().size(), equalTo(2));
|
assertThat(bQuery.getDisjuncts().size(), equalTo(2));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(),
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 0).getTerm(),
|
||||||
equalTo(new Term(STRING_FIELD_NAME, "test")));
|
equalTo(new Term(STRING_FIELD_NAME, "test")));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(),
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 1).getTerm(),
|
||||||
equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,12 +296,12 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
public void testToQueryFieldsWildcard() throws Exception {
|
public void testToQueryFieldsWildcard() throws Exception {
|
||||||
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
Query query = queryStringQuery("test").field("mapped_str*").useDisMax(false).toQuery(createShardContext());
|
Query query = queryStringQuery("test").field("mapped_str*").useDisMax(false).toQuery(createShardContext());
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
BooleanQuery bQuery = (BooleanQuery) query;
|
DisjunctionMaxQuery dQuery = (DisjunctionMaxQuery) query;
|
||||||
assertThat(bQuery.clauses().size(), equalTo(2));
|
assertThat(dQuery.getDisjuncts().size(), equalTo(2));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(),
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 0).getTerm(),
|
||||||
equalTo(new Term(STRING_FIELD_NAME, "test")));
|
equalTo(new Term(STRING_FIELD_NAME, "test")));
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(),
|
assertThat(assertDisjunctionSubQuery(query, TermQuery.class, 1).getTerm(),
|
||||||
equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,6 +399,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
|
|
||||||
// simple multi-term
|
// simple multi-term
|
||||||
Query query = queryParser.parse("guinea pig");
|
Query query = queryParser.parse("guinea pig");
|
||||||
|
|
||||||
Query expectedQuery = new BooleanQuery.Builder()
|
Query expectedQuery = new BooleanQuery.Builder()
|
||||||
.add(new BooleanQuery.Builder()
|
.add(new BooleanQuery.Builder()
|
||||||
.add(new TermQuery(new Term(STRING_FIELD_NAME, "guinea")), Occur.MUST)
|
.add(new TermQuery(new Term(STRING_FIELD_NAME, "guinea")), Occur.MUST)
|
||||||
|
@ -448,34 +451,34 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
|
|
||||||
// span query
|
// span query
|
||||||
query = queryParser.parse("\"that guinea pig smells\"");
|
query = queryParser.parse("\"that guinea pig smells\"");
|
||||||
expectedQuery = new BooleanQuery.Builder()
|
|
||||||
.add(new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
SpanNearQuery nearQuery = new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "that")))
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "that")))
|
||||||
.addClause(new SpanOrQuery(
|
.addClause(
|
||||||
|
new SpanOrQuery(
|
||||||
new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "guinea")))
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "guinea")))
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "pig"))).build(),
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "pig"))).build(),
|
||||||
new SpanTermQuery(new Term(STRING_FIELD_NAME, "cavy"))))
|
new SpanTermQuery(new Term(STRING_FIELD_NAME, "cavy"))))
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "smells")))
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "smells")))
|
||||||
.build(), Occur.SHOULD)
|
.build();
|
||||||
.build();
|
expectedQuery = new DisjunctionMaxQuery(Collections.singletonList(nearQuery), 1.0f);
|
||||||
assertThat(query, Matchers.equalTo(expectedQuery));
|
assertThat(query, Matchers.equalTo(expectedQuery));
|
||||||
|
|
||||||
// span query with slop
|
// span query with slop
|
||||||
query = queryParser.parse("\"that guinea pig smells\"~2");
|
query = queryParser.parse("\"that guinea pig smells\"~2");
|
||||||
expectedQuery = new BooleanQuery.Builder()
|
nearQuery = new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
||||||
.add(new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "that")))
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "that")))
|
.addClause(
|
||||||
.addClause(new SpanOrQuery(
|
new SpanOrQuery(
|
||||||
new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
new SpanNearQuery.Builder(STRING_FIELD_NAME, true)
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "guinea")))
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "guinea")))
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "pig"))).build(),
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "pig"))).build(),
|
||||||
new SpanTermQuery(new Term(STRING_FIELD_NAME, "cavy"))))
|
new SpanTermQuery(new Term(STRING_FIELD_NAME, "cavy"))))
|
||||||
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "smells")))
|
.addClause(new SpanTermQuery(new Term(STRING_FIELD_NAME, "smells")))
|
||||||
.setSlop(2)
|
.setSlop(2)
|
||||||
.build(),
|
|
||||||
Occur.SHOULD)
|
|
||||||
.build();
|
.build();
|
||||||
|
expectedQuery = new DisjunctionMaxQuery(Collections.singletonList(nearQuery), 1.0f);
|
||||||
assertThat(query, Matchers.equalTo(expectedQuery));
|
assertThat(query, Matchers.equalTo(expectedQuery));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
|
import org.apache.lucene.search.DisjunctionMaxQuery;
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
|
@ -47,6 +48,7 @@ import java.util.Set;
|
||||||
import static org.hamcrest.Matchers.anyOf;
|
import static org.hamcrest.Matchers.anyOf;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -211,7 +213,7 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
// the remaining tests requires either a mapping that we register with types in base test setup
|
// the remaining tests requires either a mapping that we register with types in base test setup
|
||||||
if (getCurrentTypes().length > 0) {
|
if (getCurrentTypes().length > 0) {
|
||||||
Query luceneQuery = queryBuilder.toQuery(shardContext);
|
Query luceneQuery = queryBuilder.toQuery(shardContext);
|
||||||
assertThat(luceneQuery, instanceOf(BooleanQuery.class));
|
assertThat(luceneQuery, anyOf(instanceOf(BooleanQuery.class), instanceOf(DisjunctionMaxQuery.class)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,30 +231,39 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
if ("".equals(queryBuilder.value())) {
|
if ("".equals(queryBuilder.value())) {
|
||||||
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
||||||
} else if (queryBuilder.fields().size() > 1) {
|
} else if (queryBuilder.fields().size() > 1) {
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
assertThat(query, anyOf(instanceOf(BooleanQuery.class), instanceOf(DisjunctionMaxQuery.class)));
|
||||||
BooleanQuery boolQuery = (BooleanQuery) query;
|
if (query instanceof BooleanQuery) {
|
||||||
for (BooleanClause clause : boolQuery.clauses()) {
|
BooleanQuery boolQuery = (BooleanQuery) query;
|
||||||
if (clause.getQuery() instanceof TermQuery) {
|
for (BooleanClause clause : boolQuery.clauses()) {
|
||||||
TermQuery inner = (TermQuery) clause.getQuery();
|
if (clause.getQuery() instanceof TermQuery) {
|
||||||
assertThat(inner.getTerm().bytes().toString(), is(inner.getTerm().bytes().toString().toLowerCase(Locale.ROOT)));
|
TermQuery inner = (TermQuery) clause.getQuery();
|
||||||
|
assertThat(inner.getTerm().bytes().toString(), is(inner.getTerm().bytes().toString().toLowerCase(Locale.ROOT)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThat(boolQuery.clauses().size(), equalTo(queryBuilder.fields().size()));
|
||||||
|
Iterator<Map.Entry<String, Float>> fieldsIterator = queryBuilder.fields().entrySet().iterator();
|
||||||
|
for (BooleanClause booleanClause : boolQuery) {
|
||||||
|
Map.Entry<String, Float> field = fieldsIterator.next();
|
||||||
|
assertTermOrBoostQuery(booleanClause.getQuery(), field.getKey(), queryBuilder.value(), field.getValue());
|
||||||
|
}
|
||||||
|
if (queryBuilder.minimumShouldMatch() != null) {
|
||||||
|
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
|
||||||
|
}
|
||||||
|
} else if (query instanceof DisjunctionMaxQuery) {
|
||||||
|
DisjunctionMaxQuery maxQuery = (DisjunctionMaxQuery) query;
|
||||||
|
for (Query disjunct : maxQuery.getDisjuncts()) {
|
||||||
|
if (disjunct instanceof TermQuery) {
|
||||||
|
TermQuery inner = (TermQuery) disjunct;
|
||||||
|
assertThat(inner.getTerm().bytes().toString(), is(inner.getTerm().bytes().toString().toLowerCase(Locale.ROOT)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThat(maxQuery.getDisjuncts().size(), equalTo(queryBuilder.fields().size()));
|
||||||
|
Iterator<Map.Entry<String, Float>> fieldsIterator = queryBuilder.fields().entrySet().iterator();
|
||||||
|
for (Query disjunct : maxQuery) {
|
||||||
|
Map.Entry<String, Float> field = fieldsIterator.next();
|
||||||
|
assertTermOrBoostQuery(disjunct, field.getKey(), queryBuilder.value(), field.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertThat(boolQuery.clauses().size(), equalTo(queryBuilder.fields().size()));
|
|
||||||
Iterator<Map.Entry<String, Float>> fieldsIterator = queryBuilder.fields().entrySet().iterator();
|
|
||||||
for (BooleanClause booleanClause : boolQuery) {
|
|
||||||
Map.Entry<String, Float> field = fieldsIterator.next();
|
|
||||||
assertTermOrBoostQuery(booleanClause.getQuery(), field.getKey(), queryBuilder.value(), field.getValue());
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* TODO:
|
|
||||||
* Test disabled because we cannot check min should match consistently:
|
|
||||||
* https://github.com/elastic/elasticsearch/issues/23966
|
|
||||||
*
|
|
||||||
if (queryBuilder.minimumShouldMatch() != null && !boolQuery.isCoordDisabled()) {
|
|
||||||
assertThat(boolQuery.getMinimumNumberShouldMatch(), greaterThan(0));
|
|
||||||
}
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
} else if (queryBuilder.fields().size() == 1) {
|
} else if (queryBuilder.fields().size() == 1) {
|
||||||
Map.Entry<String, Float> field = queryBuilder.fields().entrySet().iterator().next();
|
Map.Entry<String, Float> field = queryBuilder.fields().entrySet().iterator().next();
|
||||||
assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue());
|
assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue());
|
||||||
|
@ -261,7 +272,8 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
if (ms.allEnabled()) {
|
if (ms.allEnabled()) {
|
||||||
assertTermQuery(query, MetaData.ALL, queryBuilder.value());
|
assertTermQuery(query, MetaData.ALL, queryBuilder.value());
|
||||||
} else {
|
} else {
|
||||||
assertThat(query.getClass(), anyOf(equalTo(BooleanQuery.class), equalTo(MatchNoDocsQuery.class)));
|
assertThat(query.getClass(),
|
||||||
|
anyOf(equalTo(BooleanQuery.class), equalTo(DisjunctionMaxQuery.class), equalTo(MatchNoDocsQuery.class)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fail("Encountered lucene query type we do not have a validation implementation for in our "
|
fail("Encountered lucene query type we do not have a validation implementation for in our "
|
||||||
|
@ -337,7 +349,6 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
assertEquals(json, ".quote", parsed.quoteFieldSuffix());
|
assertEquals(json, ".quote", parsed.quoteFieldSuffix());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AwaitsFix(bugUrl = "Waiting on fix for minimumShouldMatch https://github.com/elastic/elasticsearch/issues/23966")
|
|
||||||
public void testMinimumShouldMatch() throws IOException {
|
public void testMinimumShouldMatch() throws IOException {
|
||||||
QueryShardContext shardContext = createShardContext();
|
QueryShardContext shardContext = createShardContext();
|
||||||
int numberOfTerms = randomIntBetween(1, 4);
|
int numberOfTerms = randomIntBetween(1, 4);
|
||||||
|
@ -360,12 +371,13 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
// check special case: one term & one field should get simplified to a TermQuery
|
// check special case: one term & one field should get simplified to a TermQuery
|
||||||
if (numberOfFields * numberOfTerms == 1) {
|
if (numberOfFields * numberOfTerms == 1) {
|
||||||
assertThat(query, instanceOf(TermQuery.class));
|
assertThat(query, instanceOf(TermQuery.class));
|
||||||
|
} else if (numberOfTerms == 1) {
|
||||||
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
} else {
|
} else {
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
assertThat(query, instanceOf(BooleanQuery.class));
|
||||||
BooleanQuery boolQuery = (BooleanQuery) query;
|
BooleanQuery boolQuery = (BooleanQuery) query;
|
||||||
int expectedMinimumShouldMatch = numberOfTerms * percent / 100;
|
int expectedMinimumShouldMatch = numberOfTerms * percent / 100;
|
||||||
if (numberOfTerms == 1
|
if (simpleQueryStringBuilder.defaultOperator().equals(Operator.AND)) {
|
||||||
|| simpleQueryStringBuilder.defaultOperator().equals(Operator.AND)) {
|
|
||||||
expectedMinimumShouldMatch = 0;
|
expectedMinimumShouldMatch = 0;
|
||||||
}
|
}
|
||||||
assertEquals(expectedMinimumShouldMatch, boolQuery.getMinimumNumberShouldMatch());
|
assertEquals(expectedMinimumShouldMatch, boolQuery.getMinimumNumberShouldMatch());
|
||||||
|
|
|
@ -93,13 +93,14 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
||||||
Query parsedQuery = multiMatchQuery("banon").field("name.first", 2).field("name.last", 3).field("foobar").type(MultiMatchQueryBuilder.Type.CROSS_FIELDS).toQuery(queryShardContext);
|
Query parsedQuery = multiMatchQuery("banon").field("name.first", 2).field("name.last", 3).field("foobar").type(MultiMatchQueryBuilder.Type.CROSS_FIELDS).toQuery(queryShardContext);
|
||||||
try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
|
try (Engine.Searcher searcher = indexService.getShard(0).acquireSearcher("test")) {
|
||||||
Query rewrittenQuery = searcher.searcher().rewrite(parsedQuery);
|
Query rewrittenQuery = searcher.searcher().rewrite(parsedQuery);
|
||||||
|
|
||||||
BooleanQuery.Builder expected = new BooleanQuery.Builder();
|
|
||||||
expected.add(new TermQuery(new Term("foobar", "banon")), BooleanClause.Occur.SHOULD);
|
|
||||||
Query tq1 = new BoostQuery(new TermQuery(new Term("name.first", "banon")), 2);
|
Query tq1 = new BoostQuery(new TermQuery(new Term("name.first", "banon")), 2);
|
||||||
Query tq2 = new BoostQuery(new TermQuery(new Term("name.last", "banon")), 3);
|
Query tq2 = new BoostQuery(new TermQuery(new Term("name.last", "banon")), 3);
|
||||||
expected.add(new DisjunctionMaxQuery(Arrays.<Query>asList(tq1, tq2), 0f), BooleanClause.Occur.SHOULD);
|
Query expected = new DisjunctionMaxQuery(
|
||||||
assertEquals(expected.build(), rewrittenQuery);
|
Arrays.asList(
|
||||||
|
new TermQuery(new Term("foobar", "banon")),
|
||||||
|
new DisjunctionMaxQuery(Arrays.asList(tq1, tq2), 0f)
|
||||||
|
), 0f);
|
||||||
|
assertEquals(expected, rewrittenQuery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
||||||
ft2.setName("bar");
|
ft2.setName("bar");
|
||||||
Term[] terms = new Term[] { new Term("foo", "baz"), new Term("bar", "baz") };
|
Term[] terms = new Term[] { new Term("foo", "baz"), new Term("bar", "baz") };
|
||||||
float[] boosts = new float[] {2, 3};
|
float[] boosts = new float[] {2, 3};
|
||||||
Query expected = BlendedTermQuery.booleanBlendedQuery(terms, boosts);
|
Query expected = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||||
Query actual = MultiMatchQuery.blendTerm(
|
Query actual = MultiMatchQuery.blendTerm(
|
||||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
||||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||||
|
@ -126,7 +127,7 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
||||||
ft2.setBoost(10);
|
ft2.setBoost(10);
|
||||||
Term[] terms = new Term[] { new Term("foo", "baz"), new Term("bar", "baz") };
|
Term[] terms = new Term[] { new Term("foo", "baz"), new Term("bar", "baz") };
|
||||||
float[] boosts = new float[] {200, 30};
|
float[] boosts = new float[] {200, 30};
|
||||||
Query expected = BlendedTermQuery.booleanBlendedQuery(terms, boosts);
|
Query expected = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||||
Query actual = MultiMatchQuery.blendTerm(
|
Query actual = MultiMatchQuery.blendTerm(
|
||||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
||||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||||
|
@ -145,7 +146,7 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
||||||
ft2.setName("bar");
|
ft2.setName("bar");
|
||||||
Term[] terms = new Term[] { new Term("foo", "baz") };
|
Term[] terms = new Term[] { new Term("foo", "baz") };
|
||||||
float[] boosts = new float[] {2};
|
float[] boosts = new float[] {2};
|
||||||
Query expected = BlendedTermQuery.booleanBlendedQuery(terms, boosts);
|
Query expected = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||||
Query actual = MultiMatchQuery.blendTerm(
|
Query actual = MultiMatchQuery.blendTerm(
|
||||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
||||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||||
|
@ -164,12 +165,13 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
||||||
ft2.setName("bar");
|
ft2.setName("bar");
|
||||||
Term[] terms = new Term[] { new Term("foo", "baz") };
|
Term[] terms = new Term[] { new Term("foo", "baz") };
|
||||||
float[] boosts = new float[] {2};
|
float[] boosts = new float[] {2};
|
||||||
Query expectedClause1 = BlendedTermQuery.booleanBlendedQuery(terms, boosts);
|
Query expectedDisjunct1 = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||||
Query expectedClause2 = new BoostQuery(new MatchAllDocsQuery(), 3);
|
Query expectedDisjunct2 = new BoostQuery(new MatchAllDocsQuery(), 3);
|
||||||
Query expected = new BooleanQuery.Builder()
|
Query expected = new DisjunctionMaxQuery(
|
||||||
.add(expectedClause1, Occur.SHOULD)
|
Arrays.asList(
|
||||||
.add(expectedClause2, Occur.SHOULD)
|
expectedDisjunct2,
|
||||||
.build();
|
expectedDisjunct1
|
||||||
|
), 1.0f);
|
||||||
Query actual = MultiMatchQuery.blendTerm(
|
Query actual = MultiMatchQuery.blendTerm(
|
||||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }),
|
||||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||||
|
|
|
@ -120,7 +120,6 @@ public class SimpleQueryStringIT extends ESIntegTestCase {
|
||||||
assertSearchHits(searchResponse, "5", "6");
|
assertSearchHits(searchResponse, "5", "6");
|
||||||
}
|
}
|
||||||
|
|
||||||
@AwaitsFix(bugUrl="https://github.com/elastic/elasticsearch/issues/23966")
|
|
||||||
public void testSimpleQueryStringMinimumShouldMatch() throws Exception {
|
public void testSimpleQueryStringMinimumShouldMatch() throws Exception {
|
||||||
createIndex("test");
|
createIndex("test");
|
||||||
ensureGreen("test");
|
ensureGreen("test");
|
||||||
|
|
|
@ -244,8 +244,8 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
|
||||||
commonTermsQuery.add(new Term("field", "fox"));
|
commonTermsQuery.add(new Term("field", "fox"));
|
||||||
addQuery(commonTermsQuery, documents);
|
addQuery(commonTermsQuery, documents);
|
||||||
|
|
||||||
BlendedTermQuery blendedTermQuery = BlendedTermQuery.booleanBlendedQuery(new Term[]{new Term("field", "quick"),
|
BlendedTermQuery blendedTermQuery = BlendedTermQuery.dismaxBlendedQuery(new Term[]{new Term("field", "quick"),
|
||||||
new Term("field", "brown"), new Term("field", "fox")});
|
new Term("field", "brown"), new Term("field", "fox")}, 1.0f);
|
||||||
addQuery(blendedTermQuery, documents);
|
addQuery(blendedTermQuery, documents);
|
||||||
|
|
||||||
SpanNearQuery spanNearQuery = new SpanNearQuery.Builder("field", true)
|
SpanNearQuery spanNearQuery = new SpanNearQuery.Builder("field", true)
|
||||||
|
|
|
@ -276,7 +276,7 @@ public class QueryAnalyzerTests extends ESTestCase {
|
||||||
|
|
||||||
public void testExtractQueryMetadata_blendedTermQuery() {
|
public void testExtractQueryMetadata_blendedTermQuery() {
|
||||||
Term[] termsArr = new Term[]{new Term("_field", "_term1"), new Term("_field", "_term2")};
|
Term[] termsArr = new Term[]{new Term("_field", "_term1"), new Term("_field", "_term2")};
|
||||||
BlendedTermQuery commonTermsQuery = BlendedTermQuery.booleanBlendedQuery(termsArr);
|
BlendedTermQuery commonTermsQuery = BlendedTermQuery.dismaxBlendedQuery(termsArr, 1.0f);
|
||||||
Result result = analyze(commonTermsQuery);
|
Result result = analyze(commonTermsQuery);
|
||||||
assertThat(result.verified, is(true));
|
assertThat(result.verified, is(true));
|
||||||
List<Term> terms = new ArrayList<>(result.terms);
|
List<Term> terms = new ArrayList<>(result.terms);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.elasticsearch.test.hamcrest;
|
package org.elasticsearch.test.hamcrest;
|
||||||
|
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
|
import org.apache.lucene.search.DisjunctionMaxQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.ExceptionsHelper;
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
|
@ -515,6 +516,14 @@ public class ElasticsearchAssertions {
|
||||||
return subqueryType.cast(q.clauses().get(i).getQuery());
|
return subqueryType.cast(q.clauses().get(i).getQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T extends Query> T assertDisjunctionSubQuery(Query query, Class<T> subqueryType, int i) {
|
||||||
|
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
|
||||||
|
DisjunctionMaxQuery q = (DisjunctionMaxQuery) query;
|
||||||
|
assertThat(q.getDisjuncts().size(), greaterThan(i));
|
||||||
|
assertThat(q.getDisjuncts().get(i), instanceOf(subqueryType));
|
||||||
|
return subqueryType.cast(q.getDisjuncts().get(i));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the request from a given builder and check that it throws an exception of the right type
|
* Run the request from a given builder and check that it throws an exception of the right type
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue