public void testMultipleAliasesPrecedence() throws Exception { client() .admin() .indices() .preparePutTemplate("template1") .setTemplate("*") .setOrder(0) .addAlias(new Alias("alias1")) .addAlias(new Alias("{index}-alias")) .addAlias( new Alias("alias3") .filter(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("test")))) .addAlias(new Alias("alias4")) .get(); client() .admin() .indices() .preparePutTemplate("template2") .setTemplate("te*") .setOrder(1) .addAlias(new Alias("alias1").routing("test")) .addAlias(new Alias("alias3")) .get(); assertAcked( prepareCreate("test").addAlias(new Alias("test-alias").searchRouting("test-routing"))); ensureGreen(); GetAliasesResponse getAliasesResponse = client().admin().indices().prepareGetAliases().addIndices("test").get(); assertThat(getAliasesResponse.getAliases().get("test").size(), equalTo(4)); for (AliasMetaData aliasMetaData : getAliasesResponse.getAliases().get("test")) { assertThat( aliasMetaData.alias(), anyOf(equalTo("alias1"), equalTo("test-alias"), equalTo("alias3"), equalTo("alias4"))); if ("alias1".equals(aliasMetaData.alias())) { assertThat(aliasMetaData.indexRouting(), equalTo("test")); assertThat(aliasMetaData.searchRouting(), equalTo("test")); } else if ("alias3".equals(aliasMetaData.alias())) { assertThat(aliasMetaData.filter(), nullValue()); } else if ("test-alias".equals(aliasMetaData.alias())) { assertThat(aliasMetaData.indexRouting(), nullValue()); assertThat(aliasMetaData.searchRouting(), equalTo("test-routing")); } } }
public IndexMetaData build() { MapBuilder<String, AliasMetaData> tmpAliases = aliases; Settings tmpSettings = settings; // For backward compatibility String[] legacyAliases = settings.getAsArray("index.aliases"); if (legacyAliases.length > 0) { tmpAliases = MapBuilder.newMapBuilder(); for (String alias : legacyAliases) { AliasMetaData aliasMd = AliasMetaData.newAliasMetaDataBuilder(alias).build(); tmpAliases.put(alias, aliasMd); } tmpAliases.putAll(aliases.immutableMap()); // Remove index.aliases from settings once they are migrated to the new data structure tmpSettings = ImmutableSettings.settingsBuilder().put(settings).putArray("index.aliases").build(); } // update default mapping on the MappingMetaData if (mappings.containsKey(MapperService.DEFAULT_MAPPING)) { MappingMetaData defaultMapping = mappings.get(MapperService.DEFAULT_MAPPING); for (MappingMetaData mappingMetaData : mappings.map().values()) { mappingMetaData.updateDefaultMapping(defaultMapping); } } return new IndexMetaData( index, version, state, tmpSettings, mappings.immutableMap(), tmpAliases.immutableMap(), customs.immutableMap()); }
private Query parse(AliasMetaData alias, QueryShardContext parseContext) { if (alias.filter() == null) { return null; } try { byte[] filterSource = alias.filter().uncompressed(); try (XContentParser parser = XContentFactory.xContent(filterSource).createParser(filterSource)) { ParsedQuery parsedFilter = parseContext.parseInnerFilter(parser); return parsedFilter == null ? null : parsedFilter.query(); } } catch (IOException ex) { throw new AliasFilterParsingException( parseContext.index(), alias.getAlias(), "Invalid alias filter", ex); } }
public static void toXContent( AliasMetaData aliasMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException { builder.startObject(aliasMetaData.alias(), XContentBuilder.FieldCaseConversion.NONE); boolean binary = params.paramAsBoolean("binary", false); if (aliasMetaData.filter() != null) { if (binary) { builder.field("filter", aliasMetaData.filter.compressed()); } else { byte[] data = aliasMetaData.filter().uncompressed(); XContentParser parser = XContentFactory.xContent(data).createParser(data); Map<String, Object> filter = parser.mapOrdered(); parser.close(); builder.field("filter", filter); } } if (aliasMetaData.indexRouting() != null) { builder.field("index_routing", aliasMetaData.indexRouting()); } if (aliasMetaData.searchRouting() != null) { builder.field("search_routing", aliasMetaData.searchRouting()); } builder.endObject(); }
// TODO: This can be moved to IndexNameExpressionResolver too, but this means that we will support // wildcards and other expressions // in the index,bulk,update and delete apis. public String resolveIndexRouting( @Nullable String parent, @Nullable String routing, String aliasOrIndex) { if (aliasOrIndex == null) { if (routing == null) { return parent; } return routing; } AliasOrIndex result = getAliasAndIndexLookup().get(aliasOrIndex); if (result == null || result.isAlias() == false) { if (routing == null) { return parent; } return routing; } AliasOrIndex.Alias alias = (AliasOrIndex.Alias) result; if (result.getIndices().size() > 1) { String[] indexNames = new String[result.getIndices().size()]; int i = 0; for (IndexMetaData indexMetaData : result.getIndices()) { indexNames[i++] = indexMetaData.getIndex().getName(); } throw new IllegalArgumentException( "Alias [" + aliasOrIndex + "] has more than one index associated with it [" + Arrays.toString(indexNames) + "], can't execute a single index op"); } AliasMetaData aliasMd = alias.getFirstAliasMetaData(); if (aliasMd.indexRouting() != null) { if (aliasMd.indexRouting().indexOf(',') != -1) { throw new IllegalArgumentException( "index/alias [" + aliasOrIndex + "] provided with routing value [" + aliasMd.getIndexRouting() + "] that resolved to several routing values, rejecting operation"); } if (routing != null) { if (!routing.equals(aliasMd.indexRouting())) { throw new IllegalArgumentException( "Alias [" + aliasOrIndex + "] has index routing associated with it [" + aliasMd.indexRouting() + "], and was provided with routing value [" + routing + "], rejecting operation"); } } // Alias routing overrides the parent routing (if any). return aliasMd.indexRouting(); } if (routing == null) { return parent; } return routing; }
@Test public void testIndicesAliasesAcknowledgement() { createIndex("test"); // testing acknowledgement when trying to submit an existing alias too // in that case it would not make any change, but we are sure about the cluster state // as the previous operation was acknowledged for (int i = 0; i < 2; i++) { assertAcked(client().admin().indices().prepareAliases().addAlias("test", "alias")); for (Client client : clients()) { AliasMetaData aliasMetaData = ((AliasOrIndex.Alias) getLocalClusterState(client).metaData().getAliasAndIndexLookup().get("alias")) .getFirstAliasMetaData(); assertThat(aliasMetaData.alias(), equalTo("alias")); } } }
private Query parse(AliasMetaData alias, QueryShardContext shardContext) { if (alias.filter() == null) { return null; } try { byte[] filterSource = alias.filter().uncompressed(); try (XContentParser parser = XContentFactory.xContent(filterSource).createParser(filterSource)) { Optional<QueryBuilder> innerQueryBuilder = shardContext.newParseContext(parser).parseInnerQueryBuilder(); if (innerQueryBuilder.isPresent()) { return shardContext.toFilter(innerQueryBuilder.get()).query(); } return null; } } catch (IOException ex) { throw new AliasFilterParsingException( shardContext.index(), alias.getAlias(), "Invalid alias filter", ex); } }
/** * Finds the specific index aliases that match with the specified aliases directly or partially * via wildcards and that point to the specified concrete indices or match partially with the * indices via wildcards. * * @param aliases The names of the index aliases to find * @param concreteIndices The concrete indexes the index aliases must point to order to be * returned. * @return the found index aliases grouped by index */ public ImmutableOpenMap<String, List<AliasMetaData>> findAliases( final String[] aliases, String[] concreteIndices) { assert aliases != null; assert concreteIndices != null; if (concreteIndices.length == 0) { return ImmutableOpenMap.of(); } boolean matchAllAliases = matchAllAliases(aliases); ImmutableOpenMap.Builder<String, List<AliasMetaData>> mapBuilder = ImmutableOpenMap.builder(); Iterable<String> intersection = HppcMaps.intersection(ObjectHashSet.from(concreteIndices), indices.keys()); for (String index : intersection) { IndexMetaData indexMetaData = indices.get(index); List<AliasMetaData> filteredValues = new ArrayList<>(); for (ObjectCursor<AliasMetaData> cursor : indexMetaData.getAliases().values()) { AliasMetaData value = cursor.value; if (matchAllAliases || Regex.simpleMatch(aliases, value.alias())) { filteredValues.add(value); } } if (!filteredValues.isEmpty()) { // Make the list order deterministic CollectionUtil.timSort( filteredValues, new Comparator<AliasMetaData>() { @Override public int compare(AliasMetaData o1, AliasMetaData o2) { return o1.alias().compareTo(o2.alias()); } }); mapBuilder.put(index, Collections.unmodifiableList(filteredValues)); } } return mapBuilder.build(); }
/** * Checks if at least one of the specified aliases exists in the specified concrete indices. * Wildcards are supported in the alias names for partial matches. * * @param aliases The names of the index aliases to find * @param concreteIndices The concrete indexes the index aliases must point to order to be * returned. * @return whether at least one of the specified aliases exists in one of the specified concrete * indices. */ public boolean hasAliases(final String[] aliases, String[] concreteIndices) { assert aliases != null; assert concreteIndices != null; if (concreteIndices.length == 0) { return false; } Iterable<String> intersection = HppcMaps.intersection(ObjectHashSet.from(concreteIndices), indices.keys()); for (String index : intersection) { IndexMetaData indexMetaData = indices.get(index); List<AliasMetaData> filteredValues = new ArrayList<>(); for (ObjectCursor<AliasMetaData> cursor : indexMetaData.getAliases().values()) { AliasMetaData value = cursor.value; if (Regex.simpleMatch(aliases, value.alias())) { filteredValues.add(value); } } if (!filteredValues.isEmpty()) { return true; } } return false; }
public static void writeTo(AliasMetaData aliasMetaData, StreamOutput out) throws IOException { out.writeString(aliasMetaData.alias()); if (aliasMetaData.filter() != null) { out.writeBoolean(true); aliasMetaData.filter.writeTo(out); } else { out.writeBoolean(false); } if (aliasMetaData.indexRouting() != null) { out.writeBoolean(true); out.writeString(aliasMetaData.indexRouting()); } else { out.writeBoolean(false); } if (aliasMetaData.searchRouting() != null) { out.writeBoolean(true); out.writeString(aliasMetaData.searchRouting()); } else { out.writeBoolean(false); } }
public Builder putAlias(AliasMetaData aliasMetaData) { aliases.put(aliasMetaData.alias(), aliasMetaData); return this; }
private AliasMetaData(AliasMetaData aliasMetaData, String alias) { this( alias, aliasMetaData.filter(), aliasMetaData.indexRouting(), aliasMetaData.searchRouting()); }
public Builder(AliasMetaData aliasMetaData) { this(aliasMetaData.alias()); filter = aliasMetaData.filter(); indexRouting = aliasMetaData.indexRouting(); searchRouting = aliasMetaData.searchRouting(); }
public MetaData build() { // TODO: We should move these datastructures to IndexNameExpressionResolver, this will give // the following benefits: // 1) The datastructures will only be rebuilded when needed. Now during serializing we rebuild // these datastructures // while these datastructures aren't even used. // 2) The aliasAndIndexLookup can be updated instead of rebuilding it all the time. // build all concrete indices arrays: // TODO: I think we can remove these arrays. it isn't worth the effort, for operations on all // indices. // When doing an operation across all indices, most of the time is spent on actually going to // all shards and // do the required operations, the bottleneck isn't resolving expressions into concrete // indices. List<String> allIndicesLst = new ArrayList<>(); for (ObjectCursor<IndexMetaData> cursor : indices.values()) { allIndicesLst.add(cursor.value.getIndex().getName()); } String[] allIndices = allIndicesLst.toArray(new String[allIndicesLst.size()]); List<String> allOpenIndicesLst = new ArrayList<>(); List<String> allClosedIndicesLst = new ArrayList<>(); for (ObjectCursor<IndexMetaData> cursor : indices.values()) { IndexMetaData indexMetaData = cursor.value; if (indexMetaData.getState() == IndexMetaData.State.OPEN) { allOpenIndicesLst.add(indexMetaData.getIndex().getName()); } else if (indexMetaData.getState() == IndexMetaData.State.CLOSE) { allClosedIndicesLst.add(indexMetaData.getIndex().getName()); } } String[] allOpenIndices = allOpenIndicesLst.toArray(new String[allOpenIndicesLst.size()]); String[] allClosedIndices = allClosedIndicesLst.toArray(new String[allClosedIndicesLst.size()]); // build all indices map SortedMap<String, AliasOrIndex> aliasAndIndexLookup = new TreeMap<>(); for (ObjectCursor<IndexMetaData> cursor : indices.values()) { IndexMetaData indexMetaData = cursor.value; aliasAndIndexLookup.put( indexMetaData.getIndex().getName(), new AliasOrIndex.Index(indexMetaData)); for (ObjectObjectCursor<String, AliasMetaData> aliasCursor : indexMetaData.getAliases()) { AliasMetaData aliasMetaData = aliasCursor.value; AliasOrIndex aliasOrIndex = aliasAndIndexLookup.get(aliasMetaData.getAlias()); if (aliasOrIndex == null) { aliasOrIndex = new AliasOrIndex.Alias(aliasMetaData, indexMetaData); aliasAndIndexLookup.put(aliasMetaData.getAlias(), aliasOrIndex); } else if (aliasOrIndex instanceof AliasOrIndex.Alias) { AliasOrIndex.Alias alias = (AliasOrIndex.Alias) aliasOrIndex; alias.addIndex(indexMetaData); } else if (aliasOrIndex instanceof AliasOrIndex.Index) { AliasOrIndex.Index index = (AliasOrIndex.Index) aliasOrIndex; throw new IllegalStateException( "index and alias names need to be unique, but alias [" + aliasMetaData.getAlias() + "] and index " + index.getIndex().getIndex() + " have the same name"); } else { throw new IllegalStateException( "unexpected alias [" + aliasMetaData.getAlias() + "][" + aliasOrIndex + "]"); } } } aliasAndIndexLookup = Collections.unmodifiableSortedMap(aliasAndIndexLookup); return new MetaData( clusterUUID, version, transientSettings, persistentSettings, indices.build(), templates.build(), customs.build(), allIndices, allOpenIndices, allClosedIndices, aliasAndIndexLookup); }