Query DSL: prefix query to support _id, closes #1648.
This commit is contained in:
parent
b2a3332698
commit
49b6d70dfd
|
@ -190,7 +190,6 @@ public class MapperQueryParser extends QueryParser {
|
|||
|
||||
@Override
|
||||
protected Query getPrefixQuery(String field, String termStr) throws ParseException {
|
||||
String indexedNameField = field;
|
||||
currentMapper = null;
|
||||
Analyzer oldAnalyzer = analyzer;
|
||||
try {
|
||||
|
@ -201,11 +200,26 @@ public class MapperQueryParser extends QueryParser {
|
|||
}
|
||||
currentMapper = fieldMappers.fieldMappers().mapper();
|
||||
if (currentMapper != null) {
|
||||
indexedNameField = currentMapper.names().indexName();
|
||||
Query query = null;
|
||||
if (currentMapper.useFieldQueryWithQueryString()) {
|
||||
if (fieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{fieldMappers.docMapper().type()});
|
||||
try {
|
||||
query = currentMapper.prefixQuery(termStr, multiTermRewriteMethod, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
query = currentMapper.prefixQuery(termStr, multiTermRewriteMethod, parseContext);
|
||||
}
|
||||
}
|
||||
if (query == null) {
|
||||
query = super.getPrefixQuery(currentMapper.names().indexName(), termStr);
|
||||
}
|
||||
return wrapSmartNameQuery(query, fieldMappers, parseContext);
|
||||
}
|
||||
return wrapSmartNameQuery(getPossiblyAnalyzedPrefixQuery(indexedNameField, termStr), fieldMappers, parseContext);
|
||||
}
|
||||
return getPossiblyAnalyzedPrefixQuery(indexedNameField, termStr);
|
||||
return super.getPrefixQuery(field, termStr);
|
||||
} finally {
|
||||
analyzer = oldAnalyzer;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.lucene.document.Field;
|
|||
import org.apache.lucene.document.Fieldable;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.index.field.data.FieldDataType;
|
||||
|
@ -173,6 +174,10 @@ public interface FieldMapper<T> {
|
|||
|
||||
Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions);
|
||||
|
||||
Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryParseContext context);
|
||||
|
||||
Filter prefixFilter(String value, @Nullable QueryParseContext context);
|
||||
|
||||
/**
|
||||
* A term query to use when parsing a query string. Can return <tt>null</tt>.
|
||||
*/
|
||||
|
|
|
@ -380,6 +380,20 @@ public abstract class AbstractFieldMapper<T> implements FieldMapper<T>, Mapper {
|
|||
return new FuzzyQuery(names().createIndexNameTerm(value), (float) minSim, prefixLength, maxExpansions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryParseContext context) {
|
||||
PrefixQuery query = new PrefixQuery(names().createIndexNameTerm(indexedValue(value)));
|
||||
if (method != null) {
|
||||
query.setRewriteMethod(method);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter prefixFilter(String value, @Nullable QueryParseContext context) {
|
||||
return new PrefixFilter(names().createIndexNameTerm(indexedValue(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
|
||||
return new TermRangeQuery(names.indexName(),
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
package org.elasticsearch.index.mapper.internal;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.Fieldable;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
import org.elasticsearch.common.lucene.search.XBooleanFilter;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.*;
|
||||
|
@ -37,6 +37,7 @@ import org.elasticsearch.index.query.QueryParseContext;
|
|||
import org.elasticsearch.index.search.UidFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.index.mapper.MapperBuilders.id;
|
||||
|
@ -175,6 +176,45 @@ public class IdFieldMapper extends AbstractFieldMapper<String> implements Intern
|
|||
return new UidFilter(context.queryTypes(), ImmutableList.of(value), context.indexCache().bloomCache());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryParseContext context) {
|
||||
if (indexed() || context == null) {
|
||||
return super.prefixQuery(value, method, context);
|
||||
}
|
||||
Collection<String> queryTypes = context.queryTypes();
|
||||
if (queryTypes.size() == 1) {
|
||||
PrefixQuery prefixQuery = new PrefixQuery(UidFieldMapper.TERM_FACTORY.createTerm(Uid.createUid(Iterables.getFirst(queryTypes, null), value)));
|
||||
if (method != null) {
|
||||
prefixQuery.setRewriteMethod(method);
|
||||
}
|
||||
}
|
||||
BooleanQuery query = new BooleanQuery();
|
||||
for (String queryType : queryTypes) {
|
||||
PrefixQuery prefixQuery = new PrefixQuery(UidFieldMapper.TERM_FACTORY.createTerm(Uid.createUid(queryType, value)));
|
||||
if (method != null) {
|
||||
prefixQuery.setRewriteMethod(method);
|
||||
}
|
||||
query.add(prefixQuery, BooleanClause.Occur.SHOULD);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter prefixFilter(String value, @Nullable QueryParseContext context) {
|
||||
if (indexed() || context == null) {
|
||||
return super.prefixFilter(value, context);
|
||||
}
|
||||
Collection<String> queryTypes = context.queryTypes();
|
||||
if (queryTypes.size() == 1) {
|
||||
return new PrefixFilter(UidFieldMapper.TERM_FACTORY.createTerm(Uid.createUid(Iterables.getFirst(queryTypes, null), value)));
|
||||
}
|
||||
XBooleanFilter filter = new XBooleanFilter();
|
||||
for (String queryType : queryTypes) {
|
||||
filter.addShould(new PrefixFilter(UidFieldMapper.TERM_FACTORY.createTerm(Uid.createUid(queryType, value))));
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preParse(ParseContext context) throws IOException {
|
||||
if (context.sourceToParse().id() != null) {
|
||||
|
|
|
@ -74,10 +74,8 @@ public class ExistsFilterParser implements FilterParser {
|
|||
|
||||
Filter filter = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
filter = smartNameFieldMappers.mapper().rangeFilter(null, null, true, true);
|
||||
}
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
filter = smartNameFieldMappers.mapper().rangeFilter(null, null, true, true);
|
||||
}
|
||||
if (filter == null) {
|
||||
filter = new TermRangeFilter(fieldName, null, null, true, true);
|
||||
|
|
|
@ -75,10 +75,8 @@ public class MissingFilterParser implements FilterParser {
|
|||
|
||||
Filter filter = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
filter = smartNameFieldMappers.mapper().rangeFilter(null, null, true, true);
|
||||
}
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
filter = smartNameFieldMappers.mapper().rangeFilter(null, null, true, true);
|
||||
}
|
||||
if (filter == null) {
|
||||
filter = new TermRangeFilter(fieldName, null, null, true, true);
|
||||
|
|
|
@ -83,10 +83,16 @@ public class PrefixFilterParser implements FilterParser {
|
|||
Filter filter = null;
|
||||
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
value = smartNameFieldMappers.mapper().indexedValue(value);
|
||||
filter = new PrefixFilter(smartNameFieldMappers.mapper().names().createIndexNameTerm(value));
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
try {
|
||||
filter = smartNameFieldMappers.mapper().prefixFilter(value, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
filter = smartNameFieldMappers.mapper().prefixFilter(value, parseContext);
|
||||
}
|
||||
}
|
||||
if (filter == null) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
|
@ -90,18 +91,27 @@ public class PrefixQueryParser implements QueryParser {
|
|||
throw new QueryParsingException(parseContext.index(), "No value specified for prefix query");
|
||||
}
|
||||
|
||||
PrefixQuery query = null;
|
||||
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(rewriteMethod);
|
||||
|
||||
Query query = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
value = smartNameFieldMappers.mapper().indexedValue(value);
|
||||
query = new PrefixQuery(smartNameFieldMappers.mapper().names().createIndexNameTerm(value));
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
try {
|
||||
query = smartNameFieldMappers.mapper().prefixQuery(value, method, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
query = smartNameFieldMappers.mapper().prefixQuery(value, method, parseContext);
|
||||
}
|
||||
}
|
||||
if (query == null) {
|
||||
query = new PrefixQuery(new Term(fieldName, value));
|
||||
PrefixQuery prefixQuery = new PrefixQuery(new Term(fieldName, value));
|
||||
prefixQuery.setRewriteMethod(method);
|
||||
query = prefixQuery;
|
||||
}
|
||||
query.setRewriteMethod(QueryParsers.parseRewriteMethod(rewriteMethod));
|
||||
query.setBoost(boost);
|
||||
return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
|
||||
}
|
||||
|
|
|
@ -86,18 +86,16 @@ public class TermFilterParser implements FilterParser {
|
|||
|
||||
Filter filter = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
try {
|
||||
filter = smartNameFieldMappers.mapper().fieldFilter(value, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
try {
|
||||
filter = smartNameFieldMappers.mapper().fieldFilter(value, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
filter = smartNameFieldMappers.mapper().fieldFilter(value, parseContext);
|
||||
}
|
||||
}
|
||||
if (filter == null) {
|
||||
|
|
|
@ -89,18 +89,16 @@ public class TermQueryParser implements QueryParser {
|
|||
|
||||
Query query = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
try {
|
||||
query = smartNameFieldMappers.mapper().fieldQuery(value, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
try {
|
||||
query = smartNameFieldMappers.mapper().fieldQuery(value, parseContext);
|
||||
} finally {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
} else {
|
||||
query = smartNameFieldMappers.mapper().fieldQuery(value, parseContext);
|
||||
}
|
||||
}
|
||||
if (query == null) {
|
||||
|
|
|
@ -97,25 +97,33 @@ public class TermsQueryParser implements QueryParser {
|
|||
|
||||
FieldMapper mapper = null;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
mapper = smartNameFieldMappers.mapper();
|
||||
String[] previousTypes = null;
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
mapper = smartNameFieldMappers.mapper();
|
||||
if (smartNameFieldMappers.hasDocMapper()) {
|
||||
previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
|
||||
}
|
||||
}
|
||||
|
||||
BooleanQuery query = new BooleanQuery(disableCoord);
|
||||
for (String value : values) {
|
||||
if (mapper != null) {
|
||||
query.add(new BooleanClause(mapper.fieldQuery(value, parseContext), BooleanClause.Occur.SHOULD));
|
||||
} else {
|
||||
query.add(new TermQuery(new Term(fieldName, value)), BooleanClause.Occur.SHOULD);
|
||||
try {
|
||||
BooleanQuery query = new BooleanQuery(disableCoord);
|
||||
for (String value : values) {
|
||||
if (mapper != null) {
|
||||
query.add(new BooleanClause(mapper.fieldQuery(value, parseContext), 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);
|
||||
} finally {
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasDocMapper()) {
|
||||
QueryParseContext.setTypes(previousTypes);
|
||||
}
|
||||
}
|
||||
query.setBoost(boost);
|
||||
if (minimumNumberShouldMatch != -1) {
|
||||
query.setMinimumNumberShouldMatch(minimumNumberShouldMatch);
|
||||
}
|
||||
return wrapSmartNameQuery(optimizeQuery(fixNegativeQueryIfNeeded(query)), smartNameFieldMappers, parseContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,11 +91,9 @@ public class WildcardQueryParser implements QueryParser {
|
|||
}
|
||||
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
fieldName = smartNameFieldMappers.mapper().names().indexName();
|
||||
value = smartNameFieldMappers.mapper().indexedValue(value);
|
||||
}
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
fieldName = smartNameFieldMappers.mapper().names().indexName();
|
||||
value = smartNameFieldMappers.mapper().indexedValue(value);
|
||||
}
|
||||
|
||||
WildcardQuery query = new WildcardQuery(new Term(fieldName, value));
|
||||
|
|
|
@ -106,13 +106,9 @@ public class TextQueryParser {
|
|||
FieldMapper mapper = null;
|
||||
String field = fieldName;
|
||||
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
|
||||
if (smartNameFieldMappers != null) {
|
||||
if (smartNameFieldMappers.hasMapper()) {
|
||||
mapper = smartNameFieldMappers.mapper();
|
||||
if (mapper != null) {
|
||||
field = mapper.names().indexName();
|
||||
}
|
||||
}
|
||||
if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
|
||||
mapper = smartNameFieldMappers.mapper();
|
||||
field = mapper.names().indexName();
|
||||
}
|
||||
|
||||
if (mapper != null && mapper.useFieldQueryWithQueryString()) {
|
||||
|
|
|
@ -81,12 +81,19 @@ public class SimpleSearchTests extends AbstractNodesTests {
|
|||
client.admin().indices().prepareDelete().execute().actionGet();
|
||||
client.admin().indices().prepareCreate("test").setSettings(ImmutableSettings.settingsBuilder().put("number_of_shards", 1)).execute().actionGet();
|
||||
|
||||
client.prepareIndex("test", "type", "1").setSource("field", "value").setRefresh(true).execute().actionGet();
|
||||
client.prepareIndex("test", "type", "XXX1").setSource("field", "value").setRefresh(true).execute().actionGet();
|
||||
// id is not indexed, but lets see that we automatically convert to
|
||||
SearchResponse searchResponse = client.prepareSearch().setQuery(QueryBuilders.termQuery("_id", "1")).execute().actionGet();
|
||||
SearchResponse searchResponse = client.prepareSearch().setQuery(QueryBuilders.termQuery("_id", "XXX1")).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
|
||||
searchResponse = client.prepareSearch().setQuery(QueryBuilders.queryString("_id:1")).execute().actionGet();
|
||||
searchResponse = client.prepareSearch().setQuery(QueryBuilders.queryString("_id:XXX1")).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
|
||||
// id is not index, but we can automatically support prefix as well
|
||||
searchResponse = client.prepareSearch().setQuery(QueryBuilders.prefixQuery("_id", "XXX")).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
|
||||
searchResponse = client.prepareSearch().setQuery(QueryBuilders.queryString("_id:XXX*")).execute().actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue