Query refactoring: FieldMaskingSpanQueryBuilder 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 Closes #11717
This commit is contained in:
parent
fabe91633f
commit
107635b194
|
@ -19,10 +19,15 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.spans.FieldMaskingSpanQuery;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMaskingSpanQueryBuilder> implements SpanQueryBuilder<FieldMaskingSpanQueryBuilder>, BoostableQueryBuilder<FieldMaskingSpanQueryBuilder> {
|
||||
|
||||
|
@ -30,17 +35,37 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
|
||||
private final SpanQueryBuilder queryBuilder;
|
||||
|
||||
private final String field;
|
||||
private final String fieldName;
|
||||
|
||||
private float boost = -1;
|
||||
private float boost = 1.0f;
|
||||
|
||||
private String queryName;
|
||||
|
||||
static final FieldMaskingSpanQueryBuilder PROTOTYPE = new FieldMaskingSpanQueryBuilder(null, null);
|
||||
|
||||
public FieldMaskingSpanQueryBuilder(SpanQueryBuilder queryBuilder, String field) {
|
||||
/**
|
||||
* Constructs a new {@link FieldMaskingSpanQueryBuilder} given an inner {@link SpanQueryBuilder} for
|
||||
* a given field
|
||||
* @param queryBuilder inner {@link SpanQueryBuilder}
|
||||
* @param fieldName the field name
|
||||
*/
|
||||
public FieldMaskingSpanQueryBuilder(SpanQueryBuilder queryBuilder, String fieldName) {
|
||||
this.queryBuilder = queryBuilder;
|
||||
this.field = field;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the field name for this query
|
||||
*/
|
||||
public String fieldName() {
|
||||
return this.fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the inner {@link QueryBuilder}
|
||||
*/
|
||||
public SpanQueryBuilder innerQuery() {
|
||||
return this.queryBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,6 +74,13 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the boost factor for this query
|
||||
*/
|
||||
public float boost() {
|
||||
return this.boost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query name for the filter that can be used when searching for matched_filters per hit.
|
||||
*/
|
||||
|
@ -57,15 +89,20 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the query name for this query
|
||||
*/
|
||||
public String queryName() {
|
||||
return this.queryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(NAME);
|
||||
builder.field("query");
|
||||
queryBuilder.toXContent(builder, params);
|
||||
builder.field("field", field);
|
||||
if (boost != -1) {
|
||||
builder.field("boost", boost);
|
||||
}
|
||||
builder.field("field", fieldName);
|
||||
builder.field("boost", boost);
|
||||
if (queryName != null) {
|
||||
builder.field("_name", queryName);
|
||||
}
|
||||
|
@ -73,13 +110,73 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
public SpanQuery toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException {
|
||||
String fieldInQuery = this.fieldName;
|
||||
MappedFieldType fieldType = parseContext.fieldMapper(fieldName);
|
||||
if (fieldType != null) {
|
||||
fieldInQuery = fieldType.names().indexName();
|
||||
}
|
||||
SpanQuery innerQuery = this.queryBuilder.toQuery(parseContext);
|
||||
|
||||
FieldMaskingSpanQuery query = new FieldMaskingSpanQuery(innerQuery, fieldInQuery);
|
||||
query.setBoost(boost);
|
||||
if (queryName != null) {
|
||||
parseContext.addNamedQuery(queryName, query);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanQuery toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException {
|
||||
//norelease just a temporary implementation, will go away once this query is refactored and properly overrides toQuery
|
||||
return (SpanQuery)super.toQuery(parseContext);
|
||||
public QueryValidationException validate() {
|
||||
QueryValidationException validationExceptions = null;
|
||||
if (queryBuilder == null) {
|
||||
validationExceptions = QueryValidationException.addValidationError("[field_masking_span] must have inner span query clause", validationExceptions);
|
||||
}
|
||||
if (fieldName == null || fieldName.isEmpty()) {
|
||||
validationExceptions = QueryValidationException.addValidationError("[field_masking_span] must have set field name", validationExceptions);
|
||||
}
|
||||
return validationExceptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldMaskingSpanQueryBuilder readFrom(StreamInput in) throws IOException {
|
||||
QueryBuilder innerQueryBuilder = in.readNamedWriteable();
|
||||
FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder((SpanQueryBuilder) innerQueryBuilder, in.readString());
|
||||
queryBuilder.queryName = in.readOptionalString();
|
||||
queryBuilder.boost = in.readFloat();
|
||||
return queryBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeNamedWriteable(this.queryBuilder);
|
||||
out.writeString(this.fieldName);
|
||||
out.writeOptionalString(queryName);
|
||||
out.writeFloat(boost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(queryBuilder, fieldName, boost, queryName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
FieldMaskingSpanQueryBuilder other = (FieldMaskingSpanQueryBuilder) obj;
|
||||
return Objects.equals(queryBuilder, other.queryBuilder) &&
|
||||
Objects.equals(fieldName, other.fieldName) &&
|
||||
Objects.equals(boost, other.boost) &&
|
||||
Objects.equals(queryName, other.queryName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,21 +19,15 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.spans.FieldMaskingSpanQuery;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class FieldMaskingSpanQueryParser extends BaseQueryParserTemp {
|
||||
public class FieldMaskingSpanQueryParser extends BaseQueryParser {
|
||||
|
||||
@Inject
|
||||
public FieldMaskingSpanQueryParser() {
|
||||
|
@ -45,12 +39,12 @@ public class FieldMaskingSpanQueryParser extends BaseQueryParserTemp {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
float boost = 1.0f;
|
||||
|
||||
SpanQuery inner = null;
|
||||
SpanQueryBuilder inner = null;
|
||||
String field = null;
|
||||
String queryName = null;
|
||||
|
||||
|
@ -61,11 +55,11 @@ public class FieldMaskingSpanQueryParser extends BaseQueryParserTemp {
|
|||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if ("query".equals(currentFieldName)) {
|
||||
Query query = parseContext.parseInnerQuery();
|
||||
if (!(query instanceof SpanQuery)) {
|
||||
QueryBuilder query = parseContext.parseInnerQueryBuilder();
|
||||
if (!(query instanceof SpanQueryBuilder)) {
|
||||
throw new QueryParsingException(parseContext, "[field_masking_span] query] must be of type span query");
|
||||
}
|
||||
inner = (SpanQuery) query;
|
||||
inner = (SpanQueryBuilder) query;
|
||||
} else {
|
||||
throw new QueryParsingException(parseContext, "[field_masking_span] query does not support ["
|
||||
+ currentFieldName + "]");
|
||||
|
@ -89,17 +83,10 @@ public class FieldMaskingSpanQueryParser extends BaseQueryParserTemp {
|
|||
throw new QueryParsingException(parseContext, "field_masking_span must have [field] set for it");
|
||||
}
|
||||
|
||||
MappedFieldType fieldType = parseContext.fieldMapper(field);
|
||||
if (fieldType != null) {
|
||||
field = fieldType.names().indexName();
|
||||
}
|
||||
|
||||
FieldMaskingSpanQuery query = new FieldMaskingSpanQuery(inner, field);
|
||||
query.setBoost(boost);
|
||||
if (queryName != null) {
|
||||
parseContext.addNamedQuery(queryName, query);
|
||||
}
|
||||
return query;
|
||||
FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(inner, field);
|
||||
queryBuilder.boost(boost);
|
||||
queryBuilder.queryName(queryName);
|
||||
return queryBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.FieldMaskingSpanQuery;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class FieldMaskingSpanQueryBuilderTest extends BaseQueryTestCase<FieldMaskingSpanQueryBuilder> {
|
||||
|
||||
@Override
|
||||
protected Query createExpectedQuery(FieldMaskingSpanQueryBuilder testQueryBuilder, QueryParseContext context) throws IOException {
|
||||
String fieldInQuery = testQueryBuilder.fieldName();
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldInQuery);
|
||||
if (fieldType != null) {
|
||||
fieldInQuery = fieldType.names().indexName();
|
||||
}
|
||||
SpanQuery innerQuery = testQueryBuilder.innerQuery().toQuery(context);
|
||||
|
||||
Query expectedQuery = new FieldMaskingSpanQuery(innerQuery, fieldInQuery);
|
||||
expectedQuery.setBoost(testQueryBuilder.boost());
|
||||
if (testQueryBuilder.queryName() != null) {
|
||||
context.addNamedQuery(testQueryBuilder.queryName(), expectedQuery);
|
||||
}
|
||||
return expectedQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertLuceneQuery(FieldMaskingSpanQueryBuilder queryBuilder, Query query, QueryParseContext context) {
|
||||
if (queryBuilder.queryName() != null) {
|
||||
Query namedQuery = context.copyNamedFilters().get(queryBuilder.queryName());
|
||||
assertThat(namedQuery, equalTo(query));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FieldMaskingSpanQueryBuilder createTestQueryBuilder() {
|
||||
String fieldName = null;
|
||||
if (randomBoolean()) {
|
||||
fieldName = randomFrom(mappedFieldNames);
|
||||
} else {
|
||||
fieldName = randomAsciiOfLengthBetween(1, 10);
|
||||
}
|
||||
SpanTermQueryBuilder innerQuery = new SpanTermQueryBuilderTest().createTestQueryBuilder();
|
||||
FieldMaskingSpanQueryBuilder query = new FieldMaskingSpanQueryBuilder(innerQuery, fieldName);
|
||||
if (randomBoolean()) {
|
||||
query.boost(2.0f / randomIntBetween(1, 20));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
query.queryName(randomAsciiOfLengthBetween(1, 10));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidate() {
|
||||
FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(new SpanTermQueryBuilder("name", "value"), "fieldName");
|
||||
assertNull(queryBuilder.validate());
|
||||
|
||||
queryBuilder = new FieldMaskingSpanQueryBuilder(null, "fieldName");
|
||||
assertThat(queryBuilder.validate().validationErrors().size(), is(1));
|
||||
|
||||
queryBuilder = new FieldMaskingSpanQueryBuilder(null, "");
|
||||
assertThat(queryBuilder.validate().validationErrors().size(), is(2));
|
||||
|
||||
queryBuilder = new FieldMaskingSpanQueryBuilder(null, null);
|
||||
assertThat(queryBuilder.validate().validationErrors().size(), is(2));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue