Skip to content

Commit f95981b

Browse files
committed
Search enhancement: adds a special case for the “_index” field which allows queries to test the name of the index. Adding this capability means we can deprecate the specialist indices query.
IndexFieldMapper is changed to make the term query factories produce match_all or match_none queries based on tests on the index name. Closes #3316
1 parent d085088 commit f95981b

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

core/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@
2222
import org.apache.lucene.document.Document;
2323
import org.apache.lucene.document.Field;
2424
import org.apache.lucene.index.IndexOptions;
25+
import org.apache.lucene.search.Query;
26+
import org.apache.lucene.util.BytesRef;
2527
import org.elasticsearch.Version;
2628
import org.elasticsearch.common.Nullable;
2729
import org.elasticsearch.common.Strings;
2830
import org.elasticsearch.common.lucene.Lucene;
31+
import org.elasticsearch.common.lucene.search.Queries;
2932
import org.elasticsearch.common.settings.Settings;
3033
import org.elasticsearch.common.xcontent.XContentBuilder;
3134
import org.elasticsearch.index.fielddata.FieldDataType;
@@ -34,9 +37,10 @@
3437
import org.elasticsearch.index.mapper.MapperParsingException;
3538
import org.elasticsearch.index.mapper.MergeMappingException;
3639
import org.elasticsearch.index.mapper.MergeResult;
37-
import org.elasticsearch.index.mapper.ParseContext;
3840
import org.elasticsearch.index.mapper.MetadataFieldMapper;
41+
import org.elasticsearch.index.mapper.ParseContext;
3942
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
43+
import org.elasticsearch.index.query.QueryParseContext;
4044

4145
import java.io.IOException;
4246
import java.util.Iterator;
@@ -135,6 +139,62 @@ public String typeName() {
135139
return CONTENT_TYPE;
136140
}
137141

142+
@Override
143+
public boolean useTermQueryWithQueryString() {
144+
// As we spoof the presence of an indexed field we have to override
145+
// the default of returning false which otherwise leads MatchQuery
146+
// et al to run an analyzer over the query string and then try to
147+
// hit the search index. We need them to use our termQuery(..)
148+
// method which checks index names
149+
return true;
150+
}
151+
152+
/**
153+
* This termQuery impl looks at the context to determine the index that
154+
* is being queried and then returns a MATCH_ALL_QUERY or MATCH_NO_QUERY
155+
* if the value matches this index. This can be useful if aliases or
156+
* wildcards are used but the aim is to restrict the query to specific
157+
* indices
158+
*/
159+
@Override
160+
public Query termQuery(Object value, @Nullable QueryParseContext context) {
161+
if (context == null) {
162+
return super.termQuery(value, context);
163+
}
164+
if (isSameIndex(value, context.index().getName())) {
165+
return Queries.newMatchAllQuery();
166+
} else {
167+
return Queries.newMatchNoDocsQuery();
168+
}
169+
}
170+
171+
172+
173+
@Override
174+
public Query termsQuery(List values, QueryParseContext context) {
175+
if (context == null) {
176+
return super.termsQuery(values, context);
177+
}
178+
for (Object value : values) {
179+
if (isSameIndex(value, context.index().getName())) {
180+
// No need to OR these clauses - we can only logically be
181+
// running in the context of just one of these index names.
182+
return Queries.newMatchAllQuery();
183+
}
184+
}
185+
// None of the listed index names are this one
186+
return Queries.newMatchNoDocsQuery();
187+
}
188+
189+
private boolean isSameIndex(Object value, String indexName) {
190+
if (value instanceof BytesRef) {
191+
BytesRef indexNameRef = new BytesRef(indexName);
192+
return (indexNameRef.bytesEquals((BytesRef) value));
193+
} else {
194+
return indexName.equals(value.toString());
195+
}
196+
}
197+
138198
@Override
139199
public String value(Object value) {
140200
if (value == null) {

core/src/test/java/org/elasticsearch/search/query/SearchQueryTests.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,58 @@ private void idsQueryTests(String index) throws Exception {
699699
assertSearchHits(searchResponse, "1", "3");
700700
}
701701

702+
@Test
703+
public void term_indexQueryTestsIndexed() throws Exception {
704+
term_indexQueryTests("not_analyzed");
705+
}
706+
707+
@Test
708+
public void term_indexQueryTestsNotIndexed() throws Exception {
709+
term_indexQueryTests("no");
710+
}
711+
712+
private void term_indexQueryTests(String index) throws Exception {
713+
Settings indexSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_1_4_2.id).build();
714+
String[] indexNames = { "test1", "test2" };
715+
for (String indexName : indexNames) {
716+
assertAcked(client()
717+
.admin()
718+
.indices()
719+
.prepareCreate(indexName)
720+
.setSettings(indexSettings)
721+
.addMapping(
722+
"type1",
723+
jsonBuilder().startObject().startObject("type1").startObject("_index").field("index", index).endObject()
724+
.endObject().endObject()));
725+
726+
indexRandom(true, client().prepareIndex(indexName, "type1", indexName + "1").setSource("field1", "value1"));
727+
728+
}
729+
for (String indexName : indexNames) {
730+
SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(termQuery("_index", indexName))).get();
731+
SearchResponse searchResponse = assertSearchResponse(request);
732+
assertHitCount(searchResponse, 1l);
733+
assertSearchHits(searchResponse, indexName + "1");
734+
}
735+
for (String indexName : indexNames) {
736+
SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(termsQuery("_index", indexName))).get();
737+
SearchResponse searchResponse = assertSearchResponse(request);
738+
assertHitCount(searchResponse, 1l);
739+
assertSearchHits(searchResponse, indexName + "1");
740+
}
741+
for (String indexName : indexNames) {
742+
SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(matchQuery("_index", indexName))).get();
743+
SearchResponse searchResponse = assertSearchResponse(request);
744+
assertHitCount(searchResponse, 1l);
745+
assertSearchHits(searchResponse, indexName + "1");
746+
}
747+
{
748+
SearchResponse request = client().prepareSearch().setQuery(constantScoreQuery(termsQuery("_index", indexNames))).get();
749+
SearchResponse searchResponse = assertSearchResponse(request);
750+
assertHitCount(searchResponse, indexNames.length);
751+
}
752+
}
753+
702754
@Test
703755
public void testLimitFilter() throws Exception {
704756
assertAcked(client().admin().indices().prepareCreate("test").setSettings(SETTING_NUMBER_OF_SHARDS, 1));

0 commit comments

Comments
 (0)