Merge pull request #19665 from cbuescher/missing-field-MultiMatchQuery
`multi_match` query should produce MatchNoDocs query on unknown field
This commit is contained in:
commit
87a4995bed
|
@ -745,11 +745,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
|
||||||
|
|
||||||
Map<String, Float> newFieldsBoosts = handleFieldsMatchPattern(context.getMapperService(), fieldsBoosts);
|
Map<String, Float> newFieldsBoosts = handleFieldsMatchPattern(context.getMapperService(), fieldsBoosts);
|
||||||
|
|
||||||
Query query = multiMatchQuery.parse(type, newFieldsBoosts, value, minimumShouldMatch);
|
return multiMatchQuery.parse(type, newFieldsBoosts, value, minimumShouldMatch);
|
||||||
if (query == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return query;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Float> handleFieldsMatchPattern(MapperService mapperService, Map<String, Float> fieldsBoosts) {
|
private static Map<String, Float> handleFieldsMatchPattern(MapperService mapperService, Map<String, Float> fieldsBoosts) {
|
||||||
|
|
|
@ -280,7 +280,6 @@ public class MatchQuery {
|
||||||
if (zeroTermsQuery == DEFAULT_ZERO_TERMS_QUERY) {
|
if (zeroTermsQuery == DEFAULT_ZERO_TERMS_QUERY) {
|
||||||
return Queries.newMatchNoDocsQuery("Matching no documents because no terms present.");
|
return Queries.newMatchNoDocsQuery("Matching no documents because no terms present.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Queries.newMatchAllQuery();
|
return Queries.newMatchAllQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,15 @@ 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;
|
||||||
|
import org.apache.lucene.search.BooleanClause.Occur;
|
||||||
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.DisjunctionMaxQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.apache.lucene.search.BooleanClause.Occur;
|
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.common.lucene.search.MatchNoDocsQuery;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.query.AbstractQueryBuilder;
|
import org.elasticsearch.index.query.AbstractQueryBuilder;
|
||||||
|
@ -72,28 +73,31 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query parse(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException {
|
public Query parse(MultiMatchQueryBuilder.Type type, Map<String, Float> fieldNames, Object value, String minimumShouldMatch) throws IOException {
|
||||||
|
Query result;
|
||||||
if (fieldNames.size() == 1) {
|
if (fieldNames.size() == 1) {
|
||||||
Map.Entry<String, Float> fieldBoost = fieldNames.entrySet().iterator().next();
|
Map.Entry<String, Float> fieldBoost = fieldNames.entrySet().iterator().next();
|
||||||
Float boostValue = fieldBoost.getValue();
|
Float boostValue = fieldBoost.getValue();
|
||||||
return parseAndApply(type.matchQueryType(), fieldBoost.getKey(), value, minimumShouldMatch, boostValue);
|
result = parseAndApply(type.matchQueryType(), fieldBoost.getKey(), value, minimumShouldMatch, boostValue);
|
||||||
|
} else {
|
||||||
|
final float tieBreaker = groupTieBreaker == null ? type.tieBreaker() : groupTieBreaker;
|
||||||
|
switch (type) {
|
||||||
|
case PHRASE:
|
||||||
|
case PHRASE_PREFIX:
|
||||||
|
case BEST_FIELDS:
|
||||||
|
case MOST_FIELDS:
|
||||||
|
queryBuilder = new QueryBuilder(tieBreaker);
|
||||||
|
break;
|
||||||
|
case CROSS_FIELDS:
|
||||||
|
queryBuilder = new CrossFieldsQueryBuilder(tieBreaker);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("No such type: " + type);
|
||||||
|
}
|
||||||
|
final List<? extends Query> queries = queryBuilder.buildGroupedQueries(type, fieldNames, value, minimumShouldMatch);
|
||||||
|
result = queryBuilder.combineGrouped(queries);
|
||||||
}
|
}
|
||||||
|
assert result != null;
|
||||||
final float tieBreaker = groupTieBreaker == null ? type.tieBreaker() : groupTieBreaker;
|
return result;
|
||||||
switch (type) {
|
|
||||||
case PHRASE:
|
|
||||||
case PHRASE_PREFIX:
|
|
||||||
case BEST_FIELDS:
|
|
||||||
case MOST_FIELDS:
|
|
||||||
queryBuilder = new QueryBuilder(tieBreaker);
|
|
||||||
break;
|
|
||||||
case CROSS_FIELDS:
|
|
||||||
queryBuilder = new CrossFieldsQueryBuilder(tieBreaker);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("No such type: " + type);
|
|
||||||
}
|
|
||||||
final List<? extends Query> queries = queryBuilder.buildGroupedQueries(type, fieldNames, value, minimumShouldMatch);
|
|
||||||
return queryBuilder.combineGrouped(queries);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryBuilder queryBuilder;
|
private QueryBuilder queryBuilder;
|
||||||
|
@ -127,9 +131,9 @@ public class MultiMatchQuery extends MatchQuery {
|
||||||
return parseAndApply(type, field, value, minimumShouldMatch, boostValue);
|
return parseAndApply(type, field, value, minimumShouldMatch, boostValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query combineGrouped(List<? extends Query> groupQuery) {
|
private Query combineGrouped(List<? extends Query> groupQuery) {
|
||||||
if (groupQuery == null || groupQuery.isEmpty()) {
|
if (groupQuery == null || groupQuery.isEmpty()) {
|
||||||
return null;
|
return new MatchNoDocsQuery("[multi_match] list of group queries was empty");
|
||||||
}
|
}
|
||||||
if (groupQuery.size() == 1) {
|
if (groupQuery.size() == 1) {
|
||||||
return groupQuery.get(0);
|
return groupQuery.get(0);
|
||||||
|
|
|
@ -53,12 +53,17 @@ import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
|
||||||
public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatchQueryBuilder> {
|
public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatchQueryBuilder> {
|
||||||
|
|
||||||
|
private static final String MISSING_WILDCARD_FIELD_NAME = "missing_*";
|
||||||
|
private static final String MISSING_FIELD_NAME = "missing";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MultiMatchQueryBuilder doCreateTestQueryBuilder() {
|
protected MultiMatchQueryBuilder doCreateTestQueryBuilder() {
|
||||||
String fieldName = randomFrom(STRING_FIELD_NAME, INT_FIELD_NAME, DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME);
|
String fieldName = randomFrom(STRING_FIELD_NAME, INT_FIELD_NAME, DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME,
|
||||||
|
MISSING_FIELD_NAME, MISSING_WILDCARD_FIELD_NAME);
|
||||||
if (fieldName.equals(DATE_FIELD_NAME)) {
|
if (fieldName.equals(DATE_FIELD_NAME)) {
|
||||||
assumeTrue("test with date fields runs only when at least a type is registered", getCurrentTypes().length > 0);
|
assumeTrue("test with date fields runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates the query with random value and field name
|
// creates the query with random value and field name
|
||||||
Object value;
|
Object value;
|
||||||
if (fieldName.equals(STRING_FIELD_NAME)) {
|
if (fieldName.equals(STRING_FIELD_NAME)) {
|
||||||
|
@ -238,6 +243,12 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
|
||||||
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testToQueryFieldMissing() throws Exception {
|
||||||
|
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
|
assertThat(multiMatchQuery("test").field(MISSING_WILDCARD_FIELD_NAME).toQuery(createShardContext()), instanceOf(MatchNoDocsQuery.class));
|
||||||
|
assertThat(multiMatchQuery("test").field(MISSING_FIELD_NAME).toQuery(createShardContext()), instanceOf(TermQuery.class));
|
||||||
|
}
|
||||||
|
|
||||||
public void testFromJson() throws IOException {
|
public void testFromJson() throws IOException {
|
||||||
String json =
|
String json =
|
||||||
"{\n" +
|
"{\n" +
|
||||||
|
|
|
@ -237,7 +237,8 @@ public class MultiMatchQueryIT extends ESIntegTestCase {
|
||||||
assertNoFailures(searchResponse);
|
assertNoFailures(searchResponse);
|
||||||
assertFirstHit(searchResponse, hasId("theone"));
|
assertFirstHit(searchResponse, hasId("theone"));
|
||||||
|
|
||||||
String[] fields = {"full_name", "first_name", "last_name", "last_name_phrase", "first_name_phrase", "category_phrase", "category"};
|
String[] fields = { "full_name", "first_name", "last_name", "last_name_phrase", "first_name_phrase", "category_phrase", "category",
|
||||||
|
"missing_field", "missing_fields*" };
|
||||||
|
|
||||||
String[] query = {"marvel","hero", "captain", "america", "15", "17", "1", "5", "ultimate", "Man",
|
String[] query = {"marvel","hero", "captain", "america", "15", "17", "1", "5", "ultimate", "Man",
|
||||||
"marvel", "wolferine", "ninja"};
|
"marvel", "wolferine", "ninja"};
|
||||||
|
@ -269,6 +270,9 @@ public class MultiMatchQueryIT extends ESIntegTestCase {
|
||||||
.setQuery(matchQueryBuilder).get();
|
.setQuery(matchQueryBuilder).get();
|
||||||
assertThat("field: " + field + " query: " + builder.toString(), multiMatchResp.getHits().getTotalHits(), equalTo(matchResp.getHits().getTotalHits()));
|
assertThat("field: " + field + " query: " + builder.toString(), multiMatchResp.getHits().getTotalHits(), equalTo(matchResp.getHits().getTotalHits()));
|
||||||
SearchHits hits = multiMatchResp.getHits();
|
SearchHits hits = multiMatchResp.getHits();
|
||||||
|
if (field.startsWith("missing")) {
|
||||||
|
assertEquals(0, hits.hits().length);
|
||||||
|
}
|
||||||
for (int j = 0; j < hits.hits().length; j++) {
|
for (int j = 0; j < hits.hits().length; j++) {
|
||||||
assertThat(hits.getHits()[j].score(), equalTo(matchResp.getHits().getHits()[j].score()));
|
assertThat(hits.getHits()[j].score(), equalTo(matchResp.getHits().getHits()[j].score()));
|
||||||
assertThat(hits.getHits()[j].getId(), equalTo(matchResp.getHits().getHits()[j].getId()));
|
assertThat(hits.getHits()[j].getId(), equalTo(matchResp.getHits().getHits()[j].getId()));
|
||||||
|
|
Loading…
Reference in New Issue