From 2cbecd9cb372fa5c55dfbffeaedb2c8bebfe02e1 Mon Sep 17 00:00:00 2001 From: Luca Cavanna Date: Tue, 6 Aug 2013 10:32:52 +0200 Subject: [PATCH] Made sure that we never throw IndexMissingException in indices query and filter It could happen although we internally use IgnoreIndices.MISSING, due to MetaData#concreteIndices contract, which throws IndexMissingException anyway if all requested indices are missing. In case all the indices specified in the query/filter are missing, we just execute the no_match query/filter, no need to throw any error. Closes #3428 --- .../index/query/IndicesFilterParser.java | 11 +- .../index/query/IndicesQueryParser.java | 11 +- .../search/query/SimpleQueryTests.java | 143 ++++++++++++++++++ 3 files changed, 163 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/elasticsearch/index/query/IndicesFilterParser.java b/src/main/java/org/elasticsearch/index/query/IndicesFilterParser.java index 785082b736e..0e1b097ce61 100644 --- a/src/main/java/org/elasticsearch/index/query/IndicesFilterParser.java +++ b/src/main/java/org/elasticsearch/index/query/IndicesFilterParser.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.indices.IndexMissingException; import java.io.IOException; import java.util.ArrayList; @@ -146,7 +147,15 @@ public class IndicesFilterParser implements FilterParser { } protected boolean matchesIndices(String currentIndex, String... indices) { - String[] concreteIndices = clusterService.state().metaData().concreteIndices(indices, IgnoreIndices.MISSING, true); + final String[] concreteIndices; + try { + concreteIndices = clusterService.state().metaData().concreteIndices(indices, IgnoreIndices.MISSING, true); + } catch(IndexMissingException e) { + //Although we use IgnoreIndices.MISSING, according to MetaData#concreteIndices contract, + // we get IndexMissing either when we have a single index that is missing or when all indices are missing + return false; + } + for (String index : concreteIndices) { if (Regex.simpleMatch(index, currentIndex)) { return true; diff --git a/src/main/java/org/elasticsearch/index/query/IndicesQueryParser.java b/src/main/java/org/elasticsearch/index/query/IndicesQueryParser.java index f260810fc44..16fee49dc0a 100644 --- a/src/main/java/org/elasticsearch/index/query/IndicesQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/IndicesQueryParser.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.indices.IndexMissingException; import java.io.IOException; import java.util.ArrayList; @@ -144,7 +145,15 @@ public class IndicesQueryParser implements QueryParser { } protected boolean matchesIndices(String currentIndex, String... indices) { - String[] concreteIndices = clusterService.state().metaData().concreteIndices(indices, IgnoreIndices.MISSING, true); + final String[] concreteIndices; + try { + concreteIndices = clusterService.state().metaData().concreteIndices(indices, IgnoreIndices.MISSING, true); + } catch(IndexMissingException e) { + //Although we use IgnoreIndices.MISSING, according to MetaData#concreteIndices contract, + // we get IndexMissing either when we have a single index that is missing or when all indices are missing + return false; + } + for (String index : concreteIndices) { if (Regex.simpleMatch(index, currentIndex)) { return true; diff --git a/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java b/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java index 4fcc0c81371..2be094f69c4 100644 --- a/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java +++ b/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java @@ -1686,6 +1686,149 @@ public class SimpleQueryTests extends ElasticsearchIntegrationTest { assertSearchHits(searchResponse, "1", "2"); } + @Test + public void testIndicesQueryMissingIndices() throws IOException { + createIndex("index1"); + createIndex("index2"); + ensureGreen(); + + client().prepareIndex("index1", "type1", "1").setSource("field", "match").get(); + client().prepareIndex("index1", "type1", "2").setSource("field", "no_match").get(); + client().prepareIndex("index2", "type1", "10").setSource("field", "match").get(); + client().prepareIndex("index2", "type1", "20").setSource("field", "no_match").get(); + client().prepareIndex("index3", "type1", "100").setSource("field", "match").get(); + client().prepareIndex("index3", "type1", "200").setSource("field", "no_match").get(); + refresh(); + + //all indices are missing + SearchResponse searchResponse = client().prepareSearch().setQuery( + indicesQuery(termQuery("field", "missing"), "test1", "test2", "test3") + .noMatchQuery(termQuery("field", "match"))).get(); + + assertHitCount(searchResponse, 3l); + + for (SearchHit hit : searchResponse.getHits().getHits()) { + if ("index1".equals(hit.index())) { + assertThat(hit, hasId("1")); + } else if ("index2".equals(hit.index())) { + assertThat(hit, hasId("10")); + } else if ("index3".equals(hit.index())) { + assertThat(hit, hasId("100")); + } else { + fail("Returned documents should belong to either index1, index2 or index3"); + } + } + + //only one index specified, which is missing + searchResponse = client().prepareSearch().setQuery( + indicesQuery(termQuery("field", "missing"), "test1") + .noMatchQuery(termQuery("field", "match"))).get(); + + assertHitCount(searchResponse, 3l); + + for (SearchHit hit : searchResponse.getHits().getHits()) { + if ("index1".equals(hit.index())) { + assertThat(hit, hasId("1")); + } else if ("index2".equals(hit.index())) { + assertThat(hit, hasId("10")); + } else if ("index3".equals(hit.index())) { + assertThat(hit, hasId("100")); + } else { + fail("Returned documents should belong to either index1, index2 or index3"); + } + } + + //more than one index specified, one of them is missing + searchResponse = client().prepareSearch().setQuery( + indicesQuery(termQuery("field", "missing"), "index1", "test1") + .noMatchQuery(termQuery("field", "match"))).get(); + + assertHitCount(searchResponse, 2l); + + for (SearchHit hit : searchResponse.getHits().getHits()) { + if ("index2".equals(hit.index())) { + assertThat(hit, hasId("10")); + } else if ("index3".equals(hit.index())) { + assertThat(hit, hasId("100")); + } else { + fail("Returned documents should belong to either index2 or index3"); + } + } + } + + @Test + public void testIndicesFilterMissingIndices() throws IOException { + createIndex("index1"); + createIndex("index2"); + ensureGreen(); + + client().prepareIndex("index1", "type1", "1").setSource("field", "match").get(); + client().prepareIndex("index1", "type1", "2").setSource("field", "no_match").get(); + client().prepareIndex("index2", "type1", "10").setSource("field", "match").get(); + client().prepareIndex("index2", "type1", "20").setSource("field", "no_match").get(); + client().prepareIndex("index3", "type1", "100").setSource("field", "match").get(); + client().prepareIndex("index3", "type1", "200").setSource("field", "no_match").get(); + refresh(); + + //all indices are missing + SearchResponse searchResponse = client().prepareSearch().setQuery( + filteredQuery(matchAllQuery(), + indicesFilter(termFilter("field", "missing"), "test1", "test2", "test3") + .noMatchFilter(termFilter("field", "match")))).get(); + + assertHitCount(searchResponse, 3l); + + for (SearchHit hit : searchResponse.getHits().getHits()) { + if ("index1".equals(hit.index())) { + assertThat(hit, hasId("1")); + } else if ("index2".equals(hit.index())) { + assertThat(hit, hasId("10")); + } else if ("index3".equals(hit.index())) { + assertThat(hit, hasId("100")); + } else { + fail("Returned documents should belong to either index1, index2 or index3"); + } + } + + //only one index specified, which is missing + searchResponse = client().prepareSearch().setQuery( + filteredQuery(matchAllQuery(), + indicesFilter(termFilter("field", "missing"), "test1") + .noMatchFilter(termFilter("field", "match")))).get(); + + assertHitCount(searchResponse, 3l); + + for (SearchHit hit : searchResponse.getHits().getHits()) { + if ("index1".equals(hit.index())) { + assertThat(hit, hasId("1")); + } else if ("index2".equals(hit.index())) { + assertThat(hit, hasId("10")); + } else if ("index3".equals(hit.index())) { + assertThat(hit, hasId("100")); + } else { + fail("Returned documents should belong to either index1, index2 or index3"); + } + } + + //more than one index specified, one of them is missing + searchResponse = client().prepareSearch().setQuery( + filteredQuery(matchAllQuery(), + indicesFilter(termFilter("field", "missing"), "index1", "test1") + .noMatchFilter(termFilter("field", "match")))).get(); + + assertHitCount(searchResponse, 2l); + + for (SearchHit hit : searchResponse.getHits().getHits()) { + if ("index2".equals(hit.index())) { + assertThat(hit, hasId("10")); + } else if ("index3".equals(hit.index())) { + assertThat(hit, hasId("100")); + } else { + fail("Returned documents should belong to either index2 or index3"); + } + } + } + @Test public void testMinScore() { createIndex("test");