diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yml index 03f218b140b8f..653979073b707 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search_shards/10_basic.yml @@ -64,10 +64,9 @@ - length: { shards: 1 } - match: { shards.0.0.index: test_index } - match: { indices.test_index.aliases: [test_alias_filter_1, test_alias_filter_2]} - - match: { indices.test_index.filter.bool.should.0.term.field.value: value1 } + - length: { indices.test_index.filter.bool.should: 2 } - lte: { indices.test_index.filter.bool.should.0.term.field.boost: 1.0 } - gte: { indices.test_index.filter.bool.should.0.term.field.boost: 1.0 } - - match: { indices.test_index.filter.bool.should.1.term.field.value: value2} - lte: { indices.test_index.filter.bool.should.1.term.field.boost: 1.0 } - gte: { indices.test_index.filter.bool.should.1.term.field.boost: 1.0 } - match: { indices.test_index.filter.bool.adjust_pure_negative: true} diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java index 41dce3148c1df..39006cd1e8407 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/shards/TransportClusterSearchShardsAction.java @@ -88,10 +88,11 @@ protected void masterOperation(final ClusterSearchShardsRequest request, final C String[] concreteIndices = indexNameExpressionResolver.concreteIndexNames(clusterState, request); Map> routingMap = indexNameExpressionResolver.resolveSearchRouting(state, request.routing(), request.indices()); Map indicesAndFilters = new HashMap<>(); + Set indicesAndAliases = indexNameExpressionResolver.resolveExpressions(clusterState, request.indices()); for (String index : concreteIndices) { - final AliasFilter aliasFilter = indicesService.buildAliasFilter(clusterState, index, request.indices()); + final AliasFilter aliasFilter = indicesService.buildAliasFilter(clusterState, index, indicesAndAliases); final String[] aliases = indexNameExpressionResolver.indexAliases(clusterState, index, aliasMetadata -> true, true, - request.indices()); + indicesAndAliases); indicesAndFilters.put(index, new AliasFilter(aliasFilter.getQueryBuilder(), aliases)); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java index 7016d1b42894f..6e10d3d42187f 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java @@ -115,8 +115,9 @@ protected void doExecute(Task task, ValidateQueryRequest request, ActionListener @Override protected ShardValidateQueryRequest newShardRequest(int numShards, ShardRouting shard, ValidateQueryRequest request) { - final AliasFilter aliasFilter = searchService.buildAliasFilter(clusterService.state(), shard.getIndexName(), - request.indices()); + final ClusterState clusterState = clusterService.state(); + final Set indicesAndAliases = indexNameExpressionResolver.resolveExpressions(clusterState, request.indices()); + final AliasFilter aliasFilter = searchService.buildAliasFilter(clusterState, shard.getIndexName(), indicesAndAliases); return new ShardValidateQueryRequest(shard.shardId(), aliasFilter, request); } diff --git a/server/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java b/server/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java index cc1e842a1ee5e..fe8475322592f 100644 --- a/server/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java +++ b/server/src/main/java/org/elasticsearch/action/explain/TransportExplainAction.java @@ -52,6 +52,7 @@ import org.elasticsearch.transport.TransportService; import java.io.IOException; +import java.util.Set; /** * Explain transport action. Computes the explain on the targeted shard. @@ -83,8 +84,8 @@ protected boolean resolveIndex(ExplainRequest request) { @Override protected void resolveRequest(ClusterState state, InternalRequest request) { - final AliasFilter aliasFilter = searchService.buildAliasFilter(state, request.concreteIndex(), - request.request().index()); + final Set indicesAndAliases = indexNameExpressionResolver.resolveExpressions(state, request.request().index()); + final AliasFilter aliasFilter = searchService.buildAliasFilter(state, request.concreteIndex(), indicesAndAliases); request.request().filteringAlias(aliasFilter); // Fail fast on the node that received the request. if (request.request().routing() == null && state.getMetaData().routingRequired(request.concreteIndex())) { diff --git a/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java b/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java index 50f96a3703379..6eaf53b87c34c 100644 --- a/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java +++ b/server/src/main/java/org/elasticsearch/action/search/TransportSearchAction.java @@ -116,9 +116,10 @@ public TransportSearchAction(ThreadPool threadPool, TransportService transportSe private Map buildPerIndexAliasFilter(SearchRequest request, ClusterState clusterState, Index[] concreteIndices, Map remoteAliasMap) { final Map aliasFilterMap = new HashMap<>(); + final Set indicesAndAliases = indexNameExpressionResolver.resolveExpressions(clusterState, request.indices()); for (Index index : concreteIndices) { clusterState.blocks().indexBlockedRaiseException(ClusterBlockLevel.READ, index.getName()); - AliasFilter aliasFilter = searchService.buildAliasFilter(clusterState, index.getName(), request.indices()); + AliasFilter aliasFilter = searchService.buildAliasFilter(clusterState, index.getName(), indicesAndAliases); assert aliasFilter != null; aliasFilterMap.put(index.getUUID(), aliasFilter); } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java index 03fa790a87175..19c6d31ccc82a 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java @@ -25,6 +25,7 @@ import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.time.DateFormatter; @@ -42,15 +43,19 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.SortedMap; +import java.util.Spliterators; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import static java.util.Collections.unmodifiableList; @@ -322,71 +327,88 @@ public String resolveDateMathExpression(String dateExpression) { return dateMathExpressionResolver.resolveExpression(dateExpression, new Context(null, null)); } + /** + * Resolve an array of expressions to the set of indices and aliases that these expressions match. + */ + public Set resolveExpressions(ClusterState state, String... expressions) { + Context context = new Context(state, IndicesOptions.lenientExpandOpen(), true, false); + List resolvedExpressions = Arrays.asList(expressions); + for (ExpressionResolver expressionResolver : expressionResolvers) { + resolvedExpressions = expressionResolver.resolve(context, resolvedExpressions); + } + return Collections.unmodifiableSet(new HashSet<>(resolvedExpressions)); + } + /** * Iterates through the list of indices and selects the effective list of filtering aliases for the * given index. *

Only aliases with filters are returned. If the indices list contains a non-filtering reference to * the index itself - null is returned. Returns {@code null} if no filtering is required. + * NOTE: The provided expressions must have been resolved already via {@link #resolveExpressions}. */ - public String[] filteringAliases(ClusterState state, String index, String... expressions) { - return indexAliases(state, index, AliasMetaData::filteringRequired, false, expressions); + public String[] filteringAliases(ClusterState state, String index, Set resolvedExpressions) { + return indexAliases(state, index, AliasMetaData::filteringRequired, false, resolvedExpressions); + } + + /** + * Whether to generate the candidate set from index aliases, or from the set of resolved expressions. + * @param indexAliasesSize the number of aliases of the index + * @param resolvedExpressionsSize the number of resolved expressions + */ + // pkg-private for testing + boolean iterateIndexAliases(int indexAliasesSize, int resolvedExpressionsSize) { + return indexAliasesSize <= resolvedExpressionsSize; } /** * Iterates through the list of indices and selects the effective list of required aliases for the given index. *

Only aliases where the given predicate tests successfully are returned. If the indices list contains a non-required reference to * the index itself - null is returned. Returns {@code null} if no filtering is required. + *

NOTE: the provided expressions must have been resolved already via {@link #resolveExpressions}. */ public String[] indexAliases(ClusterState state, String index, Predicate requiredAlias, boolean skipIdentity, - String... expressions) { - // expand the aliases wildcard - List resolvedExpressions = expressions != null ? Arrays.asList(expressions) : Collections.emptyList(); - Context context = new Context(state, IndicesOptions.lenientExpandOpen(), true, false); - for (ExpressionResolver expressionResolver : expressionResolvers) { - resolvedExpressions = expressionResolver.resolve(context, resolvedExpressions); - } - + Set resolvedExpressions) { if (isAllIndices(resolvedExpressions)) { return null; } + final IndexMetaData indexMetaData = state.metaData().getIndices().get(index); if (indexMetaData == null) { // Shouldn't happen throw new IndexNotFoundException(index); } - // optimize for the most common single index/alias scenario - if (resolvedExpressions.size() == 1) { - String alias = resolvedExpressions.get(0); - AliasMetaData aliasMetaData = indexMetaData.getAliases().get(alias); - if (aliasMetaData == null || requiredAlias.test(aliasMetaData) == false) { - return null; - } - return new String[]{alias}; + if (skipIdentity == false && resolvedExpressions.contains(index)) { + return null; + } + + final ImmutableOpenMap indexAliases = indexMetaData.getAliases(); + final AliasMetaData[] aliasCandidates; + if (iterateIndexAliases(indexAliases.size(), resolvedExpressions.size())) { + // faster to iterate indexAliases + aliasCandidates = StreamSupport.stream(Spliterators.spliteratorUnknownSize(indexAliases.values().iterator(), 0), false) + .map(cursor -> cursor.value) + .filter(aliasMetaData -> resolvedExpressions.contains(aliasMetaData.alias())) + .toArray(AliasMetaData[]::new); + } else { + // faster to iterate resolvedExpressions + aliasCandidates = resolvedExpressions.stream() + .map(indexAliases::get) + .filter(Objects::nonNull) + .toArray(AliasMetaData[]::new); } + List aliases = null; - for (String alias : resolvedExpressions) { - if (alias.equals(index)) { - if (skipIdentity) { - continue; - } else { - return null; - } - } - AliasMetaData aliasMetaData = indexMetaData.getAliases().get(alias); - // Check that this is an alias for the current index - // Otherwise - skip it - if (aliasMetaData != null) { - if (requiredAlias.test(aliasMetaData)) { - // If required - add it to the list of aliases - if (aliases == null) { - aliases = new ArrayList<>(); - } - aliases.add(alias); - } else { - // If not, we have a non required alias for this index - no further checking needed - return null; + for (AliasMetaData aliasMetaData : aliasCandidates) { + if (requiredAlias.test(aliasMetaData)) { + // If required - add it to the list of aliases + if (aliases == null) { + aliases = new ArrayList<>(); } + aliases.add(aliasMetaData.alias()); + } else { + // If not, we have a non required alias for this index - no further checking needed + return null; } } if (aliases == null) { @@ -513,7 +535,7 @@ public Map> resolveSearchRoutingAllIndices(MetaData metaData * @param aliasesOrIndices the array containing index names * @return true if the provided array maps to all indices, false otherwise */ - public static boolean isAllIndices(List aliasesOrIndices) { + public static boolean isAllIndices(Collection aliasesOrIndices) { return aliasesOrIndices == null || aliasesOrIndices.isEmpty() || isExplicitAllPattern(aliasesOrIndices); } @@ -524,8 +546,8 @@ public static boolean isAllIndices(List aliasesOrIndices) { * @param aliasesOrIndices the array containing index names * @return true if the provided array explicitly maps to all indices, false otherwise */ - static boolean isExplicitAllPattern(List aliasesOrIndices) { - return aliasesOrIndices != null && aliasesOrIndices.size() == 1 && MetaData.ALL.equals(aliasesOrIndices.get(0)); + static boolean isExplicitAllPattern(Collection aliasesOrIndices) { + return aliasesOrIndices != null && aliasesOrIndices.size() == 1 && MetaData.ALL.equals(aliasesOrIndices.iterator().next()); } /** @@ -598,7 +620,7 @@ public long getStartTime() { /** * This is used to prevent resolving aliases to concrete indices but this also means * that we might return aliases that point to a closed index. This is currently only used - * by {@link #filteringAliases(ClusterState, String, String...)} since it's the only one that needs aliases + * by {@link #filteringAliases(ClusterState, String, Set)} since it's the only one that needs aliases */ boolean isPreserveAliases() { return preserveAliases; @@ -642,6 +664,8 @@ public List resolve(Context context, List expressions) { return resolveEmptyOrTrivialWildcard(options, metaData); } + // TODO: Fix API to work with sets rather than lists since we need to convert to sets + // internally anyway. Set result = innerResolve(context, expressions, options, metaData); if (result == null) { diff --git a/server/src/main/java/org/elasticsearch/indices/IndicesService.java b/server/src/main/java/org/elasticsearch/indices/IndicesService.java index 913fb47157eda..0eeca2ae2c9dd 100644 --- a/server/src/main/java/org/elasticsearch/indices/IndicesService.java +++ b/server/src/main/java/org/elasticsearch/indices/IndicesService.java @@ -1379,7 +1379,7 @@ interface IndexDeletionAllowedPredicate { (Index index, IndexSettings indexSettings) -> canDeleteIndexContents(index, indexSettings); private final IndexDeletionAllowedPredicate ALWAYS_TRUE = (Index index, IndexSettings indexSettings) -> true; - public AliasFilter buildAliasFilter(ClusterState state, String index, String... expressions) { + public AliasFilter buildAliasFilter(ClusterState state, String index, Set resolvedExpressions) { /* Being static, parseAliasFilter doesn't have access to whatever guts it needs to parse a query. Instead of passing in a bunch * of dependencies we pass in a function that can perform the parsing. */ CheckedFunction filterParser = bytes -> { @@ -1388,8 +1388,8 @@ public AliasFilter buildAliasFilter(ClusterState state, String index, String... return parseInnerQueryBuilder(parser); } }; - String[] aliases = indexNameExpressionResolver.filteringAliases(state, index, expressions); IndexMetaData indexMetaData = state.metaData().index(index); + String[] aliases = indexNameExpressionResolver.filteringAliases(state, index, resolvedExpressions); return new AliasFilter(ShardSearchRequest.parseAliasFilter(filterParser, indexMetaData, aliases), aliases); } diff --git a/server/src/main/java/org/elasticsearch/search/SearchService.java b/server/src/main/java/org/elasticsearch/search/SearchService.java index 5ad15fa626822..0b22f5d660655 100644 --- a/server/src/main/java/org/elasticsearch/search/SearchService.java +++ b/server/src/main/java/org/elasticsearch/search/SearchService.java @@ -109,6 +109,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; @@ -1004,8 +1005,8 @@ public void run() { } } - public AliasFilter buildAliasFilter(ClusterState state, String index, String... expressions) { - return indicesService.buildAliasFilter(state, index, expressions); + public AliasFilter buildAliasFilter(ClusterState state, String index, Set resolvedExpressions) { + return indicesService.buildAliasFilter(state, index, resolvedExpressions); } /** diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverAliasIterationTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverAliasIterationTests.java new file mode 100644 index 0000000000000..13d3cfd6cea95 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverAliasIterationTests.java @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.cluster.metadata; + +public class IndexNameExpressionResolverAliasIterationTests extends IndexNameExpressionResolverTests { + + protected IndexNameExpressionResolver getIndexNameExpressionResolver() { + return new IndexNameExpressionResolver() { + @Override + boolean iterateIndexAliases(int indexAliasesSize, int resolvedExpressionsSize) { + return true; + } + }; + } + +} diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverExpressionsIterationTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverExpressionsIterationTests.java new file mode 100644 index 0000000000000..00d46aad0e8cd --- /dev/null +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverExpressionsIterationTests.java @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.cluster.metadata; + +public class IndexNameExpressionResolverExpressionsIterationTests extends IndexNameExpressionResolverTests { + + protected IndexNameExpressionResolver getIndexNameExpressionResolver() { + return new IndexNameExpressionResolver() { + @Override + boolean iterateIndexAliases(int indexAliasesSize, int resolvedExpressionsSize) { + return false; + } + }; + } + +} diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java index 228d05c51c462..e53b7ae064679 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java @@ -46,6 +46,7 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Function; import static org.elasticsearch.common.util.set.Sets.newHashSet; @@ -60,7 +61,17 @@ import static org.hamcrest.Matchers.notNullValue; public class IndexNameExpressionResolverTests extends ESTestCase { - private final IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver(); + private IndexNameExpressionResolver indexNameExpressionResolver; + + protected IndexNameExpressionResolver getIndexNameExpressionResolver() { + return new IndexNameExpressionResolver(); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + indexNameExpressionResolver = getIndexNameExpressionResolver(); + } public void testIndexOptionsStrict() { MetaData.Builder mdBuilder = MetaData.builder() @@ -1020,20 +1031,39 @@ public void testFilterClosedIndicesOnAliases() { assertArrayEquals(new String[] {"test-0"}, strings); } + public void testResolveExpressions() { + MetaData.Builder mdBuilder = MetaData.builder() + .put(indexBuilder("test-0").state(State.OPEN).putAlias(AliasMetaData.builder("alias-0").filter("{ \"term\": \"foo\"}"))) + .put(indexBuilder("test-1").state(State.OPEN).putAlias(AliasMetaData.builder("alias-1"))); + ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); + + assertEquals(new HashSet<>(Arrays.asList("alias-0", "alias-1")), + indexNameExpressionResolver.resolveExpressions(state, "alias-*")); + assertEquals(new HashSet<>(Arrays.asList("test-0", "alias-0", "alias-1")), + indexNameExpressionResolver.resolveExpressions(state, "test-0", "alias-*")); + assertEquals(new HashSet<>(Arrays.asList("test-0", "test-1", "alias-0", "alias-1")), + indexNameExpressionResolver.resolveExpressions(state, "test-*", "alias-*")); + assertEquals(new HashSet<>(Arrays.asList("test-1", "alias-1")), + indexNameExpressionResolver.resolveExpressions(state, "*-1")); + } + public void testFilteringAliases() { MetaData.Builder mdBuilder = MetaData.builder() .put(indexBuilder("test-0").state(State.OPEN).putAlias(AliasMetaData.builder("alias-0").filter("{ \"term\": \"foo\"}"))) .put(indexBuilder("test-1").state(State.OPEN).putAlias(AliasMetaData.builder("alias-1"))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); - String[] strings = indexNameExpressionResolver.filteringAliases(state, "test-0", "alias-*"); + Set resolvedExpressions = new HashSet<>(Arrays.asList("alias-0", "alias-1")); + String[] strings = indexNameExpressionResolver.filteringAliases(state, "test-0", resolvedExpressions); assertArrayEquals(new String[] {"alias-0"}, strings); // concrete index supersedes filtering alias - strings = indexNameExpressionResolver.filteringAliases(state, "test-0", "test-0,alias-*"); + resolvedExpressions = new HashSet<>(Arrays.asList("test-0", "alias-0", "alias-1")); + strings = indexNameExpressionResolver.filteringAliases(state, "test-0", resolvedExpressions); assertNull(strings); - strings = indexNameExpressionResolver.filteringAliases(state, "test-0", "test-*,alias-*"); + resolvedExpressions = new HashSet<>(Arrays.asList("test-0", "test-1", "alias-0", "alias-1")); + strings = indexNameExpressionResolver.filteringAliases(state, "test-0", resolvedExpressions); assertNull(strings); } @@ -1045,9 +1075,36 @@ public void testIndexAliases() { .putAlias(AliasMetaData.builder("test-alias-non-filtering")) ); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); - String[] strings = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, true, "test-*"); + Set resolvedExpressions = indexNameExpressionResolver.resolveExpressions(state, "test-*"); + + String[] strings = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, true, resolvedExpressions); Arrays.sort(strings); assertArrayEquals(new String[] {"test-alias-0", "test-alias-1", "test-alias-non-filtering"}, strings); + + strings = indexNameExpressionResolver.indexAliases(state, "test-0", x -> x.alias().equals("test-alias-1"), true, + resolvedExpressions); + assertArrayEquals(null, strings); + } + + public void testIndexAliasesSkipIdentity() { + MetaData.Builder mdBuilder = MetaData.builder() + .put(indexBuilder("test-0").state(State.OPEN) + .putAlias(AliasMetaData.builder("test-alias")) + .putAlias(AliasMetaData.builder("other-alias")) + ); + ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); + + Set resolvedExpressions = new HashSet<>(Arrays.asList("test-0", "test-alias")); + String[] aliases = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, false, resolvedExpressions); + assertNull(aliases); + aliases = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, true, resolvedExpressions); + assertArrayEquals(new String[] {"test-alias"}, aliases); + + resolvedExpressions = Collections.singleton("other-alias"); + aliases = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, false, resolvedExpressions); + assertArrayEquals(new String[] {"other-alias"}, aliases); + aliases = indexNameExpressionResolver.indexAliases(state, "test-0", x -> true, true, resolvedExpressions); + assertArrayEquals(new String[] {"other-alias"}, aliases); } public void testConcreteWriteIndexSuccessful() { @@ -1057,7 +1114,7 @@ public void testConcreteWriteIndexSuccessful() { .putAlias(AliasMetaData.builder("test-alias").writeIndex(testZeroWriteIndex ? true : null))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); String[] strings = indexNameExpressionResolver - .indexAliases(state, "test-0", x -> true, true, "test-*"); + .indexAliases(state, "test-0", x -> true, true, new HashSet<>(Arrays.asList("test-0", "test-alias"))); Arrays.sort(strings); assertArrayEquals(new String[] {"test-alias"}, strings); IndicesRequest request = new IndicesRequest() { @@ -1118,7 +1175,7 @@ public void testConcreteWriteIndexWithWildcardExpansion() { .putAlias(AliasMetaData.builder("test-alias").writeIndex(testZeroWriteIndex ? randomFrom(false, null) : true))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); String[] strings = indexNameExpressionResolver - .indexAliases(state, "test-0", x -> true, true, "test-*"); + .indexAliases(state, "test-0", x -> true, true, new HashSet<>(Arrays.asList("test-0", "test-1", "test-alias"))); Arrays.sort(strings); assertArrayEquals(new String[] {"test-alias"}, strings); IndicesRequest request = new IndicesRequest() { @@ -1146,7 +1203,7 @@ public void testConcreteWriteIndexWithNoWriteIndexWithSingleIndex() { .putAlias(AliasMetaData.builder("test-alias").writeIndex(false))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); String[] strings = indexNameExpressionResolver - .indexAliases(state, "test-0", x -> true, true, "test-*"); + .indexAliases(state, "test-0", x -> true, true, new HashSet<>(Arrays.asList("test-0", "test-alias"))); Arrays.sort(strings); assertArrayEquals(new String[] {"test-alias"}, strings); DocWriteRequest request = randomFrom(new IndexRequest("test-alias"), @@ -1166,7 +1223,7 @@ public void testConcreteWriteIndexWithNoWriteIndexWithMultipleIndices() { .putAlias(AliasMetaData.builder("test-alias").writeIndex(randomFrom(false, null)))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); String[] strings = indexNameExpressionResolver - .indexAliases(state, "test-0", x -> true, true, "test-*"); + .indexAliases(state, "test-0", x -> true, true, new HashSet<>(Arrays.asList("test-0", "test-1", "test-alias"))); Arrays.sort(strings); assertArrayEquals(new String[] {"test-alias"}, strings); DocWriteRequest request = randomFrom(new IndexRequest("test-alias"), @@ -1187,7 +1244,7 @@ public void testAliasResolutionNotAllowingMultipleIndices() { .putAlias(AliasMetaData.builder("test-alias").writeIndex(randomFrom(!test0WriteIndex, null)))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); String[] strings = indexNameExpressionResolver - .indexAliases(state, "test-0", x -> true, true, "test-*"); + .indexAliases(state, "test-0", x -> true, true, new HashSet<>(Arrays.asList("test-0", "test-1", "test-alias"))); Arrays.sort(strings); assertArrayEquals(new String[] {"test-alias"}, strings); IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,