Throw parsing error if match query contains multiple fields
Match Query, like many other queries, used to parse even when the query referred to multiple fields and the first one would win. We rather throw an exception now instead. Also added test for short prefix query variant and modified the parsing code to consume the whole query object.
This commit is contained in:
parent
f7b3dce4bc
commit
1e45fd5850
|
@ -510,13 +510,7 @@ public class MatchQueryBuilder extends AbstractQueryBuilder<MatchQueryBuilder> {
|
||||||
|
|
||||||
public static Optional<MatchQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException {
|
public static Optional<MatchQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException {
|
||||||
XContentParser parser = parseContext.parser();
|
XContentParser parser = parseContext.parser();
|
||||||
|
String fieldName = null;
|
||||||
XContentParser.Token token = parser.nextToken();
|
|
||||||
if (token != XContentParser.Token.FIELD_NAME) {
|
|
||||||
throw new ParsingException(parser.getTokenLocation(), "[" + MatchQueryBuilder.NAME + "] query malformed, no field");
|
|
||||||
}
|
|
||||||
String fieldName = parser.currentName();
|
|
||||||
|
|
||||||
MatchQuery.Type type = MatchQuery.Type.BOOLEAN;
|
MatchQuery.Type type = MatchQuery.Type.BOOLEAN;
|
||||||
Object value = null;
|
Object value = null;
|
||||||
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
||||||
|
@ -533,80 +527,84 @@ public class MatchQueryBuilder extends AbstractQueryBuilder<MatchQueryBuilder> {
|
||||||
Float cutOffFrequency = null;
|
Float cutOffFrequency = null;
|
||||||
ZeroTermsQuery zeroTermsQuery = MatchQuery.DEFAULT_ZERO_TERMS_QUERY;
|
ZeroTermsQuery zeroTermsQuery = MatchQuery.DEFAULT_ZERO_TERMS_QUERY;
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
|
String currentFieldName = null;
|
||||||
token = parser.nextToken();
|
XContentParser.Token token;
|
||||||
if (token == XContentParser.Token.START_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
String currentFieldName = null;
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
currentFieldName = parser.currentName();
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
} else if (parseContext.isDeprecatedSetting(currentFieldName)) {
|
||||||
currentFieldName = parser.currentName();
|
// skip
|
||||||
} else if (token.isValue()) {
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
|
if (fieldName != null) {
|
||||||
value = parser.objectText();
|
throw new ParsingException(parser.getTokenLocation(), "[match] query doesn't support multiple fields, found ["
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, TYPE_FIELD)) {
|
+ fieldName + "] and [" + currentFieldName + "]");
|
||||||
String tStr = parser.text();
|
}
|
||||||
if ("boolean".equals(tStr)) {
|
fieldName = currentFieldName;
|
||||||
type = MatchQuery.Type.BOOLEAN;
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
} else if ("phrase".equals(tStr)) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
type = MatchQuery.Type.PHRASE;
|
currentFieldName = parser.currentName();
|
||||||
} else if ("phrase_prefix".equals(tStr) || ("phrasePrefix".equals(tStr))) {
|
} else if (token.isValue()) {
|
||||||
type = MatchQuery.Type.PHRASE_PREFIX;
|
if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
|
||||||
} else {
|
value = parser.objectText();
|
||||||
throw new ParsingException(parser.getTokenLocation(), "[" + NAME + "] query does not support type " + tStr);
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, TYPE_FIELD)) {
|
||||||
}
|
String tStr = parser.text();
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, ANALYZER_FIELD)) {
|
if ("boolean".equals(tStr)) {
|
||||||
analyzer = parser.text();
|
type = MatchQuery.Type.BOOLEAN;
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
|
} else if ("phrase".equals(tStr)) {
|
||||||
boost = parser.floatValue();
|
type = MatchQuery.Type.PHRASE;
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, SLOP_FIELD)) {
|
} else if ("phrase_prefix".equals(tStr) || ("phrasePrefix".equals(tStr))) {
|
||||||
slop = parser.intValue();
|
type = MatchQuery.Type.PHRASE_PREFIX;
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, Fuzziness.FIELD)) {
|
} else {
|
||||||
fuzziness = Fuzziness.parse(parser);
|
throw new ParsingException(parser.getTokenLocation(), "[" + NAME + "] query does not support type " + tStr);
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, PREFIX_LENGTH_FIELD)) {
|
}
|
||||||
prefixLength = parser.intValue();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, ANALYZER_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, MAX_EXPANSIONS_FIELD)) {
|
analyzer = parser.text();
|
||||||
maxExpansion = parser.intValue();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, OPERATOR_FIELD)) {
|
boost = parser.floatValue();
|
||||||
operator = Operator.fromString(parser.text());
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, SLOP_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, MINIMUM_SHOULD_MATCH_FIELD)) {
|
slop = parser.intValue();
|
||||||
minimumShouldMatch = parser.textOrNull();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, Fuzziness.FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, FUZZY_REWRITE_FIELD)) {
|
fuzziness = Fuzziness.parse(parser);
|
||||||
fuzzyRewrite = parser.textOrNull();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, PREFIX_LENGTH_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, FUZZY_TRANSPOSITIONS_FIELD)) {
|
prefixLength = parser.intValue();
|
||||||
fuzzyTranspositions = parser.booleanValue();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, MAX_EXPANSIONS_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, LENIENT_FIELD)) {
|
maxExpansion = parser.intValue();
|
||||||
lenient = parser.booleanValue();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, OPERATOR_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, CUTOFF_FREQUENCY_FIELD)) {
|
operator = Operator.fromString(parser.text());
|
||||||
cutOffFrequency = parser.floatValue();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, MINIMUM_SHOULD_MATCH_FIELD)) {
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, ZERO_TERMS_QUERY_FIELD)) {
|
minimumShouldMatch = parser.textOrNull();
|
||||||
String zeroTermsDocs = parser.text();
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, FUZZY_REWRITE_FIELD)) {
|
||||||
if ("none".equalsIgnoreCase(zeroTermsDocs)) {
|
fuzzyRewrite = parser.textOrNull();
|
||||||
zeroTermsQuery = MatchQuery.ZeroTermsQuery.NONE;
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, FUZZY_TRANSPOSITIONS_FIELD)) {
|
||||||
} else if ("all".equalsIgnoreCase(zeroTermsDocs)) {
|
fuzzyTranspositions = parser.booleanValue();
|
||||||
zeroTermsQuery = MatchQuery.ZeroTermsQuery.ALL;
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, LENIENT_FIELD)) {
|
||||||
|
lenient = parser.booleanValue();
|
||||||
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, CUTOFF_FREQUENCY_FIELD)) {
|
||||||
|
cutOffFrequency = parser.floatValue();
|
||||||
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, ZERO_TERMS_QUERY_FIELD)) {
|
||||||
|
String zeroTermsDocs = parser.text();
|
||||||
|
if ("none".equalsIgnoreCase(zeroTermsDocs)) {
|
||||||
|
zeroTermsQuery = MatchQuery.ZeroTermsQuery.NONE;
|
||||||
|
} else if ("all".equalsIgnoreCase(zeroTermsDocs)) {
|
||||||
|
zeroTermsQuery = MatchQuery.ZeroTermsQuery.ALL;
|
||||||
|
} else {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
|
"Unsupported zero_terms_docs value [" + zeroTermsDocs + "]");
|
||||||
|
}
|
||||||
|
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
|
||||||
|
queryName = parser.text();
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(),
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
"Unsupported zero_terms_docs value [" + zeroTermsDocs + "]");
|
"[" + NAME + "] query does not support [" + currentFieldName + "]");
|
||||||
}
|
}
|
||||||
} else if (parseContext.getParseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
|
|
||||||
queryName = parser.text();
|
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(),
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
"[" + NAME + "] query does not support [" + currentFieldName + "]");
|
"[" + NAME + "] unknown token [" + token + "] after [" + currentFieldName + "]");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
throw new ParsingException(parser.getTokenLocation(),
|
|
||||||
"[" + NAME + "] unknown token [" + token + "] after [" + currentFieldName + "]");
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
parser.nextToken();
|
fieldName = parser.currentName();
|
||||||
} else {
|
value = parser.objectText();
|
||||||
value = parser.objectText();
|
|
||||||
// move to the next token
|
|
||||||
token = parser.nextToken();
|
|
||||||
if (token != XContentParser.Token.END_OBJECT) {
|
|
||||||
throw new ParsingException(parser.getTokenLocation(), "[match] query parsed in simplified form, with direct field name, "
|
|
||||||
+ "but included more options than just the field name, possibly use its 'options' form, with 'query' element?");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.lucene.search.PointRangeQuery;
|
||||||
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.elasticsearch.common.ParseFieldMatcher;
|
import org.elasticsearch.common.ParseFieldMatcher;
|
||||||
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.lucene.search.MatchNoDocsQuery;
|
import org.elasticsearch.common.lucene.search.MatchNoDocsQuery;
|
||||||
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
|
@ -40,7 +41,9 @@ import org.elasticsearch.test.AbstractQueryTestCase;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.either;
|
import static org.hamcrest.CoreMatchers.either;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
@ -118,6 +121,19 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase<MatchQueryBuil
|
||||||
return matchQuery;
|
return matchQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, MatchQueryBuilder> getAlternateVersions() {
|
||||||
|
Map<String, MatchQueryBuilder> alternateVersions = new HashMap<>();
|
||||||
|
MatchQueryBuilder matchQuery = new MatchQueryBuilder(randomAsciiOfLengthBetween(1, 10), randomAsciiOfLengthBetween(1, 10));
|
||||||
|
String contentString = "{\n" +
|
||||||
|
" \"match\" : {\n" +
|
||||||
|
" \"" + matchQuery.fieldName() + "\" : \"" + matchQuery.value() + "\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
|
alternateVersions.put(contentString, matchQuery);
|
||||||
|
return alternateVersions;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doAssertLuceneQuery(MatchQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
protected void doAssertLuceneQuery(MatchQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||||
assertThat(query, notNullValue());
|
assertThat(query, notNullValue());
|
||||||
|
@ -406,4 +422,24 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase<MatchQueryBuil
|
||||||
query.lenient(true);
|
query.lenient(true);
|
||||||
query.toQuery(context); // no exception
|
query.toQuery(context); // no exception
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testParseFailsWithMultipleFields() throws IOException {
|
||||||
|
String json = "{\n" +
|
||||||
|
" \"match\" : {\n" +
|
||||||
|
" \"message1\" : {\n" +
|
||||||
|
" \"query\" : \"this is a test\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"message2\" : {\n" +
|
||||||
|
" \"query\" : \"this is a test\"\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
try {
|
||||||
|
parseQuery(json);
|
||||||
|
fail("parseQuery should have failed");
|
||||||
|
} catch(ParsingException e) {
|
||||||
|
assertEquals("[match] query doesn't support multiple fields, found [message1] and [message2]", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue