diff --git a/core/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java index 513dd1a8841..aa9d9669d56 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java @@ -22,10 +22,13 @@ package org.elasticsearch.index.mapper.internal; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexOptions; +import org.apache.lucene.search.Query; +import org.apache.lucene.util.BytesRef; import org.elasticsearch.Version; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.lucene.Lucene; +import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.fielddata.FieldDataType; @@ -34,9 +37,10 @@ import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.MergeMappingException; import org.elasticsearch.index.mapper.MergeResult; -import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.MetadataFieldMapper; +import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.core.AbstractFieldMapper; +import org.elasticsearch.index.query.QueryParseContext; import java.io.IOException; import java.util.Iterator; @@ -135,6 +139,62 @@ public class IndexFieldMapper extends MetadataFieldMapper { return CONTENT_TYPE; } + @Override + public boolean useTermQueryWithQueryString() { + // As we spoof the presence of an indexed field we have to override + // the default of returning false which otherwise leads MatchQuery + // et al to run an analyzer over the query string and then try to + // hit the search index. We need them to use our termQuery(..) + // method which checks index names + return true; + } + + /** + * This termQuery impl looks at the context to determine the index that + * is being queried and then returns a MATCH_ALL_QUERY or MATCH_NO_QUERY + * if the value matches this index. This can be useful if aliases or + * wildcards are used but the aim is to restrict the query to specific + * indices + */ + @Override + public Query termQuery(Object value, @Nullable QueryParseContext context) { + if (context == null) { + return super.termQuery(value, context); + } + if (isSameIndex(value, context.index().getName())) { + return Queries.newMatchAllQuery(); + } else { + return Queries.newMatchNoDocsQuery(); + } + } + + + + @Override + public Query termsQuery(List values, QueryParseContext context) { + if (context == null) { + return super.termsQuery(values, context); + } + for (Object value : values) { + if (isSameIndex(value, context.index().getName())) { + // No need to OR these clauses - we can only logically be + // running in the context of just one of these index names. + return Queries.newMatchAllQuery(); + } + } + // None of the listed index names are this one + return Queries.newMatchNoDocsQuery(); + } + + private boolean isSameIndex(Object value, String indexName) { + if (value instanceof BytesRef) { + BytesRef indexNameRef = new BytesRef(indexName); + return (indexNameRef.bytesEquals((BytesRef) value)); + } else { + return indexName.equals(value.toString()); + } + } + @Override public String value(Object value) { if (value == null) { diff --git a/core/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java b/core/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java index ee08d41c71e..21b2c83af76 100644 --- a/core/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java +++ b/core/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java @@ -699,6 +699,58 @@ public class SearchQueryTests extends ElasticsearchIntegrationTest { assertSearchHits(searchResponse, "1", "3"); } + @Test + public void term_indexQueryTestsIndexed() throws Exception { + term_indexQueryTests("not_analyzed"); + } + + @Test + public void term_indexQueryTestsNotIndexed() throws Exception { + term_indexQueryTests("no"); + } + + private void term_indexQueryTests(String index) throws Exception { + Settings indexSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_1_4_2.id).build(); + String[] indexNames = { "test1", "test2" }; + for (String indexName : indexNames) { + assertAcked(client() + .admin() + .indices() + .prepareCreate(indexName) + .setSettings(indexSettings) + .addMapping( + "type1", + jsonBuilder().startObject().startObject("type1").startObject("_index").field("index", index).endObject() + .endObject().endObject())); + + indexRandom(true, client().prepareIndex(indexName, "type1", indexName + "1").setSource("field1", "value1")); + + } + for (String indexName : indexNames) { + SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(termQuery("_index", indexName))).get(); + SearchResponse searchResponse = assertSearchResponse(request); + assertHitCount(searchResponse, 1l); + assertSearchHits(searchResponse, indexName + "1"); + } + for (String indexName : indexNames) { + SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(termsQuery("_index", indexName))).get(); + SearchResponse searchResponse = assertSearchResponse(request); + assertHitCount(searchResponse, 1l); + assertSearchHits(searchResponse, indexName + "1"); + } + for (String indexName : indexNames) { + SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(matchQuery("_index", indexName))).get(); + SearchResponse searchResponse = assertSearchResponse(request); + assertHitCount(searchResponse, 1l); + assertSearchHits(searchResponse, indexName + "1"); + } + { + SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(termsQuery("_index", indexNames))).get(); + SearchResponse searchResponse = assertSearchResponse(request); + assertHitCount(searchResponse, indexNames.length); + } + } + @Test public void testLimitFilter() throws Exception { assertAcked(client().admin().indices().prepareCreate("test").setSettings(SETTING_NUMBER_OF_SHARDS, 1));