Add terms/in query, alias terms filter to be in filter as well, closes #557.
This commit is contained in:
parent
0828f18738
commit
167d35807c
|
@ -227,6 +227,7 @@ public class IndexQueryParserModule extends AbstractModule {
|
|||
bindings.processXContentQueryParser(QueryStringQueryParser.NAME, QueryStringQueryParser.class);
|
||||
bindings.processXContentQueryParser(BoolQueryParser.NAME, BoolQueryParser.class);
|
||||
bindings.processXContentQueryParser(TermQueryParser.NAME, TermQueryParser.class);
|
||||
bindings.processXContentQueryParser(TermsQueryParser.NAME, TermsQueryParser.class);
|
||||
bindings.processXContentQueryParser(FuzzyQueryParser.NAME, FuzzyQueryParser.class);
|
||||
bindings.processXContentQueryParser(FieldQueryParser.NAME, FieldQueryParser.class);
|
||||
bindings.processXContentQueryParser(RangeQueryParser.NAME, RangeQueryParser.class);
|
||||
|
|
|
@ -153,6 +153,66 @@ public abstract class FilterBuilders {
|
|||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsFilterBuilder inFilter(String name, String... values) {
|
||||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsFilterBuilder inFilter(String name, int... values) {
|
||||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsFilterBuilder inFilter(String name, long... values) {
|
||||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsFilterBuilder inFilter(String name, float... values) {
|
||||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsFilterBuilder inFilter(String name, double... values) {
|
||||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsFilterBuilder inFilter(String name, Object... values) {
|
||||
return new TermsFilterBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that restricts search results to values that have a matching prefix in a given
|
||||
* field.
|
||||
|
|
|
@ -422,6 +422,137 @@ public abstract class QueryBuilders {
|
|||
return new HasChildQueryBuilder(type, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder termsQuery(String name, String... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder termsQuery(String name, int... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder termsQuery(String name, long... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder termsQuery(String name, float... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder termsQuery(String name, double... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder termsQuery(String name, Object... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder inQuery(String name, String... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder inQuery(String name, int... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder inQuery(String name, long... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder inQuery(String name, float... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder inQuery(String name, double... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filer for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public static TermsQueryBuilder inQuery(String name, Object... values) {
|
||||
return new TermsQueryBuilder(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that restricts search results to values that have a matching prefix in a given
|
||||
* field.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param prefix The prefix
|
||||
*/
|
||||
public static PrefixFilterBuilder inQuery(String name, String prefix) {
|
||||
return new PrefixFilterBuilder(name, prefix);
|
||||
}
|
||||
|
||||
private QueryBuilders() {
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class TermsFilterParser extends AbstractIndexComponent implements XConten
|
|||
}
|
||||
|
||||
@Override public String[] names() {
|
||||
return new String[]{NAME};
|
||||
return new String[]{NAME, "in"};
|
||||
}
|
||||
|
||||
@Override public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search 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.xcontent;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class TermsQueryBuilder extends BaseQueryBuilder {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Object[] values;
|
||||
|
||||
private int minimumMatch = -1;
|
||||
|
||||
private Boolean disableCoord;
|
||||
|
||||
private float boost = -1;
|
||||
|
||||
/**
|
||||
* A query for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public TermsQueryBuilder(String name, String... values) {
|
||||
this(name, (Object[]) values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A query for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public TermsQueryBuilder(String name, int... values) {
|
||||
this.name = name;
|
||||
this.values = new Integer[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A query for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public TermsQueryBuilder(String name, long... values) {
|
||||
this.name = name;
|
||||
this.values = new Long[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A query for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public TermsQueryBuilder(String name, float... values) {
|
||||
this.name = name;
|
||||
this.values = new Float[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A query for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public TermsQueryBuilder(String name, double... values) {
|
||||
this.name = name;
|
||||
this.values = new Double[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
this.values[i] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A query for a field based on several terms matching on any of them.
|
||||
*
|
||||
* @param name The field name
|
||||
* @param values The terms
|
||||
*/
|
||||
public TermsQueryBuilder(String name, Object... values) {
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of matches across the provided terms. Defaults to <tt>1</tt>.
|
||||
*/
|
||||
public TermsQueryBuilder minimumMatch(int minimumMatch) {
|
||||
this.minimumMatch = minimumMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the boost for this query. Documents matching this query will (in addition to the normal
|
||||
* weightings) have their score multiplied by the boost provided.
|
||||
*/
|
||||
public TermsQueryBuilder boost(float boost) {
|
||||
this.boost = boost;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables <tt>Similarity#coord(int,int)</tt> in scoring. Defualts to <tt>false</tt>.
|
||||
*/
|
||||
public TermsQueryBuilder disableCoord(boolean disableCoord) {
|
||||
this.disableCoord = disableCoord;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(TermsQueryParser.NAME);
|
||||
builder.startArray(name);
|
||||
for (Object value : values) {
|
||||
builder.value(value);
|
||||
}
|
||||
builder.endArray();
|
||||
|
||||
if (minimumMatch != -1) {
|
||||
builder.field("minimum_match", minimumMatch);
|
||||
}
|
||||
if (disableCoord != null) {
|
||||
builder.field("disable_coord", disableCoord);
|
||||
}
|
||||
if (boost != -1) {
|
||||
builder.field("boost", boost);
|
||||
}
|
||||
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search 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.xcontent;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.AbstractIndexComponent;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.query.QueryParsingException;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.collect.Lists.*;
|
||||
import static org.elasticsearch.common.lucene.search.Queries.*;
|
||||
import static org.elasticsearch.index.query.support.QueryParsers.*;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "terms" : {
|
||||
* "field_name" : [ "value1", "value2" ]
|
||||
* "minimum_match" : 1
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class TermsQueryParser extends AbstractIndexComponent implements XContentQueryParser {
|
||||
|
||||
public static final String NAME = "terms";
|
||||
|
||||
@Inject public TermsQueryParser(Index index, @IndexSettings Settings settings) {
|
||||
super(index, settings);
|
||||
}
|
||||
|
||||
@Override public String[] names() {
|
||||
return new String[]{NAME, "in"}; // allow both "in" and "terms" (since its similar to the "terms" filter)
|
||||
}
|
||||
|
||||
@Override public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
|
||||
String fieldName = null;
|
||||
boolean disableCoord = false;
|
||||
float boost = 1.0f;
|
||||
int minimumNumberShouldMatch = 1;
|
||||
List<String> values = newArrayList();
|
||||
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
fieldName = currentFieldName;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
String value = parser.text();
|
||||
if (value == null) {
|
||||
throw new QueryParsingException(index, "No value specified for terms query");
|
||||
}
|
||||
values.add(value);
|
||||
}
|
||||
} else if (token.isValue()) {
|
||||
if ("disable_coord".equals(currentFieldName) || "disableCoord".equals(currentFieldName)) {
|
||||
disableCoord = parser.booleanValue();
|
||||
} else if ("minimum_match".equals(currentFieldName) || "minimumMatch".equals(currentFieldName)) {
|
||||
minimumNumberShouldMatch = parser.intValue();
|
||||
} else if ("boost".equals(currentFieldName)) {
|
||||
boost = parser.floatValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FieldMapper mapper = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
mapper = smartNameFieldMappers.mapper();
|
||||
}
|
||||
}
|
||||
|
||||
BooleanQuery query = new BooleanQuery(disableCoord);
|
||||
for (String value : values) {
|
||||
if (mapper != null) {
|
||||
query.add(new BooleanClause(mapper.fieldQuery(value), BooleanClause.Occur.SHOULD));
|
||||
} else {
|
||||
query.add(new TermQuery(new Term(fieldName, value)), BooleanClause.Occur.SHOULD);
|
||||
}
|
||||
}
|
||||
query.setBoost(boost);
|
||||
if (minimumNumberShouldMatch != -1) {
|
||||
query.setMinimumNumberShouldMatch(minimumNumberShouldMatch);
|
||||
}
|
||||
return wrapSmartNameQuery(optimizeQuery(fixNegativeQueryIfNeeded(query)), smartNameFieldMappers, parseContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -760,6 +760,23 @@ public class SimpleIndexQueryParserTests {
|
|||
assertThat(clauses[3].getOccur(), equalTo(BooleanClause.Occur.SHOULD));
|
||||
}
|
||||
|
||||
@Test public void testTermsQuery() throws IOException {
|
||||
IndexQueryParser queryParser = queryParser();
|
||||
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/terms-query.json");
|
||||
Query parsedQuery = queryParser.parse(query).query();
|
||||
assertThat(parsedQuery, instanceOf(BooleanQuery.class));
|
||||
BooleanQuery booleanQuery = (BooleanQuery) parsedQuery;
|
||||
BooleanClause[] clauses = booleanQuery.getClauses();
|
||||
|
||||
assertThat(clauses.length, equalTo(2));
|
||||
|
||||
assertThat(((TermQuery) clauses[0].getQuery()).getTerm(), equalTo(new Term("name.first", "shay")));
|
||||
assertThat(clauses[0].getOccur(), equalTo(BooleanClause.Occur.SHOULD));
|
||||
|
||||
assertThat(((TermQuery) clauses[1].getQuery()).getTerm(), equalTo(new Term("name.first", "test")));
|
||||
assertThat(clauses[1].getOccur(), equalTo(BooleanClause.Occur.SHOULD));
|
||||
}
|
||||
|
||||
@Test public void testFilteredQueryBuilder() throws IOException {
|
||||
IndexQueryParser queryParser = queryParser();
|
||||
Query parsedQuery = queryParser.parse(filteredQuery(termQuery("name.first", "shay"), termFilter("name.last", "banon"))).query();
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"terms" : { "name.first" : ["shay", "test"] }
|
||||
}
|
Loading…
Reference in New Issue