Skip to content

Commit b315e48

Browse files
committed
Refactors PrefixQuery
Relates to elastic#10217 Closes elastic#12032 This PR is against the query-refactoring branch.
1 parent c01eecc commit b315e48

File tree

4 files changed

+190
-45
lines changed

4 files changed

+190
-45
lines changed

core/src/main/java/org/elasticsearch/index/query/BaseTermQueryBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public QueryValidationException validate() {
147147

148148
@Override
149149
protected final int doHashCode() {
150-
return Objects.hash(getClass(), fieldName, value);
150+
return Objects.hash(fieldName, value);
151151
}
152152

153153
@Override

core/src/main/java/org/elasticsearch/index/query/PrefixQueryBuilder.java

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,20 @@
1919

2020
package org.elasticsearch.index.query;
2121

22+
import org.apache.lucene.index.Term;
23+
import org.apache.lucene.search.MultiTermQuery;
24+
import org.apache.lucene.search.PrefixQuery;
25+
import org.apache.lucene.search.Query;
26+
import org.elasticsearch.common.Strings;
27+
import org.elasticsearch.common.io.stream.StreamInput;
28+
import org.elasticsearch.common.io.stream.StreamOutput;
29+
import org.elasticsearch.common.lucene.BytesRefs;
2230
import org.elasticsearch.common.xcontent.XContentBuilder;
31+
import org.elasticsearch.index.mapper.MappedFieldType;
32+
import org.elasticsearch.index.query.support.QueryParsers;
2333

2434
import java.io.IOException;
35+
import java.util.Objects;
2536

2637
/**
2738
* A Query that matches documents containing terms with a specified prefix.
@@ -30,35 +41,47 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
3041

3142
public static final String NAME = "prefix";
3243

33-
private final String name;
34-
35-
private final String prefix;
36-
44+
private final String fieldName;
45+
46+
private final String value;
47+
3748
private String rewrite;
3849

3950
static final PrefixQueryBuilder PROTOTYPE = new PrefixQueryBuilder(null, null);
4051

4152
/**
4253
* A Query that matches documents containing terms with a specified prefix.
4354
*
44-
* @param name The name of the field
45-
* @param prefix The prefix query
55+
* @param fieldName The name of the field
56+
* @param value The prefix query
4657
*/
47-
public PrefixQueryBuilder(String name, String prefix) {
48-
this.name = name;
49-
this.prefix = prefix;
58+
public PrefixQueryBuilder(String fieldName, String value) {
59+
this.fieldName = fieldName;
60+
this.value = value;
61+
}
62+
63+
public String fieldName() {
64+
return this.fieldName;
65+
}
66+
67+
public String value() {
68+
return this.value;
5069
}
5170

5271
public PrefixQueryBuilder rewrite(String rewrite) {
5372
this.rewrite = rewrite;
5473
return this;
5574
}
5675

76+
public String rewrite() {
77+
return this.rewrite;
78+
}
79+
5780
@Override
5881
public void doXContent(XContentBuilder builder, Params params) throws IOException {
5982
builder.startObject(NAME);
60-
builder.startObject(name);
61-
builder.field("prefix", prefix);
83+
builder.startObject(fieldName);
84+
builder.field("prefix", this.value);
6285
if (rewrite != null) {
6386
builder.field("rewrite", rewrite);
6487
}
@@ -71,4 +94,62 @@ public void doXContent(XContentBuilder builder, Params params) throws IOExceptio
7194
public String getName() {
7295
return NAME;
7396
}
97+
98+
@Override
99+
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
100+
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(parseContext.parseFieldMatcher(), rewrite, null);
101+
102+
Query query = null;
103+
MappedFieldType fieldType = parseContext.fieldMapper(fieldName);
104+
if (fieldType != null) {
105+
query = fieldType.prefixQuery(value, method, parseContext);
106+
}
107+
if (query == null) {
108+
PrefixQuery prefixQuery = new PrefixQuery(new Term(fieldName, BytesRefs.toBytesRef(value)));
109+
if (method != null) {
110+
prefixQuery.setRewriteMethod(method);
111+
}
112+
query = prefixQuery;
113+
}
114+
115+
return query;
116+
}
117+
118+
@Override
119+
public QueryValidationException validate() {
120+
QueryValidationException validationException = null;
121+
if (Strings.isEmpty(this.fieldName)) {
122+
validationException = addValidationError("field name cannot be null or empty.", validationException);
123+
}
124+
if (this.value == null) {
125+
validationException = addValidationError("query text cannot be null", validationException);
126+
}
127+
return validationException;
128+
}
129+
130+
@Override
131+
protected PrefixQueryBuilder doReadFrom(StreamInput in) throws IOException {
132+
PrefixQueryBuilder prefixQueryBuilder = new PrefixQueryBuilder(in.readString(), in.readString());
133+
prefixQueryBuilder.rewrite = in.readOptionalString();
134+
return prefixQueryBuilder;
135+
}
136+
137+
@Override
138+
protected void doWriteTo(StreamOutput out) throws IOException {
139+
out.writeString(fieldName);
140+
out.writeString(value);
141+
out.writeOptionalString(rewrite);
142+
}
143+
144+
@Override
145+
protected final int doHashCode() {
146+
return Objects.hash(fieldName, value, rewrite);
147+
}
148+
149+
@Override
150+
protected boolean doEquals(PrefixQueryBuilder other) {
151+
return Objects.equals(fieldName, other.fieldName) &&
152+
Objects.equals(value, other.value) &&
153+
Objects.equals(rewrite, other.rewrite);
154+
}
74155
}

core/src/main/java/org/elasticsearch/index/query/PrefixQueryParser.java

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,15 @@
1919

2020
package org.elasticsearch.index.query;
2121

22-
import org.apache.lucene.index.Term;
23-
import org.apache.lucene.search.MultiTermQuery;
24-
import org.apache.lucene.search.PrefixQuery;
25-
import org.apache.lucene.search.Query;
2622
import org.elasticsearch.common.inject.Inject;
27-
import org.elasticsearch.common.lucene.BytesRefs;
2823
import org.elasticsearch.common.xcontent.XContentParser;
29-
import org.elasticsearch.index.mapper.MappedFieldType;
30-
import org.elasticsearch.index.query.support.QueryParsers;
3124

3225
import java.io.IOException;
3326

3427
/**
3528
*
3629
*/
37-
public class PrefixQueryParser extends BaseQueryParserTemp {
30+
public class PrefixQueryParser extends BaseQueryParser {
3831

3932
@Inject
4033
public PrefixQueryParser() {
@@ -46,14 +39,14 @@ public String[] names() {
4639
}
4740

4841
@Override
49-
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
42+
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
5043
XContentParser parser = parseContext.parser();
5144

5245
String fieldName = parser.currentName();
53-
String rewriteMethod = null;
54-
String queryName = null;
55-
5646
String value = null;
47+
String rewrite = null;
48+
49+
String queryName = null;
5750
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
5851
String currentFieldName = null;
5952
XContentParser.Token token;
@@ -75,7 +68,7 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
7568
} else if ("boost".equals(currentFieldName)) {
7669
boost = parser.floatValue();
7770
} else if ("rewrite".equals(currentFieldName)) {
78-
rewriteMethod = parser.textOrNull();
71+
rewrite = parser.textOrNull();
7972
} else {
8073
throw new QueryParsingException(parseContext, "[regexp] query does not support [" + currentFieldName + "]");
8174
}
@@ -94,26 +87,10 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
9487
if (value == null) {
9588
throw new QueryParsingException(parseContext, "No value specified for prefix query");
9689
}
97-
98-
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(parseContext.parseFieldMatcher(), rewriteMethod, null);
99-
100-
Query query = null;
101-
MappedFieldType fieldType = parseContext.fieldMapper(fieldName);
102-
if (fieldType != null) {
103-
query = fieldType.prefixQuery(value, method, parseContext);
104-
}
105-
if (query == null) {
106-
PrefixQuery prefixQuery = new PrefixQuery(new Term(fieldName, BytesRefs.toBytesRef(value)));
107-
if (method != null) {
108-
prefixQuery.setRewriteMethod(method);
109-
}
110-
query = prefixQuery;
111-
}
112-
query.setBoost(boost);
113-
if (queryName != null) {
114-
parseContext.addNamedQuery(queryName, query);
115-
}
116-
return query;
90+
return new PrefixQueryBuilder(fieldName, value)
91+
.rewrite(rewrite)
92+
.boost(boost)
93+
.queryName(queryName);
11794
}
11895

11996
@Override
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.index.query;
21+
22+
import org.apache.lucene.index.Term;
23+
import org.apache.lucene.search.MultiTermQuery;
24+
import org.apache.lucene.search.PrefixQuery;
25+
import org.apache.lucene.search.Query;
26+
import org.elasticsearch.common.ParseFieldMatcher;
27+
import org.elasticsearch.common.lucene.BytesRefs;
28+
import org.elasticsearch.index.mapper.MappedFieldType;
29+
import org.elasticsearch.index.query.support.QueryParsers;
30+
import org.junit.Test;
31+
32+
import java.io.IOException;
33+
34+
import static org.hamcrest.Matchers.is;
35+
36+
public class PrefixQueryBuilderTest extends BaseQueryTestCase<PrefixQueryBuilder> {
37+
38+
@Override
39+
protected PrefixQueryBuilder doCreateTestQueryBuilder() {
40+
String fieldName = randomBoolean() ? STRING_FIELD_NAME : randomAsciiOfLengthBetween(1, 10);
41+
String value = randomAsciiOfLengthBetween(1, 10);
42+
PrefixQueryBuilder query = new PrefixQueryBuilder(fieldName, value);
43+
44+
if (randomBoolean()) {
45+
query.rewrite(getRandomRewriteMethod());
46+
}
47+
return query;
48+
}
49+
50+
@Override
51+
protected Query doCreateExpectedQuery(PrefixQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
52+
//norelease fix to be removed to avoid NPE on unmapped fields (Dtests.seed=BF5D7566DECBC5B1)
53+
context.parseFieldMatcher(randomBoolean() ? ParseFieldMatcher.EMPTY : ParseFieldMatcher.STRICT);
54+
55+
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(context.parseFieldMatcher(), queryBuilder.rewrite(), null);
56+
57+
Query query = null;
58+
MappedFieldType fieldType = context.fieldMapper(queryBuilder.fieldName());
59+
if (fieldType != null) {
60+
query = fieldType.prefixQuery(queryBuilder.value(), method, context);
61+
}
62+
if (query == null) {
63+
PrefixQuery prefixQuery = new PrefixQuery(new Term(queryBuilder.fieldName(), BytesRefs.toBytesRef(queryBuilder.value())));
64+
if (method != null) {
65+
prefixQuery.setRewriteMethod(method);
66+
}
67+
query = prefixQuery;
68+
}
69+
70+
return query;
71+
}
72+
73+
@Test
74+
public void testValidate() {
75+
PrefixQueryBuilder prefixQueryBuilder = new PrefixQueryBuilder("", "prefix");
76+
assertThat(prefixQueryBuilder.validate().validationErrors().size(), is(1));
77+
78+
prefixQueryBuilder = new PrefixQueryBuilder("field", null);
79+
assertThat(prefixQueryBuilder.validate().validationErrors().size(), is(1));
80+
81+
prefixQueryBuilder = new PrefixQueryBuilder("field", "prefix");
82+
assertNull(prefixQueryBuilder.validate());
83+
84+
prefixQueryBuilder = new PrefixQueryBuilder(null, null);
85+
assertThat(prefixQueryBuilder.validate().validationErrors().size(), is(2));
86+
}
87+
}

0 commit comments

Comments
 (0)