Skip to content

Commit eea7ee5

Browse files
author
Christoph Büscher
committed
Query refactoring: Add refactored MatchAllQuery and BaseQueryTestCase
1 parent 6c32279 commit eea7ee5

4 files changed

Lines changed: 285 additions & 25 deletions

File tree

src/main/java/org/elasticsearch/index/query/MatchAllQueryBuilder.java

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,22 @@
1919

2020
package org.elasticsearch.index.query;
2121

22+
import org.apache.lucene.search.MatchAllDocsQuery;
23+
import org.apache.lucene.search.Query;
24+
import org.elasticsearch.common.io.stream.StreamInput;
25+
import org.elasticsearch.common.io.stream.StreamOutput;
26+
import org.elasticsearch.common.io.stream.Streamable;
27+
import org.elasticsearch.common.lucene.search.Queries;
2228
import org.elasticsearch.common.xcontent.XContentBuilder;
2329

2430
import java.io.IOException;
2531

2632
/**
2733
* A query that matches on all documents.
28-
*
29-
*
3034
*/
31-
public class MatchAllQueryBuilder extends BaseQueryBuilder implements BoostableQueryBuilder<MatchAllQueryBuilder> {
35+
public class MatchAllQueryBuilder extends BaseQueryBuilder implements Streamable, BoostableQueryBuilder<MatchAllQueryBuilder> {
3236

33-
private float boost = -1;
37+
private float boost = 1.0f;
3438

3539
/**
3640
* Sets the boost for this query. Documents matching this query will (in addition to the normal
@@ -42,10 +46,17 @@ public MatchAllQueryBuilder boost(float boost) {
4246
return this;
4347
}
4448

49+
/**
50+
* Gets the boost for this query.
51+
*/
52+
public float boost() {
53+
return this.boost;
54+
}
55+
4556
@Override
4657
public void doXContent(XContentBuilder builder, Params params) throws IOException {
4758
builder.startObject(MatchAllQueryParser.NAME);
48-
if (boost != -1) {
59+
if (boost != 1.0f) {
4960
builder.field("boost", boost);
5061
}
5162
builder.endObject();
@@ -54,4 +65,42 @@ public void doXContent(XContentBuilder builder, Params params) throws IOExceptio
5465
final protected String parserName() {
5566
return MatchAllQueryParser.NAME;
5667
}
57-
}
68+
69+
@Override
70+
public Query toQuery(QueryParseContext parseContext) {
71+
if (this.boost == 1.0f) {
72+
return Queries.newMatchAllQuery();
73+
}
74+
75+
MatchAllDocsQuery query = new MatchAllDocsQuery();
76+
query.setBoost(boost);
77+
return query;
78+
}
79+
80+
@Override
81+
public boolean equals(Object o) {
82+
if (this == o) {
83+
return true;
84+
}
85+
if (o == null || getClass() != o.getClass()) {
86+
return false;
87+
}
88+
MatchAllQueryBuilder that = (MatchAllQueryBuilder) o;
89+
return Float.compare(that.boost, boost) == 0;
90+
}
91+
92+
@Override
93+
public int hashCode() {
94+
return boost != +0.0f ? Float.floatToIntBits(boost) : 0;
95+
}
96+
97+
@Override
98+
public void readFrom(StreamInput in) throws IOException {
99+
this.boost = in.readFloat();
100+
}
101+
102+
@Override
103+
public void writeTo(StreamOutput out) throws IOException {
104+
out.writeFloat(this.boost);
105+
}
106+
}

src/main/java/org/elasticsearch/index/query/MatchAllQueryParser.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,16 @@
1919

2020
package org.elasticsearch.index.query;
2121

22-
import org.apache.lucene.search.MatchAllDocsQuery;
23-
import org.apache.lucene.search.Query;
2422
import org.elasticsearch.common.Strings;
2523
import org.elasticsearch.common.inject.Inject;
26-
import org.elasticsearch.common.lucene.search.Queries;
2724
import org.elasticsearch.common.xcontent.XContentParser;
2825

2926
import java.io.IOException;
3027

3128
/**
32-
*
29+
* Parser code for MatchAllQuery
3330
*/
34-
public class MatchAllQueryParser extends BaseQueryParserTemp {
31+
public class MatchAllQueryParser extends BaseQueryParser {
3532

3633
public static final String NAME = "match_all";
3734

@@ -44,32 +41,23 @@ public String[] names() {
4441
return new String[]{NAME, Strings.toCamelCase(NAME)};
4542
}
4643

47-
@Override
48-
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
44+
public MatchAllQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException {
45+
MatchAllQueryBuilder queryBuilder = new MatchAllQueryBuilder();
4946
XContentParser parser = parseContext.parser();
5047

51-
float boost = 1.0f;
5248
String currentFieldName = null;
53-
5449
XContentParser.Token token;
5550
while (((token = parser.nextToken()) != XContentParser.Token.END_OBJECT && token != XContentParser.Token.END_ARRAY)) {
5651
if (token == XContentParser.Token.FIELD_NAME) {
5752
currentFieldName = parser.currentName();
5853
} else if (token.isValue()) {
5954
if ("boost".equals(currentFieldName)) {
60-
boost = parser.floatValue();
55+
queryBuilder.boost(parser.floatValue());
6156
} else {
6257
throw new QueryParsingException(parseContext.index(), "[match_all] query does not support [" + currentFieldName + "]");
6358
}
6459
}
6560
}
66-
67-
if (boost == 1.0f) {
68-
return Queries.newMatchAllQuery();
69-
}
70-
71-
MatchAllDocsQuery query = new MatchAllDocsQuery();
72-
query.setBoost(boost);
73-
return query;
61+
return queryBuilder;
7462
}
75-
}
63+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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.search.Query;
23+
import org.elasticsearch.Version;
24+
import org.elasticsearch.cluster.ClusterService;
25+
import org.elasticsearch.cluster.metadata.IndexMetaData;
26+
import org.elasticsearch.common.inject.AbstractModule;
27+
import org.elasticsearch.common.inject.Injector;
28+
import org.elasticsearch.common.inject.ModulesBuilder;
29+
import org.elasticsearch.common.inject.util.Providers;
30+
import org.elasticsearch.common.io.stream.BytesStreamInput;
31+
import org.elasticsearch.common.io.stream.BytesStreamOutput;
32+
import org.elasticsearch.common.io.stream.Streamable;
33+
import org.elasticsearch.common.settings.ImmutableSettings;
34+
import org.elasticsearch.common.settings.Settings;
35+
import org.elasticsearch.common.settings.SettingsModule;
36+
import org.elasticsearch.common.xcontent.XContentFactory;
37+
import org.elasticsearch.env.Environment;
38+
import org.elasticsearch.env.EnvironmentModule;
39+
import org.elasticsearch.index.Index;
40+
import org.elasticsearch.index.IndexNameModule;
41+
import org.elasticsearch.index.analysis.AnalysisModule;
42+
import org.elasticsearch.index.cache.IndexCacheModule;
43+
import org.elasticsearch.index.query.functionscore.FunctionScoreModule;
44+
import org.elasticsearch.index.settings.IndexSettingsModule;
45+
import org.elasticsearch.index.similarity.SimilarityModule;
46+
import org.elasticsearch.indices.breaker.CircuitBreakerService;
47+
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
48+
import org.elasticsearch.indices.query.IndicesQueriesModule;
49+
import org.elasticsearch.script.ScriptModule;
50+
import org.elasticsearch.test.ElasticsearchTestCase;
51+
import org.elasticsearch.threadpool.ThreadPool;
52+
import org.elasticsearch.threadpool.ThreadPoolModule;
53+
import org.junit.AfterClass;
54+
import org.junit.BeforeClass;
55+
import org.junit.Ignore;
56+
import org.junit.Test;
57+
58+
import java.io.IOException;
59+
60+
@Ignore
61+
public abstract class BaseQueryTestCase<QB extends BaseQueryBuilder & Streamable> extends ElasticsearchTestCase {
62+
63+
private static Injector injector;
64+
private static IndexQueryParserService queryParserService;
65+
private static Index index;
66+
67+
protected QB testQuery = createTestQueryBuilder();
68+
69+
/**
70+
* Setup for the whole base test class.
71+
*/
72+
@BeforeClass
73+
public static void init() throws IOException {
74+
Settings settings = ImmutableSettings.settingsBuilder()
75+
.put("name", BaseQueryTestCase.class.toString())
76+
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
77+
.build();
78+
79+
index = new Index("test");
80+
injector = new ModulesBuilder().add(
81+
new EnvironmentModule(new Environment(settings)),
82+
new SettingsModule(settings),
83+
new ThreadPoolModule(settings),
84+
new IndicesQueriesModule(),
85+
new ScriptModule(settings),
86+
new IndexSettingsModule(index, settings),
87+
new IndexCacheModule(settings),
88+
new AnalysisModule(settings),
89+
new SimilarityModule(settings),
90+
new IndexNameModule(index),
91+
new IndexQueryParserModule(settings),
92+
new FunctionScoreModule(),
93+
new AbstractModule() {
94+
@Override
95+
protected void configure() {
96+
bind(ClusterService.class).toProvider(Providers.of((ClusterService) null));
97+
bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
98+
}
99+
}
100+
).createInjector();
101+
queryParserService = injector.getInstance(IndexQueryParserService.class);
102+
}
103+
104+
@AfterClass
105+
public static void after() throws Exception {
106+
terminate(injector.getInstance(ThreadPool.class));
107+
injector = null;
108+
index = null;
109+
queryParserService = null;
110+
}
111+
112+
/**
113+
* Create the query that is being tested
114+
*/
115+
protected abstract QB createTestQueryBuilder();
116+
117+
/**
118+
* Subclass should handle assertions on the lucene query produced by the query builder under test here
119+
*/
120+
protected abstract void assertLuceneQuery(QB queryBuilder, Query query) throws IOException;
121+
122+
/**
123+
* Creates an empty builder of the type of query under test
124+
*/
125+
protected abstract QB createEmptyQueryBuilder();
126+
127+
/**
128+
* Generic test that creates new query from the test query and checks both for equality
129+
* and asserts equality on the two queries.
130+
*/
131+
@Test
132+
public void testFromXContent() throws IOException {
133+
QueryParseContext context = new QueryParseContext(index, queryParserService);
134+
String contentString = testQuery.toString();
135+
context.reset(XContentFactory.xContent(contentString).createParser(contentString));
136+
137+
QueryBuilder newQuery = queryParserService.queryParser(testQuery.parserName()).fromXContent(context);
138+
assertNotSame(newQuery, testQuery);
139+
assertEquals(newQuery, testQuery);
140+
}
141+
142+
/**
143+
* Test creates the {@link Query} from the {@link QueryBuilder} under test and delegates the
144+
* assertions being made on the result to the implementing subclass.
145+
*/
146+
@Test
147+
public void testToQuery() throws IOException {
148+
QueryParseContext context = new QueryParseContext(index, queryParserService);
149+
assertLuceneQuery(this.testQuery, this.testQuery.toQuery(context));
150+
}
151+
152+
/**
153+
* Test serialization and deserialization of the test query.
154+
* @throws IOException
155+
*/
156+
@Test
157+
public void testSerialization() throws IOException {
158+
BytesStreamOutput output = new BytesStreamOutput();
159+
testQuery.writeTo(output);
160+
161+
BytesStreamInput in = new BytesStreamInput(output.bytes());
162+
QB deserializedQuery = createEmptyQueryBuilder();
163+
deserializedQuery.readFrom(in);
164+
165+
assertEquals(deserializedQuery, testQuery);
166+
assertNotSame(deserializedQuery, testQuery);
167+
}
168+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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.search.MatchAllDocsQuery;
23+
import org.apache.lucene.search.Query;
24+
25+
import java.io.IOException;
26+
27+
import static org.hamcrest.Matchers.instanceOf;
28+
import static org.hamcrest.Matchers.is;
29+
30+
public class MatchAllQueryBuilderTest extends BaseQueryTestCase<MatchAllQueryBuilder> {
31+
32+
@Override
33+
protected void assertLuceneQuery(MatchAllQueryBuilder queryBuilder, Query query) throws IOException {
34+
assertThat(query, instanceOf(MatchAllDocsQuery.class));
35+
assertThat(query.getBoost(), is(queryBuilder.boost()));
36+
}
37+
38+
@Override
39+
protected MatchAllQueryBuilder createEmptyQueryBuilder() {
40+
return new MatchAllQueryBuilder();
41+
}
42+
43+
/**
44+
* @return a MatchAllQuery with random boost between 0.1f and 2.0f
45+
*/
46+
@Override
47+
protected MatchAllQueryBuilder createTestQueryBuilder() {
48+
MatchAllQueryBuilder query = new MatchAllQueryBuilder();
49+
if (randomBoolean()) {
50+
query.boost(2.0f / randomIntBetween(1, 20));
51+
}
52+
return query;
53+
}
54+
55+
}

0 commit comments

Comments
 (0)