Query refactoring: SpanWithinQueryBuilder and Parser
Moving the query building functionality from the parser to the builders new toQuery() method analogous to other recent query refactorings. Relates to #10217
This commit is contained in:
parent
e11e75e3ec
commit
fc1b5a993e
|
@ -324,9 +324,12 @@ public abstract class QueryBuilders {
|
||||||
return new SpanOrQueryBuilder();
|
return new SpanOrQueryBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a new {@code span_within} builder. */
|
/** Creates a new {@code span_within} builder.
|
||||||
public static SpanWithinQueryBuilder spanWithinQuery() {
|
* @param big the big clause, it must enclose {@code little} for a match.
|
||||||
return new SpanWithinQueryBuilder();
|
* @param little the little clause, it must be contained within {@code big} for a match.
|
||||||
|
*/
|
||||||
|
public static SpanWithinQueryBuilder spanWithinQuery(SpanQueryBuilder big, SpanQueryBuilder little) {
|
||||||
|
return new SpanWithinQueryBuilder(big, little);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,9 +19,15 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.spans.SpanQuery;
|
||||||
|
import org.apache.lucene.search.spans.SpanWithinQuery;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for {@link org.apache.lucene.search.spans.SpanWithinQuery}.
|
* Builder for {@link org.apache.lucene.search.spans.SpanWithinQuery}.
|
||||||
|
@ -29,34 +35,44 @@ import java.io.IOException;
|
||||||
public class SpanWithinQueryBuilder extends AbstractQueryBuilder<SpanWithinQueryBuilder> implements SpanQueryBuilder<SpanWithinQueryBuilder> {
|
public class SpanWithinQueryBuilder extends AbstractQueryBuilder<SpanWithinQueryBuilder> implements SpanQueryBuilder<SpanWithinQueryBuilder> {
|
||||||
|
|
||||||
public static final String NAME = "span_within";
|
public static final String NAME = "span_within";
|
||||||
private SpanQueryBuilder big;
|
private final SpanQueryBuilder big;
|
||||||
private SpanQueryBuilder little;
|
private final SpanQueryBuilder little;
|
||||||
static final SpanWithinQueryBuilder PROTOTYPE = new SpanWithinQueryBuilder();
|
static final SpanWithinQueryBuilder PROTOTYPE = new SpanWithinQueryBuilder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the little clause, it must be contained within {@code big} for a match.
|
* Query that returns spans from <code>little</code> that are contained in a spans from <code>big</code>.
|
||||||
|
* @param big clause that must enclose {@code little} for a match.
|
||||||
|
* @param little the little clause, it must be contained within {@code big} for a match.
|
||||||
*/
|
*/
|
||||||
public SpanWithinQueryBuilder little(SpanQueryBuilder clause) {
|
public SpanWithinQueryBuilder(SpanQueryBuilder big, SpanQueryBuilder little) {
|
||||||
this.little = clause;
|
this.little = Objects.requireNonNull(little);
|
||||||
return this;
|
this.big = Objects.requireNonNull(big);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the big clause, it must enclose {@code little} for a match.
|
* for prototype only
|
||||||
*/
|
*/
|
||||||
public SpanWithinQueryBuilder big(SpanQueryBuilder clause) {
|
private SpanWithinQueryBuilder() {
|
||||||
this.big = clause;
|
this.little = null;
|
||||||
return this;
|
this.big = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the little clause, contained within {@code big} for a match.
|
||||||
|
*/
|
||||||
|
public SpanQueryBuilder little() {
|
||||||
|
return this.little;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the big clause that must enclose {@code little} for a match.
|
||||||
|
*/
|
||||||
|
public SpanQueryBuilder big() {
|
||||||
|
return this.big;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
if (big == null) {
|
|
||||||
throw new IllegalArgumentException("Must specify big clause when building a span_within query");
|
|
||||||
}
|
|
||||||
if (little == null) {
|
|
||||||
throw new IllegalArgumentException("Must specify little clause when building a span_within query");
|
|
||||||
}
|
|
||||||
builder.startObject(NAME);
|
builder.startObject(NAME);
|
||||||
|
|
||||||
builder.field("big");
|
builder.field("big");
|
||||||
|
@ -70,6 +86,46 @@ public class SpanWithinQueryBuilder extends AbstractQueryBuilder<SpanWithinQuery
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Query doToQuery(QueryParseContext parseContext) throws IOException {
|
||||||
|
Query innerBig = big.toQuery(parseContext);
|
||||||
|
assert innerBig instanceof SpanQuery;
|
||||||
|
Query innerLittle = little.toQuery(parseContext);
|
||||||
|
assert innerLittle instanceof SpanQuery;
|
||||||
|
return new SpanWithinQuery((SpanQuery) innerBig, (SpanQuery) innerLittle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryValidationException validate() {
|
||||||
|
QueryValidationException validationExceptions = validateInnerQuery(big, null);
|
||||||
|
validationExceptions = validateInnerQuery(little, validationExceptions);
|
||||||
|
return validationExceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpanWithinQueryBuilder doReadFrom(StreamInput in) throws IOException {
|
||||||
|
SpanQueryBuilder big = in.readNamedWriteable();
|
||||||
|
SpanQueryBuilder little = in.readNamedWriteable();
|
||||||
|
return new SpanWithinQueryBuilder(big, little);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWriteTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeNamedWriteable(big);
|
||||||
|
out.writeNamedWriteable(little);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int doHashCode() {
|
||||||
|
return Objects.hash(big, little);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doEquals(SpanWithinQueryBuilder other) {
|
||||||
|
return Objects.equals(big, other.big) &&
|
||||||
|
Objects.equals(little, other.little);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import org.apache.lucene.search.Query;
|
|
||||||
import org.apache.lucene.search.spans.SpanQuery;
|
|
||||||
import org.apache.lucene.search.spans.SpanWithinQuery;
|
import org.apache.lucene.search.spans.SpanWithinQuery;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
@ -31,7 +29,7 @@ import java.io.IOException;
|
||||||
/**
|
/**
|
||||||
* Parser for {@link SpanWithinQuery}
|
* Parser for {@link SpanWithinQuery}
|
||||||
*/
|
*/
|
||||||
public class SpanWithinQueryParser extends BaseQueryParserTemp {
|
public class SpanWithinQueryParser extends BaseQueryParser {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SpanWithinQueryParser() {
|
public SpanWithinQueryParser() {
|
||||||
|
@ -43,13 +41,13 @@ public class SpanWithinQueryParser extends BaseQueryParserTemp {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||||
XContentParser parser = parseContext.parser();
|
XContentParser parser = parseContext.parser();
|
||||||
|
|
||||||
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
SpanQuery big = null;
|
SpanQueryBuilder big = null;
|
||||||
SpanQuery little = null;
|
SpanQueryBuilder little = null;
|
||||||
|
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
|
@ -58,17 +56,17 @@ public class SpanWithinQueryParser extends BaseQueryParserTemp {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
if ("big".equals(currentFieldName)) {
|
if ("big".equals(currentFieldName)) {
|
||||||
Query query = parseContext.parseInnerQuery();
|
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||||
if (query instanceof SpanQuery == false) {
|
if (query instanceof SpanQueryBuilder == false) {
|
||||||
throw new QueryParsingException(parseContext, "span_within [big] must be of type span query");
|
throw new QueryParsingException(parseContext, "span_within [big] must be of type span query");
|
||||||
}
|
}
|
||||||
big = (SpanQuery) query;
|
big = (SpanQueryBuilder) query;
|
||||||
} else if ("little".equals(currentFieldName)) {
|
} else if ("little".equals(currentFieldName)) {
|
||||||
Query query = parseContext.parseInnerQuery();
|
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||||
if (query instanceof SpanQuery == false) {
|
if (query instanceof SpanQueryBuilder == false) {
|
||||||
throw new QueryParsingException(parseContext, "span_within [little] must be of type span query");
|
throw new QueryParsingException(parseContext, "span_within [little] must be of type span query");
|
||||||
}
|
}
|
||||||
little = (SpanQuery) query;
|
little = (SpanQueryBuilder) query;
|
||||||
} else {
|
} else {
|
||||||
throw new QueryParsingException(parseContext, "[span_within] query does not support [" + currentFieldName + "]");
|
throw new QueryParsingException(parseContext, "[span_within] query does not support [" + currentFieldName + "]");
|
||||||
}
|
}
|
||||||
|
@ -88,11 +86,8 @@ public class SpanWithinQueryParser extends BaseQueryParserTemp {
|
||||||
throw new QueryParsingException(parseContext, "span_within must include [little]");
|
throw new QueryParsingException(parseContext, "span_within must include [little]");
|
||||||
}
|
}
|
||||||
|
|
||||||
Query query = new SpanWithinQuery(big, little);
|
SpanWithinQueryBuilder query = new SpanWithinQueryBuilder(big, little);
|
||||||
query.setBoost(boost);
|
query.boost(boost).queryName(queryName);
|
||||||
if (queryName != null) {
|
|
||||||
parseContext.addNamedQuery(queryName, query);
|
|
||||||
}
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1347,9 +1347,7 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest {
|
||||||
IndexQueryParserService queryParser = queryParser();
|
IndexQueryParserService queryParser = queryParser();
|
||||||
Query expectedQuery = new SpanWithinQuery(new SpanTermQuery(new Term("age", longToPrefixCoded(34, 0))),
|
Query expectedQuery = new SpanWithinQuery(new SpanTermQuery(new Term("age", longToPrefixCoded(34, 0))),
|
||||||
new SpanTermQuery(new Term("age", longToPrefixCoded(35, 0))));
|
new SpanTermQuery(new Term("age", longToPrefixCoded(35, 0))));
|
||||||
Query actualQuery = queryParser.parse(spanWithinQuery()
|
Query actualQuery = queryParser.parse(spanWithinQuery(spanTermQuery("age", 34), spanTermQuery("age", 35)))
|
||||||
.big(spanTermQuery("age", 34))
|
|
||||||
.little(spanTermQuery("age", 35)))
|
|
||||||
.query();
|
.query();
|
||||||
assertEquals(expectedQuery, actualQuery);
|
assertEquals(expectedQuery, actualQuery);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.spans.SpanQuery;
|
||||||
|
import org.apache.lucene.search.spans.SpanWithinQuery;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SpanWithinQueryBuilderTest extends BaseQueryTestCase<SpanWithinQueryBuilder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Query doCreateExpectedQuery(SpanWithinQueryBuilder testQueryBuilder, QueryParseContext context) throws IOException {
|
||||||
|
SpanQuery big = (SpanQuery) testQueryBuilder.big().toQuery(context);
|
||||||
|
SpanQuery little = (SpanQuery) testQueryBuilder.little().toQuery(context);
|
||||||
|
return new SpanWithinQuery(big, little);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpanWithinQueryBuilder doCreateTestQueryBuilder() {
|
||||||
|
SpanTermQueryBuilder bigQuery = new SpanTermQueryBuilderTest().createTestQueryBuilder();
|
||||||
|
// we need same field name and value type as bigQuery for little query
|
||||||
|
String fieldName = bigQuery.fieldName();
|
||||||
|
Object littleValue;
|
||||||
|
switch (fieldName) {
|
||||||
|
case BOOLEAN_FIELD_NAME: littleValue = randomBoolean(); break;
|
||||||
|
case INT_FIELD_NAME: littleValue = randomInt(); break;
|
||||||
|
case DOUBLE_FIELD_NAME: littleValue = randomDouble(); break;
|
||||||
|
case STRING_FIELD_NAME: littleValue = randomAsciiOfLengthBetween(1, 10); break;
|
||||||
|
default : littleValue = randomAsciiOfLengthBetween(1, 10);
|
||||||
|
}
|
||||||
|
SpanTermQueryBuilder littleQuery = new SpanTermQueryBuilder(fieldName, littleValue);
|
||||||
|
return new SpanWithinQueryBuilder(bigQuery, littleQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidate() {
|
||||||
|
int totalExpectedErrors = 0;
|
||||||
|
SpanQueryBuilder bigSpanQueryBuilder;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
bigSpanQueryBuilder = new SpanTermQueryBuilder("", "test");
|
||||||
|
totalExpectedErrors++;
|
||||||
|
} else {
|
||||||
|
bigSpanQueryBuilder = new SpanTermQueryBuilder("name", "value");
|
||||||
|
}
|
||||||
|
SpanQueryBuilder littleSpanQueryBuilder;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
littleSpanQueryBuilder = new SpanTermQueryBuilder("", "test");
|
||||||
|
totalExpectedErrors++;
|
||||||
|
} else {
|
||||||
|
littleSpanQueryBuilder = new SpanTermQueryBuilder("name", "value");
|
||||||
|
}
|
||||||
|
SpanWithinQueryBuilder queryBuilder = new SpanWithinQueryBuilder(bigSpanQueryBuilder, littleSpanQueryBuilder);
|
||||||
|
assertValidate(queryBuilder, totalExpectedErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=NullPointerException.class)
|
||||||
|
public void testNullBig() {
|
||||||
|
new SpanWithinQueryBuilder(null, new SpanTermQueryBuilder("name", "value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=NullPointerException.class)
|
||||||
|
public void testNullLittle() {
|
||||||
|
new SpanWithinQueryBuilder(new SpanTermQueryBuilder("name", "value"), null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,13 @@ Updated the static factory methods in QueryBuilders accordingly.
|
||||||
Removed setter for mandatory include/exclude span query clause, needs to be set in constructor now.
|
Removed setter for mandatory include/exclude span query clause, needs to be set in constructor now.
|
||||||
Updated the static factory methods in QueryBuilders and tests accordingly.
|
Updated the static factory methods in QueryBuilders and tests accordingly.
|
||||||
|
|
||||||
|
==== SpanWithinQueryBuilder
|
||||||
|
|
||||||
|
Removed setters for mandatory big/little inner span queries. Both arguments now have
|
||||||
|
to be supplied at construction time already and have to be non-null. Updated
|
||||||
|
static factory methods in QueryBuilders accordingly.
|
||||||
|
>>>>>>> Query refactoring: SpanWithinQueryBuilder and Parser
|
||||||
|
|
||||||
==== QueryFilterBuilder
|
==== QueryFilterBuilder
|
||||||
|
|
||||||
Removed the setter `queryName(String queryName)` since this field is not supported
|
Removed the setter `queryName(String queryName)` since this field is not supported
|
||||||
|
|
Loading…
Reference in New Issue