Currently `match_phrase_prefix` doesn't support `zero_terms_query` like the other match-type queries. This change adds this support. Closes #58468
This commit is contained in:
parent
6ccf3548e7
commit
f4ff5fe93b
|
@ -21,6 +21,7 @@ package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
@ -28,6 +29,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.search.MatchQuery;
|
import org.elasticsearch.index.search.MatchQuery;
|
||||||
|
import org.elasticsearch.index.search.MatchQuery.ZeroTermsQuery;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -39,6 +41,7 @@ import java.util.Objects;
|
||||||
public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhrasePrefixQueryBuilder> {
|
public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhrasePrefixQueryBuilder> {
|
||||||
public static final String NAME = "match_phrase_prefix";
|
public static final String NAME = "match_phrase_prefix";
|
||||||
public static final ParseField MAX_EXPANSIONS_FIELD = new ParseField("max_expansions");
|
public static final ParseField MAX_EXPANSIONS_FIELD = new ParseField("max_expansions");
|
||||||
|
public static final ParseField ZERO_TERMS_QUERY_FIELD = new ParseField("zero_terms_query");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String fieldName;
|
||||||
|
|
||||||
|
@ -50,6 +53,8 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
|
|
||||||
private int maxExpansions = FuzzyQuery.defaultMaxExpansions;
|
private int maxExpansions = FuzzyQuery.defaultMaxExpansions;
|
||||||
|
|
||||||
|
private ZeroTermsQuery zeroTermsQuery = MatchQuery.DEFAULT_ZERO_TERMS_QUERY;
|
||||||
|
|
||||||
public MatchPhrasePrefixQueryBuilder(String fieldName, Object value) {
|
public MatchPhrasePrefixQueryBuilder(String fieldName, Object value) {
|
||||||
if (fieldName == null) {
|
if (fieldName == null) {
|
||||||
throw new IllegalArgumentException("[" + NAME + "] requires fieldName");
|
throw new IllegalArgumentException("[" + NAME + "] requires fieldName");
|
||||||
|
@ -71,6 +76,9 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
slop = in.readVInt();
|
slop = in.readVInt();
|
||||||
maxExpansions = in.readVInt();
|
maxExpansions = in.readVInt();
|
||||||
analyzer = in.readOptionalString();
|
analyzer = in.readOptionalString();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
this.zeroTermsQuery = ZeroTermsQuery.readFromStream(in);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,6 +88,9 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
out.writeVInt(slop);
|
out.writeVInt(slop);
|
||||||
out.writeVInt(maxExpansions);
|
out.writeVInt(maxExpansions);
|
||||||
out.writeOptionalString(analyzer);
|
out.writeOptionalString(analyzer);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
|
||||||
|
zeroTermsQuery.writeTo(out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the field name used in this query. */
|
/** Returns the field name used in this query. */
|
||||||
|
@ -139,6 +150,23 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
return this.maxExpansions;
|
return this.maxExpansions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets query to use in case no query terms are available, e.g. after analysis removed them.
|
||||||
|
* Defaults to {@link ZeroTermsQuery#NONE}, but can be set to
|
||||||
|
* {@link ZeroTermsQuery#ALL} instead.
|
||||||
|
*/
|
||||||
|
public MatchPhrasePrefixQueryBuilder zeroTermsQuery(ZeroTermsQuery zeroTermsQuery) {
|
||||||
|
if (zeroTermsQuery == null) {
|
||||||
|
throw new IllegalArgumentException("[" + NAME + "] requires zeroTermsQuery to be non-null");
|
||||||
|
}
|
||||||
|
this.zeroTermsQuery = zeroTermsQuery;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZeroTermsQuery zeroTermsQuery() {
|
||||||
|
return this.zeroTermsQuery;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
|
@ -155,6 +183,7 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
}
|
}
|
||||||
builder.field(MatchPhraseQueryBuilder.SLOP_FIELD.getPreferredName(), slop);
|
builder.field(MatchPhraseQueryBuilder.SLOP_FIELD.getPreferredName(), slop);
|
||||||
builder.field(MAX_EXPANSIONS_FIELD.getPreferredName(), maxExpansions);
|
builder.field(MAX_EXPANSIONS_FIELD.getPreferredName(), maxExpansions);
|
||||||
|
builder.field(ZERO_TERMS_QUERY_FIELD.getPreferredName(), zeroTermsQuery.toString());
|
||||||
printBoostAndQueryName(builder);
|
printBoostAndQueryName(builder);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
@ -173,6 +202,7 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
}
|
}
|
||||||
matchQuery.setPhraseSlop(slop);
|
matchQuery.setPhraseSlop(slop);
|
||||||
matchQuery.setMaxExpansions(maxExpansions);
|
matchQuery.setMaxExpansions(maxExpansions);
|
||||||
|
matchQuery.setZeroTermsQuery(zeroTermsQuery);
|
||||||
|
|
||||||
return matchQuery.parse(MatchQuery.Type.PHRASE_PREFIX, fieldName, value);
|
return matchQuery.parse(MatchQuery.Type.PHRASE_PREFIX, fieldName, value);
|
||||||
}
|
}
|
||||||
|
@ -183,12 +213,13 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
Objects.equals(value, other.value) &&
|
Objects.equals(value, other.value) &&
|
||||||
Objects.equals(analyzer, other.analyzer)&&
|
Objects.equals(analyzer, other.analyzer)&&
|
||||||
Objects.equals(slop, other.slop) &&
|
Objects.equals(slop, other.slop) &&
|
||||||
Objects.equals(maxExpansions, other.maxExpansions);
|
Objects.equals(maxExpansions, other.maxExpansions) &&
|
||||||
|
Objects.equals(zeroTermsQuery, other.zeroTermsQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int doHashCode() {
|
protected int doHashCode() {
|
||||||
return Objects.hash(fieldName, value, analyzer, slop, maxExpansions);
|
return Objects.hash(fieldName, value, analyzer, slop, maxExpansions, zeroTermsQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MatchPhrasePrefixQueryBuilder fromXContent(XContentParser parser) throws IOException {
|
public static MatchPhrasePrefixQueryBuilder fromXContent(XContentParser parser) throws IOException {
|
||||||
|
@ -201,6 +232,7 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
|
ZeroTermsQuery zeroTermsQuery = MatchQuery.DEFAULT_ZERO_TERMS_QUERY;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
|
@ -223,6 +255,16 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
maxExpansion = parser.intValue();
|
maxExpansion = parser.intValue();
|
||||||
} else if (AbstractQueryBuilder.NAME_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (AbstractQueryBuilder.NAME_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
queryName = parser.text();
|
queryName = parser.text();
|
||||||
|
} else if (ZERO_TERMS_QUERY_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
|
String zeroTermsValue = parser.text();
|
||||||
|
if ("none".equalsIgnoreCase(zeroTermsValue)) {
|
||||||
|
zeroTermsQuery = ZeroTermsQuery.NONE;
|
||||||
|
} else if ("all".equalsIgnoreCase(zeroTermsValue)) {
|
||||||
|
zeroTermsQuery = ZeroTermsQuery.ALL;
|
||||||
|
} else {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
|
"Unsupported zero_terms_query value [" + zeroTermsValue + "]");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(),
|
throw new ParsingException(parser.getTokenLocation(),
|
||||||
"[" + NAME + "] query does not support [" + currentFieldName + "]");
|
"[" + NAME + "] query does not support [" + currentFieldName + "]");
|
||||||
|
@ -245,6 +287,7 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr
|
||||||
matchQuery.maxExpansions(maxExpansion);
|
matchQuery.maxExpansions(maxExpansion);
|
||||||
matchQuery.queryName(queryName);
|
matchQuery.queryName(queryName);
|
||||||
matchQuery.boost(boost);
|
matchQuery.boost(boost);
|
||||||
|
matchQuery.zeroTermsQuery(zeroTermsQuery);
|
||||||
return matchQuery;
|
return matchQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.SynonymQuery;
|
import org.apache.lucene.search.SynonymQuery;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
||||||
|
import org.elasticsearch.index.search.MatchQuery.ZeroTermsQuery;
|
||||||
import org.elasticsearch.test.AbstractQueryTestCase;
|
import org.elasticsearch.test.AbstractQueryTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -33,6 +35,7 @@ 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;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
|
||||||
public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<MatchPhrasePrefixQueryBuilder> {
|
public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<MatchPhrasePrefixQueryBuilder> {
|
||||||
|
@ -64,6 +67,9 @@ public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<Ma
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
matchQuery.maxExpansions(randomIntBetween(1, 10000));
|
matchQuery.maxExpansions(randomIntBetween(1, 10000));
|
||||||
}
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
matchQuery.zeroTermsQuery(randomFrom(ZeroTermsQuery.ALL, ZeroTermsQuery.NONE));
|
||||||
|
}
|
||||||
return matchQuery;
|
return matchQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +91,12 @@ public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<Ma
|
||||||
protected void doAssertLuceneQuery(MatchPhrasePrefixQueryBuilder queryBuilder, Query query, QueryShardContext context)
|
protected void doAssertLuceneQuery(MatchPhrasePrefixQueryBuilder queryBuilder, Query query, QueryShardContext context)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
assertThat(query, notNullValue());
|
assertThat(query, notNullValue());
|
||||||
|
|
||||||
|
if (query instanceof MatchAllDocsQuery) {
|
||||||
|
assertThat(queryBuilder.zeroTermsQuery(), equalTo(ZeroTermsQuery.ALL));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assertThat(query, either(instanceOf(MultiPhrasePrefixQuery.class))
|
assertThat(query, either(instanceOf(MultiPhrasePrefixQuery.class))
|
||||||
.or(instanceOf(SynonymQuery.class))
|
.or(instanceOf(SynonymQuery.class))
|
||||||
.or(instanceOf(MatchNoDocsQuery.class)));
|
.or(instanceOf(MatchNoDocsQuery.class)));
|
||||||
|
@ -115,6 +127,16 @@ public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<Ma
|
||||||
expectThrows(IllegalStateException.class, () -> matchQuery.doToQuery(createShardContext()));
|
expectThrows(IllegalStateException.class, () -> matchQuery.doToQuery(createShardContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPhrasePrefixZeroTermsQuery() throws IOException {
|
||||||
|
MatchPhrasePrefixQueryBuilder matchQuery = new MatchPhrasePrefixQueryBuilder(TEXT_FIELD_NAME, "");
|
||||||
|
matchQuery.zeroTermsQuery(ZeroTermsQuery.NONE);
|
||||||
|
assertEquals(new MatchNoDocsQuery(), matchQuery.doToQuery(createShardContext()));
|
||||||
|
|
||||||
|
matchQuery = new MatchPhrasePrefixQueryBuilder(TEXT_FIELD_NAME, "");
|
||||||
|
matchQuery.zeroTermsQuery(ZeroTermsQuery.ALL);
|
||||||
|
assertEquals(new MatchAllDocsQuery(), matchQuery.doToQuery(createShardContext()));
|
||||||
|
}
|
||||||
|
|
||||||
public void testPhrasePrefixMatchQuery() throws IOException {
|
public void testPhrasePrefixMatchQuery() throws IOException {
|
||||||
String json1 = "{\n" +
|
String json1 = "{\n" +
|
||||||
" \"match_phrase_prefix\" : {\n" +
|
" \"match_phrase_prefix\" : {\n" +
|
||||||
|
@ -128,6 +150,7 @@ public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<Ma
|
||||||
" \"query\" : \"this is a test\",\n" +
|
" \"query\" : \"this is a test\",\n" +
|
||||||
" \"slop\" : 0,\n" +
|
" \"slop\" : 0,\n" +
|
||||||
" \"max_expansions\" : 50,\n" +
|
" \"max_expansions\" : 50,\n" +
|
||||||
|
" \"zero_terms_query\" : \"NONE\",\n" +
|
||||||
" \"boost\" : 1.0\n" +
|
" \"boost\" : 1.0\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
|
@ -149,6 +172,7 @@ public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<Ma
|
||||||
" \"query\" : \"this is a test\",\n" +
|
" \"query\" : \"this is a test\",\n" +
|
||||||
" \"slop\" : 0,\n" +
|
" \"slop\" : 0,\n" +
|
||||||
" \"max_expansions\" : 10,\n" +
|
" \"max_expansions\" : 10,\n" +
|
||||||
|
" \"zero_terms_query\" : \"NONE\",\n" +
|
||||||
" \"boost\" : 1.0\n" +
|
" \"boost\" : 1.0\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
|
|
Loading…
Reference in New Issue