Skip to content

Commit 94d13c7

Browse files
committed
Refactors WildcardQueryBuilder and Parser
Relates to #10217 Closes #12110 This PR is against the query-refactoring branch.
1 parent 817b992 commit 94d13c7

File tree

3 files changed

+201
-38
lines changed

3 files changed

+201
-38
lines changed

core/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.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.Query;
25+
import org.apache.lucene.search.WildcardQuery;
26+
import org.apache.lucene.util.BytesRef;
27+
import org.elasticsearch.common.Strings;
28+
import org.elasticsearch.common.io.stream.StreamInput;
29+
import org.elasticsearch.common.io.stream.StreamOutput;
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
* Implements the wildcard search query. Supported wildcards are <tt>*</tt>, which
@@ -35,9 +46,9 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
3546

3647
public static final String NAME = "wildcard";
3748

38-
private final String name;
49+
private final String fieldName;
3950

40-
private final String wildcard;
51+
private final String value;
4152

4253
private String rewrite;
4354

@@ -51,24 +62,41 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
5162
* a Wildcard term should not start with one of the wildcards <tt>*</tt> or
5263
* <tt>?</tt>.
5364
*
54-
* @param name The field name
55-
* @param wildcard The wildcard query string
65+
* @param fieldName The field name
66+
* @param value The wildcard query string
5667
*/
57-
public WildcardQueryBuilder(String name, String wildcard) {
58-
this.name = name;
59-
this.wildcard = wildcard;
68+
public WildcardQueryBuilder(String fieldName, String value) {
69+
this.fieldName = fieldName;
70+
this.value = value;
71+
}
72+
73+
public String fieldName() {
74+
return fieldName;
75+
}
76+
77+
public String value() {
78+
return value;
6079
}
6180

6281
public WildcardQueryBuilder rewrite(String rewrite) {
6382
this.rewrite = rewrite;
6483
return this;
6584
}
6685

86+
public String rewrite() {
87+
return this.rewrite;
88+
}
89+
90+
@Override
91+
public String getName() {
92+
return NAME;
93+
}
94+
6795
@Override
6896
public void doXContent(XContentBuilder builder, Params params) throws IOException {
6997
builder.startObject(NAME);
70-
builder.startObject(name);
71-
builder.field("wildcard", wildcard);
98+
builder.startObject(fieldName);
99+
builder.field("wildcard", value);
72100
if (rewrite != null) {
73101
builder.field("rewrite", rewrite);
74102
}
@@ -78,7 +106,60 @@ public void doXContent(XContentBuilder builder, Params params) throws IOExceptio
78106
}
79107

80108
@Override
81-
public String getName() {
82-
return NAME;
109+
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
110+
String indexFieldName;
111+
BytesRef valueBytes;
112+
113+
MappedFieldType fieldType = parseContext.fieldMapper(fieldName);
114+
if (fieldType != null) {
115+
indexFieldName = fieldType.names().indexName();
116+
valueBytes = fieldType.indexedValueForSearch(value);
117+
} else {
118+
indexFieldName = fieldName;
119+
valueBytes = new BytesRef(value);
120+
}
121+
122+
WildcardQuery query = new WildcardQuery(new Term(indexFieldName, valueBytes));
123+
MultiTermQuery.RewriteMethod rewriteMethod = QueryParsers.parseRewriteMethod(parseContext.parseFieldMatcher(), rewrite, null);
124+
QueryParsers.setRewriteMethod(query, rewriteMethod);
125+
return query;
126+
}
127+
128+
@Override
129+
public QueryValidationException validate() {
130+
QueryValidationException validationException = null;
131+
if (Strings.isEmpty(this.fieldName)) {
132+
validationException = addValidationError("field name cannot be null or empty.", validationException);
133+
}
134+
if (this.value == null) {
135+
validationException = addValidationError("wildcard cannot be null", validationException);
136+
}
137+
return validationException;
138+
}
139+
140+
@Override
141+
protected WildcardQueryBuilder doReadFrom(StreamInput in) throws IOException {
142+
WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder(in.readString(), in.readString());
143+
wildcardQueryBuilder.rewrite = in.readOptionalString();
144+
return wildcardQueryBuilder;
145+
}
146+
147+
@Override
148+
protected void doWriteTo(StreamOutput out) throws IOException {
149+
out.writeString(fieldName);
150+
out.writeString(value);
151+
out.writeOptionalString(rewrite);
152+
}
153+
154+
@Override
155+
protected int doHashCode() {
156+
return Objects.hash(fieldName, value, rewrite);
157+
}
158+
159+
@Override
160+
protected boolean doEquals(WildcardQueryBuilder other) {
161+
return Objects.equals(fieldName, other.fieldName) &&
162+
Objects.equals(value, other.value) &&
163+
Objects.equals(rewrite, other.rewrite);
83164
}
84165
}

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

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,15 @@
1919

2020
package org.elasticsearch.index.query;
2121

22-
import org.apache.lucene.index.Term;
23-
import org.apache.lucene.search.Query;
24-
import org.apache.lucene.search.WildcardQuery;
25-
import org.apache.lucene.util.BytesRef;
2622
import org.elasticsearch.common.inject.Inject;
2723
import org.elasticsearch.common.xcontent.XContentParser;
28-
import org.elasticsearch.index.mapper.MappedFieldType;
29-
import org.elasticsearch.index.query.support.QueryParsers;
3024

3125
import java.io.IOException;
3226

3327
/**
3428
*
3529
*/
36-
public class WildcardQueryParser extends BaseQueryParserTemp {
30+
public class WildcardQueryParser extends BaseQueryParser {
3731

3832
@Inject
3933
public WildcardQueryParser() {
@@ -45,15 +39,15 @@ public String[] names() {
4539
}
4640

4741
@Override
48-
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
42+
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
4943
XContentParser parser = parseContext.parser();
5044

5145
XContentParser.Token token = parser.nextToken();
5246
if (token != XContentParser.Token.FIELD_NAME) {
5347
throw new QueryParsingException(parseContext, "[wildcard] query malformed, no field");
5448
}
5549
String fieldName = parser.currentName();
56-
String rewriteMethod = null;
50+
String rewrite = null;
5751

5852
String value = null;
5953
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
@@ -72,7 +66,7 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
7266
} else if ("boost".equals(currentFieldName)) {
7367
boost = parser.floatValue();
7468
} else if ("rewrite".equals(currentFieldName)) {
75-
rewriteMethod = parser.textOrNull();
69+
rewrite = parser.textOrNull();
7670
} else if ("_name".equals(currentFieldName)) {
7771
queryName = parser.text();
7872
} else {
@@ -89,23 +83,10 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
8983
if (value == null) {
9084
throw new QueryParsingException(parseContext, "No value specified for prefix query");
9185
}
92-
93-
BytesRef valueBytes;
94-
MappedFieldType fieldType = parseContext.fieldMapper(fieldName);
95-
if (fieldType != null) {
96-
fieldName = fieldType.names().indexName();
97-
valueBytes = fieldType.indexedValueForSearch(value);
98-
} else {
99-
valueBytes = new BytesRef(value);
100-
}
101-
102-
WildcardQuery wildcardQuery = new WildcardQuery(new Term(fieldName, valueBytes));
103-
QueryParsers.setRewriteMethod(wildcardQuery, parseContext.parseFieldMatcher(), rewriteMethod);
104-
wildcardQuery.setBoost(boost);
105-
if (queryName != null) {
106-
parseContext.addNamedQuery(queryName, wildcardQuery);
107-
}
108-
return wildcardQuery;
86+
return new WildcardQueryBuilder(fieldName, value)
87+
.rewrite(rewrite)
88+
.boost(boost)
89+
.queryName(queryName);
10990
}
11091

11192
@Override
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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.Query;
25+
import org.apache.lucene.search.WildcardQuery;
26+
import org.apache.lucene.util.BytesRef;
27+
import org.elasticsearch.common.ParseFieldMatcher;
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 WildcardQueryBuilderTest extends BaseQueryTestCase<WildcardQueryBuilder> {
37+
38+
@Override
39+
protected WildcardQueryBuilder doCreateTestQueryBuilder() {
40+
WildcardQueryBuilder query;
41+
42+
// mapped or unmapped field
43+
String text = randomAsciiOfLengthBetween(1, 10);
44+
if (randomBoolean()) {
45+
query = new WildcardQueryBuilder(STRING_FIELD_NAME, text);
46+
} else {
47+
query = new WildcardQueryBuilder(randomAsciiOfLengthBetween(1, 10), text);
48+
}
49+
if (randomBoolean()) {
50+
query.rewrite(randomFrom(getRandomRewriteMethod()));
51+
}
52+
return query;
53+
}
54+
55+
@Override
56+
protected Query doCreateExpectedQuery(WildcardQueryBuilder queryBuilder, QueryParseContext context) throws IOException {
57+
String indexFieldName;
58+
BytesRef valueBytes;
59+
60+
MappedFieldType fieldType = context.fieldMapper(queryBuilder.fieldName());
61+
if (fieldType != null) {
62+
indexFieldName = fieldType.names().indexName();
63+
valueBytes = fieldType.indexedValueForSearch(queryBuilder.value());
64+
} else {
65+
indexFieldName = queryBuilder.fieldName();
66+
valueBytes = new BytesRef(queryBuilder.value());
67+
}
68+
69+
WildcardQuery expectedQuery = new WildcardQuery(new Term(indexFieldName, valueBytes));
70+
71+
//norelease fix to be removed to avoid NPE on unmapped fields
72+
context.parseFieldMatcher(randomBoolean() ? ParseFieldMatcher.EMPTY : ParseFieldMatcher.STRICT);
73+
MultiTermQuery.RewriteMethod rewriteMethod = QueryParsers.parseRewriteMethod(context.parseFieldMatcher(), queryBuilder.rewrite(), null);
74+
QueryParsers.setRewriteMethod(expectedQuery, rewriteMethod);
75+
return expectedQuery;
76+
}
77+
78+
@Test
79+
public void testValidate() {
80+
WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder("", "text");
81+
assertThat(wildcardQueryBuilder.validate().validationErrors().size(), is(1));
82+
83+
wildcardQueryBuilder = new WildcardQueryBuilder("field", null);
84+
assertThat(wildcardQueryBuilder.validate().validationErrors().size(), is(1));
85+
86+
wildcardQueryBuilder = new WildcardQueryBuilder(null, null);
87+
assertThat(wildcardQueryBuilder.validate().validationErrors().size(), is(2));
88+
89+
wildcardQueryBuilder = new WildcardQueryBuilder("field", "text");
90+
assertNull(wildcardQueryBuilder.validate());
91+
}
92+
93+
@Test
94+
public void testEmptyValue() throws IOException {
95+
QueryParseContext context = createContext();
96+
context.setAllowUnmappedFields(true);
97+
98+
WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder(getRandomType(), "");
99+
assertEquals(wildcardQueryBuilder.toQuery(context).getClass(), WildcardQuery.class);
100+
}
101+
}

0 commit comments

Comments
 (0)