Query DSL: prefix query to support _id, closes #1648.

This commit is contained in:
Shay Banon 2012-01-29 21:09:11 +02:00
parent b2a3332698
commit 49b6d70dfd
14 changed files with 165 additions and 75 deletions

View File

@ -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;
}

View File

@ -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>.
*/

View File

@ -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(),

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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()) {

View File

@ -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));
}