Added support for aliases to index templates
Adapted existing PR (#2739) to updated code (post #4920), added tests and docs (@javanna) Closes #1825
This commit is contained in:
parent
56fa5458e6
commit
a93d6d55a5
|
@ -27,6 +27,35 @@ Defines a template named template_1, with a template pattern of `te*`.
|
|||
The settings and mappings will be applied to any index name that matches
|
||||
the `te*` template.
|
||||
|
||||
coming[1.1.0]
|
||||
|
||||
It is also possible to include aliases in an index template as follows:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
curl -XPUT localhost:9200/_template/template_1 -d '
|
||||
{
|
||||
"template" : "te*",
|
||||
"settings" : {
|
||||
"number_of_shards" : 1
|
||||
},
|
||||
"aliases" : {
|
||||
"alias1" : {},
|
||||
"alias2" : {
|
||||
"filter" : {
|
||||
"term" : {"user" : "kimchy" }
|
||||
},
|
||||
"routing" : "kimchy"
|
||||
},
|
||||
"{index}-alias" : {} <1>
|
||||
}
|
||||
}
|
||||
'
|
||||
--------------------------------------------------
|
||||
|
||||
<1> the `{index}` placeholder within the alias name will be replaced with the
|
||||
actual index name that the template gets applied to during index creation.
|
||||
|
||||
[float]
|
||||
[[delete]]
|
||||
=== Deleting a Template
|
||||
|
|
|
@ -15,3 +15,27 @@
|
|||
|
||||
- match: {test.template: "test-*"}
|
||||
- match: {test.settings: {index.number_of_shards: '1', index.number_of_replicas: '0'}}
|
||||
|
||||
---
|
||||
"Put template with aliases":
|
||||
- do:
|
||||
indices.put_template:
|
||||
name: test
|
||||
body:
|
||||
template: test-*
|
||||
aliases:
|
||||
test_alias: {}
|
||||
test_blias: {routing: b}
|
||||
test_clias: {filter: {term :{user : kimchy}}}
|
||||
|
||||
- do:
|
||||
indices.get_template:
|
||||
name: test
|
||||
|
||||
- match: {test.template: "test-*"}
|
||||
- length: {test.aliases: 3}
|
||||
- is_true: test.aliases.test_alias
|
||||
- match: {test.aliases.test_blias.index_routing: "b"}
|
||||
- match: {test.aliases.test_blias.search_routing: "b"}
|
||||
- match: {test.aliases.test_clias.filter.term.user: "kimchy"}
|
||||
|
||||
|
|
|
@ -21,24 +21,27 @@ package org.elasticsearch.action.admin.indices.template.put;
|
|||
import org.elasticsearch.ElasticsearchGenerationException;
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequest;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.common.xcontent.*;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.collect.Maps.newHashMap;
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.Builder.EMPTY_SETTINGS;
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.readSettingsFromStream;
|
||||
|
@ -63,6 +66,8 @@ public class PutIndexTemplateRequest extends MasterNodeOperationRequest<PutIndex
|
|||
|
||||
private Map<String, String> mappings = newHashMap();
|
||||
|
||||
private final Set<Alias> aliases = newHashSet();
|
||||
|
||||
private Map<String, IndexMetaData.Custom> customs = newHashMap();
|
||||
|
||||
PutIndexTemplateRequest() {
|
||||
|
@ -251,6 +256,7 @@ public class PutIndexTemplateRequest extends MasterNodeOperationRequest<PutIndex
|
|||
/**
|
||||
* The template source definition.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PutIndexTemplateRequest source(Map templateSource) {
|
||||
Map<String, Object> source = templateSource;
|
||||
for (Map.Entry<String, Object> entry : source.entrySet()) {
|
||||
|
@ -272,6 +278,8 @@ public class PutIndexTemplateRequest extends MasterNodeOperationRequest<PutIndex
|
|||
}
|
||||
mapping(entry1.getKey(), (Map<String, Object>) entry1.getValue());
|
||||
}
|
||||
} else if (name.equals("aliases")) {
|
||||
aliases((Map<String, Object>) entry.getValue());
|
||||
} else {
|
||||
// maybe custom?
|
||||
IndexMetaData.Custom.Factory factory = IndexMetaData.lookupFactory(name);
|
||||
|
@ -336,6 +344,66 @@ public class PutIndexTemplateRequest extends MasterNodeOperationRequest<PutIndex
|
|||
return this.customs;
|
||||
}
|
||||
|
||||
Set<Alias> aliases() {
|
||||
return this.aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public PutIndexTemplateRequest aliases(Map source) {
|
||||
try {
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||
builder.map(source);
|
||||
return aliases(builder.bytes());
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequest aliases(XContentBuilder source) {
|
||||
return aliases(source.bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequest aliases(String source) {
|
||||
return aliases(new BytesArray(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequest aliases(BytesReference source) {
|
||||
try {
|
||||
XContentParser parser = XContentHelper.createParser(source);
|
||||
//move to the first alias
|
||||
parser.nextToken();
|
||||
while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
alias(Alias.fromXContent(parser));
|
||||
}
|
||||
return this;
|
||||
} catch(IOException e) {
|
||||
throw new ElasticsearchParseException("Failed to parse aliases", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an alias that will be added when the index gets created.
|
||||
*
|
||||
* @param alias The metadata for the new alias
|
||||
* @return the index template creation request
|
||||
*/
|
||||
public PutIndexTemplateRequest alias(Alias alias) {
|
||||
aliases.add(alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
|
@ -355,6 +423,12 @@ public class PutIndexTemplateRequest extends MasterNodeOperationRequest<PutIndex
|
|||
IndexMetaData.Custom customIndexMetaData = IndexMetaData.lookupFactorySafe(type).readFrom(in);
|
||||
customs.put(type, customIndexMetaData);
|
||||
}
|
||||
if (in.getVersion().onOrAfter(Version.V_1_1_0)) {
|
||||
int aliasesSize = in.readVInt();
|
||||
for (int i = 0; i < aliasesSize; i++) {
|
||||
aliases.add(Alias.read(in));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -376,5 +450,11 @@ public class PutIndexTemplateRequest extends MasterNodeOperationRequest<PutIndex
|
|||
out.writeString(entry.getKey());
|
||||
IndexMetaData.lookupFactorySafe(entry.getKey()).writeTo(entry.getValue(), out);
|
||||
}
|
||||
if (out.getVersion().onOrAfter(Version.V_1_1_0)) {
|
||||
out.writeVInt(aliases.size());
|
||||
for (Alias alias : aliases) {
|
||||
alias.writeTo(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.elasticsearch.action.admin.indices.template.put;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||
import org.elasticsearch.client.IndicesAdminClient;
|
||||
import org.elasticsearch.client.internal.InternalIndicesAdminClient;
|
||||
|
@ -109,6 +110,49 @@ public class PutIndexTemplateRequestBuilder extends MasterNodeOperationRequestBu
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequestBuilder setAliases(Map source) {
|
||||
request.aliases(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequestBuilder setAliases(String source) {
|
||||
request.aliases(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequestBuilder setAliases(XContentBuilder source) {
|
||||
request.aliases(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the aliases that will be associated with the index when it gets created
|
||||
*/
|
||||
public PutIndexTemplateRequestBuilder setAliases(BytesReference source) {
|
||||
request.aliases(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an alias that will be added when the index template gets created.
|
||||
*
|
||||
* @param alias The alias
|
||||
* @return the request builder
|
||||
*/
|
||||
public PutIndexTemplateRequestBuilder addAlias(Alias alias) {
|
||||
request.alias(alias);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cause for this index template creation.
|
||||
*/
|
||||
|
|
|
@ -83,6 +83,7 @@ public class TransportPutIndexTemplateAction extends TransportMasterNodeOperatio
|
|||
.order(request.order())
|
||||
.settings(request.settings())
|
||||
.mappings(request.mappings())
|
||||
.aliases(request.aliases())
|
||||
.customs(request.customs())
|
||||
.create(request.create())
|
||||
.masterTimeout(request.masterNodeTimeout()),
|
||||
|
|
|
@ -62,6 +62,10 @@ public class AliasMetaData {
|
|||
}
|
||||
}
|
||||
|
||||
private AliasMetaData(AliasMetaData aliasMetaData, String alias) {
|
||||
this(alias, aliasMetaData.filter(), aliasMetaData.indexRouting(), aliasMetaData.searchRouting());
|
||||
}
|
||||
|
||||
public String alias() {
|
||||
return alias;
|
||||
}
|
||||
|
@ -110,6 +114,13 @@ public class AliasMetaData {
|
|||
return new Builder(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AliasMetaData instance with same content as the given one, but with a different alias name
|
||||
*/
|
||||
public static AliasMetaData newAliasMetaData(AliasMetaData aliasMetaData, String newAlias) {
|
||||
return new AliasMetaData(aliasMetaData, newAlias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -137,7 +148,7 @@ public class AliasMetaData {
|
|||
|
||||
public static class Builder {
|
||||
|
||||
private String alias;
|
||||
private final String alias;
|
||||
|
||||
private CompressedString filter;
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.elasticsearch.index.Index;
|
|||
import org.elasticsearch.index.query.IndexQueryParserService;
|
||||
import org.elasticsearch.indices.InvalidAliasNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Validator for an alias, to be used before adding an alias to the index metadata
|
||||
* and make sure the alias is valid
|
||||
|
@ -44,7 +46,8 @@ public class AliasValidator extends AbstractComponent {
|
|||
|
||||
/**
|
||||
* Allows to validate an {@link org.elasticsearch.cluster.metadata.AliasAction} and make sure
|
||||
* it's valid before it gets added to the index metadata
|
||||
* it's valid before it gets added to the index metadata. Doesn't validate the alias filter.
|
||||
* @throws org.elasticsearch.ElasticsearchIllegalArgumentException if the alias is not valid
|
||||
*/
|
||||
public void validateAliasAction(AliasAction aliasAction, MetaData metaData) {
|
||||
validateAlias(aliasAction.alias(), aliasAction.index(), aliasAction.indexRouting(), metaData);
|
||||
|
@ -52,22 +55,58 @@ public class AliasValidator extends AbstractComponent {
|
|||
|
||||
/**
|
||||
* Allows to validate an {@link org.elasticsearch.action.admin.indices.alias.Alias} and make sure
|
||||
* it's valid before it gets added to the index metadata
|
||||
* it's valid before it gets added to the index metadata. Doesn't validate the alias filter.
|
||||
* @throws org.elasticsearch.ElasticsearchIllegalArgumentException if the alias is not valid
|
||||
*/
|
||||
public void validateAlias(Alias alias, String index, MetaData metaData) {
|
||||
validateAlias(alias.name(), index, alias.indexRouting(), metaData);
|
||||
}
|
||||
|
||||
private void validateAlias(String alias, String index, String indexRouting, MetaData metaData) {
|
||||
assert metaData != null;
|
||||
if (!Strings.hasText(alias) || !Strings.hasText(index)) {
|
||||
throw new ElasticsearchIllegalArgumentException("index name and alias name are required");
|
||||
/**
|
||||
* Allows to validate an {@link org.elasticsearch.cluster.metadata.AliasMetaData} and make sure
|
||||
* it's valid before it gets added to the index metadata. Doesn't validate the alias filter.
|
||||
* @throws org.elasticsearch.ElasticsearchIllegalArgumentException if the alias is not valid
|
||||
*/
|
||||
public void validateAliasMetaData(AliasMetaData aliasMetaData, String index, MetaData metaData) {
|
||||
validateAlias(aliasMetaData.alias(), index, aliasMetaData.indexRouting(), metaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to partially validate an alias, without knowing which index it'll get applied to.
|
||||
* Useful with index templates containing aliases. Checks also that it is possible to parse
|
||||
* the alias filter via {@link org.elasticsearch.common.xcontent.XContentParser},
|
||||
* without validating it as a filter though.
|
||||
* @throws org.elasticsearch.ElasticsearchIllegalArgumentException if the alias is not valid
|
||||
*/
|
||||
public void validateAliasStandalone(Alias alias) {
|
||||
validateAliasStandalone(alias.name(), alias.indexRouting());
|
||||
if (Strings.hasLength(alias.filter())) {
|
||||
try {
|
||||
XContentParser parser = XContentFactory.xContent(alias.filter()).createParser(alias.filter());
|
||||
parser.mapAndClose();
|
||||
} catch (Throwable e) {
|
||||
throw new ElasticsearchIllegalArgumentException("failed to parse filter for alias [" + alias.name() + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAlias(String alias, String index, String indexRouting, MetaData metaData) {
|
||||
validateAliasStandalone(alias, indexRouting);
|
||||
|
||||
if (!Strings.hasText(index)) {
|
||||
throw new ElasticsearchIllegalArgumentException("index name is required");
|
||||
}
|
||||
|
||||
assert metaData != null;
|
||||
if (metaData.hasIndex(alias)) {
|
||||
throw new InvalidAliasNameException(new Index(index), alias, "an index exists with the same name as the alias");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAliasStandalone(String alias, String indexRouting) {
|
||||
if (!Strings.hasText(alias)) {
|
||||
throw new ElasticsearchIllegalArgumentException("alias name is required");
|
||||
}
|
||||
if (indexRouting != null && indexRouting.indexOf(',') != -1) {
|
||||
throw new ElasticsearchIllegalArgumentException("alias [" + alias + "] has several index routing values associated with it");
|
||||
}
|
||||
|
@ -82,13 +121,32 @@ public class AliasValidator extends AbstractComponent {
|
|||
assert indexQueryParserService != null;
|
||||
try {
|
||||
XContentParser parser = XContentFactory.xContent(filter).createParser(filter);
|
||||
validateAliasFilter(parser, indexQueryParserService);
|
||||
} catch (Throwable e) {
|
||||
throw new ElasticsearchIllegalArgumentException("failed to parse filter for alias [" + alias + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an alias filter by parsing it using the
|
||||
* provided {@link org.elasticsearch.index.query.IndexQueryParserService}
|
||||
* @throws org.elasticsearch.ElasticsearchIllegalArgumentException if the filter is not valid
|
||||
*/
|
||||
public void validateAliasFilter(String alias, byte[] filter, IndexQueryParserService indexQueryParserService) {
|
||||
assert indexQueryParserService != null;
|
||||
try {
|
||||
XContentParser parser = XContentFactory.xContent(filter).createParser(filter);
|
||||
validateAliasFilter(parser, indexQueryParserService);
|
||||
} catch (Throwable e) {
|
||||
throw new ElasticsearchIllegalArgumentException("failed to parse filter for alias [" + alias + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateAliasFilter(XContentParser parser, IndexQueryParserService indexQueryParserService) throws IOException {
|
||||
try {
|
||||
indexQueryParserService.parseInnerFilter(parser);
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new ElasticsearchIllegalArgumentException("failed to parse filter for alias [" + alias + "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
*/
|
||||
package org.elasticsearch.cluster.metadata;
|
||||
|
||||
import com.carrotsearch.hppc.cursors.ObjectCursor;
|
||||
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.common.compress.CompressedString;
|
||||
|
@ -53,14 +55,18 @@ public class IndexTemplateMetaData {
|
|||
// the mapping source should always include the type as top level
|
||||
private final ImmutableOpenMap<String, CompressedString> mappings;
|
||||
|
||||
private final ImmutableOpenMap<String, AliasMetaData> aliases;
|
||||
|
||||
private final ImmutableOpenMap<String, IndexMetaData.Custom> customs;
|
||||
|
||||
public IndexTemplateMetaData(String name, int order, String template, Settings settings, ImmutableOpenMap<String, CompressedString> mappings, ImmutableOpenMap<String, IndexMetaData.Custom> customs) {
|
||||
public IndexTemplateMetaData(String name, int order, String template, Settings settings, ImmutableOpenMap<String, CompressedString> mappings,
|
||||
ImmutableOpenMap<String, AliasMetaData> aliases, ImmutableOpenMap<String, IndexMetaData.Custom> customs) {
|
||||
this.name = name;
|
||||
this.order = order;
|
||||
this.template = template;
|
||||
this.settings = settings;
|
||||
this.mappings = mappings;
|
||||
this.aliases = aliases;
|
||||
this.customs = customs;
|
||||
}
|
||||
|
||||
|
@ -104,6 +110,14 @@ public class IndexTemplateMetaData {
|
|||
return this.mappings;
|
||||
}
|
||||
|
||||
public ImmutableOpenMap<String, AliasMetaData> aliases() {
|
||||
return this.aliases;
|
||||
}
|
||||
|
||||
public ImmutableOpenMap<String, AliasMetaData> getAliases() {
|
||||
return this.aliases;
|
||||
}
|
||||
|
||||
public ImmutableOpenMap<String, IndexMetaData.Custom> customs() {
|
||||
return this.customs;
|
||||
}
|
||||
|
@ -112,6 +126,7 @@ public class IndexTemplateMetaData {
|
|||
return this.customs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends IndexMetaData.Custom> T custom(String type) {
|
||||
return (T) customs.get(type);
|
||||
}
|
||||
|
@ -163,11 +178,14 @@ public class IndexTemplateMetaData {
|
|||
|
||||
private final ImmutableOpenMap.Builder<String, CompressedString> mappings;
|
||||
|
||||
private final ImmutableOpenMap.Builder<String, AliasMetaData> aliases;
|
||||
|
||||
private final ImmutableOpenMap.Builder<String, IndexMetaData.Custom> customs;
|
||||
|
||||
public Builder(String name) {
|
||||
this.name = name;
|
||||
mappings = ImmutableOpenMap.builder();
|
||||
aliases = ImmutableOpenMap.builder();
|
||||
customs = ImmutableOpenMap.builder();
|
||||
}
|
||||
|
||||
|
@ -178,6 +196,7 @@ public class IndexTemplateMetaData {
|
|||
settings(indexTemplateMetaData.settings());
|
||||
|
||||
mappings = ImmutableOpenMap.builder(indexTemplateMetaData.mappings());
|
||||
aliases = ImmutableOpenMap.builder(indexTemplateMetaData.aliases());
|
||||
customs = ImmutableOpenMap.builder(indexTemplateMetaData.customs());
|
||||
}
|
||||
|
||||
|
@ -220,6 +239,16 @@ public class IndexTemplateMetaData {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder putAlias(AliasMetaData aliasMetaData) {
|
||||
aliases.put(aliasMetaData.alias(), aliasMetaData);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder putAlias(AliasMetaData.Builder aliasMetaData) {
|
||||
aliases.put(aliasMetaData.alias(), aliasMetaData.build());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder putCustom(String type, IndexMetaData.Custom customIndexMetaData) {
|
||||
this.customs.put(type, customIndexMetaData);
|
||||
return this;
|
||||
|
@ -235,9 +264,10 @@ public class IndexTemplateMetaData {
|
|||
}
|
||||
|
||||
public IndexTemplateMetaData build() {
|
||||
return new IndexTemplateMetaData(name, order, template, settings, mappings.build(), customs.build());
|
||||
return new IndexTemplateMetaData(name, order, template, settings, mappings.build(), aliases.build(), customs.build());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void toXContent(IndexTemplateMetaData indexTemplateMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||
builder.startObject(indexTemplateMetaData.name(), XContentBuilder.FieldCaseConversion.NONE);
|
||||
|
||||
|
@ -281,6 +311,12 @@ public class IndexTemplateMetaData {
|
|||
builder.endObject();
|
||||
}
|
||||
|
||||
builder.startObject("aliases");
|
||||
for (ObjectCursor<AliasMetaData> cursor : indexTemplateMetaData.aliases().values()) {
|
||||
AliasMetaData.Builder.toXContent(cursor.value, builder, params);
|
||||
}
|
||||
builder.endObject();
|
||||
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
|
@ -313,6 +349,10 @@ public class IndexTemplateMetaData {
|
|||
builder.putMapping(mappingType, XContentFactory.jsonBuilder().map(mappingSource).string());
|
||||
}
|
||||
}
|
||||
} else if ("aliases".equals(currentFieldName)) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
builder.putAlias(AliasMetaData.Builder.fromXContent(parser));
|
||||
}
|
||||
} else {
|
||||
// check if its a custom index metadata
|
||||
IndexMetaData.Custom.Factory<IndexMetaData.Custom> factory = IndexMetaData.lookupFactory(currentFieldName);
|
||||
|
@ -377,6 +417,13 @@ public class IndexTemplateMetaData {
|
|||
for (int i = 0; i < mappingsSize; i++) {
|
||||
builder.putMapping(in.readString(), CompressedString.readCompressedString(in));
|
||||
}
|
||||
if (in.getVersion().onOrAfter(Version.V_1_1_0)) {
|
||||
int aliasesSize = in.readVInt();
|
||||
for (int i = 0; i < aliasesSize; i++) {
|
||||
AliasMetaData aliasMd = AliasMetaData.Builder.readFrom(in);
|
||||
builder.putAlias(aliasMd);
|
||||
}
|
||||
}
|
||||
int customSize = in.readVInt();
|
||||
for (int i = 0; i < customSize; i++) {
|
||||
String type = in.readString();
|
||||
|
@ -396,6 +443,12 @@ public class IndexTemplateMetaData {
|
|||
out.writeString(cursor.key);
|
||||
cursor.value.writeTo(out);
|
||||
}
|
||||
if (out.getVersion().onOrAfter(Version.V_1_1_0)) {
|
||||
out.writeVInt(indexTemplateMetaData.aliases().size());
|
||||
for (ObjectCursor<AliasMetaData> cursor : indexTemplateMetaData.aliases().values()) {
|
||||
AliasMetaData.Builder.writeTo(cursor.value, out);
|
||||
}
|
||||
}
|
||||
out.writeVInt(indexTemplateMetaData.customs().size());
|
||||
for (ObjectObjectCursor<String, IndexMetaData.Custom> cursor : indexTemplateMetaData.customs()) {
|
||||
out.writeString(cursor.key);
|
||||
|
|
|
@ -232,6 +232,8 @@ public class MetaDataCreateIndexService extends AbstractComponent {
|
|||
// add the request mapping
|
||||
Map<String, Map<String, Object>> mappings = Maps.newHashMap();
|
||||
|
||||
Map<String, AliasMetaData> templatesAliases = Maps.newHashMap();
|
||||
|
||||
for (Map.Entry<String, String> entry : request.mappings().entrySet()) {
|
||||
mappings.put(entry.getKey(), parseMapping(entry.getValue()));
|
||||
}
|
||||
|
@ -261,6 +263,28 @@ public class MetaDataCreateIndexService extends AbstractComponent {
|
|||
customs.put(type, merged);
|
||||
}
|
||||
}
|
||||
//handle aliases
|
||||
for (ObjectObjectCursor<String, AliasMetaData> cursor : template.aliases()) {
|
||||
AliasMetaData aliasMetaData = cursor.value;
|
||||
//if an alias with same name came with the create index request itself,
|
||||
// ignore this one taken from the index template
|
||||
if (request.aliases().contains(new Alias(aliasMetaData.alias()))) {
|
||||
continue;
|
||||
}
|
||||
//if an alias with same name was already processed, ignore this one
|
||||
if (templatesAliases.containsKey(cursor.key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Allow templatesAliases to be templated by replacing a token with the name of the index that we are applying it to
|
||||
if (aliasMetaData.alias().contains("{index}")) {
|
||||
String templatedAlias = aliasMetaData.alias().replace("{index}", request.index());
|
||||
aliasMetaData = AliasMetaData.newAliasMetaData(aliasMetaData, templatedAlias);
|
||||
}
|
||||
|
||||
aliasValidator.validateAliasMetaData(aliasMetaData, request.index(), currentState.metaData());
|
||||
templatesAliases.put(aliasMetaData.alias(), aliasMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
// now add config level mappings
|
||||
|
@ -349,6 +373,11 @@ public class MetaDataCreateIndexService extends AbstractComponent {
|
|||
aliasValidator.validateAliasFilter(alias.name(), alias.filter(), indexQueryParserService);
|
||||
}
|
||||
}
|
||||
for (AliasMetaData aliasMetaData : templatesAliases.values()) {
|
||||
if (aliasMetaData.filter() != null) {
|
||||
aliasValidator.validateAliasFilter(aliasMetaData.alias(), aliasMetaData.filter().uncompressed(), indexQueryParserService);
|
||||
}
|
||||
}
|
||||
|
||||
// now, update the mappings with the actual source
|
||||
Map<String, MappingMetaData> mappingsMetaData = Maps.newHashMap();
|
||||
|
@ -361,15 +390,22 @@ public class MetaDataCreateIndexService extends AbstractComponent {
|
|||
for (MappingMetaData mappingMd : mappingsMetaData.values()) {
|
||||
indexMetaDataBuilder.putMapping(mappingMd);
|
||||
}
|
||||
|
||||
for (AliasMetaData aliasMetaData : templatesAliases.values()) {
|
||||
indexMetaDataBuilder.putAlias(aliasMetaData);
|
||||
}
|
||||
for (Alias alias : request.aliases()) {
|
||||
AliasMetaData aliasMetaData = AliasMetaData.builder(alias.name()).filter(alias.filter())
|
||||
.indexRouting(alias.indexRouting()).searchRouting(alias.searchRouting()).build();
|
||||
indexMetaDataBuilder.putAlias(aliasMetaData);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Custom> customEntry : customs.entrySet()) {
|
||||
indexMetaDataBuilder.putCustom(customEntry.getKey(), customEntry.getValue());
|
||||
}
|
||||
|
||||
indexMetaDataBuilder.state(request.state());
|
||||
|
||||
final IndexMetaData indexMetaData;
|
||||
try {
|
||||
indexMetaData = indexMetaDataBuilder.build();
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
package org.elasticsearch.cluster.metadata;
|
||||
|
||||
import com.carrotsearch.hppc.cursors.ObjectCursor;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequest;
|
||||
import org.elasticsearch.cluster.ClusterService;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
|
@ -39,21 +41,24 @@ import org.elasticsearch.indices.IndexTemplateAlreadyExistsException;
|
|||
import org.elasticsearch.indices.IndexTemplateMissingException;
|
||||
import org.elasticsearch.indices.InvalidIndexTemplateException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* Service responsible for submitting index templates updates
|
||||
*/
|
||||
public class MetaDataIndexTemplateService extends AbstractComponent {
|
||||
|
||||
private final ClusterService clusterService;
|
||||
private final AliasValidator aliasValidator;
|
||||
|
||||
@Inject
|
||||
public MetaDataIndexTemplateService(Settings settings, ClusterService clusterService) {
|
||||
public MetaDataIndexTemplateService(Settings settings, ClusterService clusterService, AliasValidator aliasValidator) {
|
||||
super(settings);
|
||||
this.clusterService = clusterService;
|
||||
this.aliasValidator = aliasValidator;
|
||||
}
|
||||
|
||||
public void removeTemplates(final RemoveRequest request, final RemoveListener listener) {
|
||||
|
@ -136,6 +141,11 @@ public class MetaDataIndexTemplateService extends AbstractComponent {
|
|||
for (Map.Entry<String, String> entry : request.mappings.entrySet()) {
|
||||
templateBuilder.putMapping(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Alias alias : request.aliases) {
|
||||
AliasMetaData aliasMetaData = AliasMetaData.builder(alias.name()).filter(alias.filter())
|
||||
.indexRouting(alias.indexRouting()).searchRouting(alias.searchRouting()).build();
|
||||
templateBuilder.putAlias(aliasMetaData);
|
||||
}
|
||||
for (Map.Entry<String, IndexMetaData.Custom> entry : request.customs.entrySet()) {
|
||||
templateBuilder.putCustom(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
@ -205,6 +215,11 @@ public class MetaDataIndexTemplateService extends AbstractComponent {
|
|||
if (!Strings.validFileNameExcludingAstrix(request.template)) {
|
||||
throw new InvalidIndexTemplateException(request.name, "template must not container the following characters " + Strings.INVALID_FILENAME_CHARS);
|
||||
}
|
||||
|
||||
for (Alias alias : request.aliases) {
|
||||
//we validate the alias only partially, as we don't know yet to which index it'll get applied to
|
||||
aliasValidator.validateAliasStandalone(alias);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface PutListener {
|
||||
|
@ -222,6 +237,7 @@ public class MetaDataIndexTemplateService extends AbstractComponent {
|
|||
String template;
|
||||
Settings settings = ImmutableSettings.Builder.EMPTY_SETTINGS;
|
||||
Map<String, String> mappings = Maps.newHashMap();
|
||||
List<Alias> aliases = Lists.newArrayList();
|
||||
Map<String, IndexMetaData.Custom> customs = Maps.newHashMap();
|
||||
|
||||
TimeValue masterTimeout = MasterNodeOperationRequest.DEFAULT_MASTER_NODE_TIMEOUT;
|
||||
|
@ -256,6 +272,11 @@ public class MetaDataIndexTemplateService extends AbstractComponent {
|
|||
return this;
|
||||
}
|
||||
|
||||
public PutRequest aliases(Set<Alias> aliases) {
|
||||
this.aliases.addAll(aliases);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PutRequest customs(Map<String, IndexMetaData.Custom> customs) {
|
||||
this.customs.putAll(customs);
|
||||
return this;
|
||||
|
|
|
@ -92,9 +92,13 @@ public class ToAndFromJsonMetaDataTests extends ElasticsearchTestCase {
|
|||
.putAlias(newAliasMetaDataBuilder("alias4").filter(ALIAS_FILTER2)))
|
||||
.put(IndexTemplateMetaData.builder("foo")
|
||||
.template("bar")
|
||||
.order(1).settings(settingsBuilder()
|
||||
.order(1)
|
||||
.settings(settingsBuilder()
|
||||
.put("setting1", "value1")
|
||||
.put("setting2", "value2")))
|
||||
.put("setting2", "value2"))
|
||||
.putAlias(newAliasMetaDataBuilder("alias-bar1"))
|
||||
.putAlias(newAliasMetaDataBuilder("alias-bar2").filter("{\"term\":{\"user\":\"kimchy\"}}"))
|
||||
.putAlias(newAliasMetaDataBuilder("alias-bar3").routing("routing-bar")))
|
||||
.build();
|
||||
|
||||
String metaDataSource = MetaData.Builder.toXContent(metaData);
|
||||
|
@ -184,6 +188,13 @@ public class ToAndFromJsonMetaDataTests extends ElasticsearchTestCase {
|
|||
assertThat(parsedMetaData.templates().get("foo").template(), is("bar"));
|
||||
assertThat(parsedMetaData.templates().get("foo").settings().get("index.setting1"), is("value1"));
|
||||
assertThat(parsedMetaData.templates().get("foo").settings().getByPrefix("index.").get("setting2"), is("value2"));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().size(), equalTo(3));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().get("alias-bar1").alias(), equalTo("alias-bar1"));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().get("alias-bar2").alias(), equalTo("alias-bar2"));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().get("alias-bar2").filter().string(), equalTo("{\"term\":{\"user\":\"kimchy\"}}"));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().get("alias-bar3").alias(), equalTo("alias-bar3"));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().get("alias-bar3").indexRouting(), equalTo("routing-bar"));
|
||||
assertThat(parsedMetaData.templates().get("foo").aliases().get("alias-bar3").searchRouting(), equalTo("routing-bar"));
|
||||
}
|
||||
|
||||
private static final String MAPPING_SOURCE1 = "{\"mapping1\":{\"text1\":{\"type\":\"string\"}}}";
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.io.File;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
|
@ -84,6 +85,9 @@ public class IndexTemplateFileLoadingTests extends ElasticsearchIntegrationTest
|
|||
ClusterStateResponse stateResponse = client().admin().cluster().prepareState().setIndices(indexName).get();
|
||||
assertThat(stateResponse.getState().getMetaData().indices().get(indexName).getNumberOfShards(), is(10));
|
||||
assertThat(stateResponse.getState().getMetaData().indices().get(indexName).getNumberOfReplicas(), is(0));
|
||||
assertThat(stateResponse.getState().getMetaData().indices().get(indexName).aliases().size(), equalTo(1));
|
||||
String aliasName = indexName + "-alias";
|
||||
assertThat(stateResponse.getState().getMetaData().indices().get(indexName).aliases().get(aliasName).alias(), equalTo(aliasName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,22 +19,34 @@
|
|||
package org.elasticsearch.indices.template;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||
import org.elasticsearch.common.Priority;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.index.query.FilterBuilders;
|
||||
import org.elasticsearch.index.query.QueryParsingException;
|
||||
import org.elasticsearch.indices.IndexTemplateAlreadyExistsException;
|
||||
import org.elasticsearch.indices.InvalidAliasNameException;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
@ -322,4 +334,265 @@ public class SimpleIndexTemplateTests extends ElasticsearchIntegrationTest {
|
|||
GetSettingsResponse getSettingsResponse = client().admin().indices().prepareGetSettings("test").get();
|
||||
assertThat(getSettingsResponse.getIndexToSettings().get("test").getAsMap().get("index.does_not_exist"), equalTo("test"));
|
||||
}
|
||||
|
||||
public void testIndexTemplateWithAliases() throws Exception {
|
||||
|
||||
client().admin().indices().preparePutTemplate("template_with_aliases")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias("simple_alias"))
|
||||
.addAlias(new Alias("templated_alias-{index}"))
|
||||
.addAlias(new Alias("filtered_alias").filter("{\"type\":{\"value\":\"type2\"}}"))
|
||||
.addAlias(new Alias("complex_filtered_alias")
|
||||
.filter(FilterBuilders.termsFilter("_type", "typeX", "typeY", "typeZ").execution("bool").cache(true)))
|
||||
.get();
|
||||
|
||||
client().prepareIndex("test_index", "type1", "1").setSource("field", "A value").get();
|
||||
client().prepareIndex("test_index", "type2", "2").setSource("field", "B value").get();
|
||||
client().prepareIndex("test_index", "typeX", "3").setSource("field", "C value").get();
|
||||
client().prepareIndex("test_index", "typeY", "4").setSource("field", "D value").get();
|
||||
client().prepareIndex("test_index", "typeZ", "5").setSource("field", "E value").get();
|
||||
|
||||
GetAliasesResponse getAliasesResponse = client().admin().indices().prepareGetAliases().setIndices("test_index").get();
|
||||
assertThat(getAliasesResponse.getAliases().size(), equalTo(1));
|
||||
assertThat(getAliasesResponse.getAliases().get("test_index").size(), equalTo(4));
|
||||
|
||||
refresh();
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test_index").get();
|
||||
assertHitCount(searchResponse, 5l);
|
||||
|
||||
searchResponse = client().prepareSearch("simple_alias").get();
|
||||
assertHitCount(searchResponse, 5l);
|
||||
|
||||
searchResponse = client().prepareSearch("templated_alias-test_index").get();
|
||||
assertHitCount(searchResponse, 5l);
|
||||
|
||||
searchResponse = client().prepareSearch("filtered_alias").get();
|
||||
assertHitCount(searchResponse, 1l);
|
||||
assertThat(searchResponse.getHits().getAt(0).type(), equalTo("type2"));
|
||||
|
||||
// Search the complex filter alias
|
||||
searchResponse = client().prepareSearch("complex_filtered_alias").get();
|
||||
assertHitCount(searchResponse, 3l);
|
||||
|
||||
Set<String> types = Sets.newHashSet();
|
||||
for (SearchHit searchHit : searchResponse.getHits().getHits()) {
|
||||
types.add(searchHit.getType());
|
||||
}
|
||||
assertThat(types.size(), equalTo(3));
|
||||
assertThat(types, containsInAnyOrder("typeX", "typeY", "typeZ"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexTemplateWithAliasesInSource() {
|
||||
client().admin().indices().preparePutTemplate("template_1")
|
||||
.setSource("{\n" +
|
||||
" \"template\" : \"*\",\n" +
|
||||
" \"aliases\" : {\n" +
|
||||
" \"my_alias\" : {\n" +
|
||||
" \"filter\" : {\n" +
|
||||
" \"type\" : {\n" +
|
||||
" \"value\" : \"type2\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}").get();
|
||||
|
||||
|
||||
createIndex("test_index");
|
||||
ensureGreen();
|
||||
|
||||
GetAliasesResponse getAliasesResponse = client().admin().indices().prepareGetAliases().setIndices("test_index").get();
|
||||
assertThat(getAliasesResponse.getAliases().size(), equalTo(1));
|
||||
assertThat(getAliasesResponse.getAliases().get("test_index").size(), equalTo(1));
|
||||
|
||||
client().prepareIndex("test_index", "type1", "1").setSource("field", "value1").get();
|
||||
client().prepareIndex("test_index", "type2", "2").setSource("field", "value2").get();
|
||||
refresh();
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test_index").get();
|
||||
assertHitCount(searchResponse, 2l);
|
||||
|
||||
searchResponse = client().prepareSearch("my_alias").get();
|
||||
assertHitCount(searchResponse, 1l);
|
||||
assertThat(searchResponse.getHits().getAt(0).type(), equalTo("type2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexTemplateWithAliasesSource() {
|
||||
client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.setAliases(
|
||||
" {\n" +
|
||||
" \"alias1\" : {},\n" +
|
||||
" \"alias2\" : {\n" +
|
||||
" \"filter\" : {\n" +
|
||||
" \"type\" : {\n" +
|
||||
" \"value\" : \"type2\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"alias3\" : { \"routing\" : \"1\" }" +
|
||||
" }\n").get();
|
||||
|
||||
createIndex("test_index");
|
||||
ensureGreen();
|
||||
|
||||
GetAliasesResponse getAliasesResponse = client().admin().indices().prepareGetAliases().setIndices("test_index").get();
|
||||
assertThat(getAliasesResponse.getAliases().size(), equalTo(1));
|
||||
assertThat(getAliasesResponse.getAliases().get("test_index").size(), equalTo(3));
|
||||
|
||||
client().prepareIndex("test_index", "type1", "1").setSource("field", "value1").get();
|
||||
client().prepareIndex("test_index", "type2", "2").setSource("field", "value2").get();
|
||||
refresh();
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test_index").get();
|
||||
assertHitCount(searchResponse, 2l);
|
||||
|
||||
searchResponse = client().prepareSearch("alias1").get();
|
||||
assertHitCount(searchResponse, 2l);
|
||||
|
||||
searchResponse = client().prepareSearch("alias2").get();
|
||||
assertHitCount(searchResponse, 1l);
|
||||
assertThat(searchResponse.getHits().getAt(0).type(), equalTo("type2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateAlias() throws Exception {
|
||||
client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias("my_alias").filter(FilterBuilders.termFilter("field", "value1")))
|
||||
.addAlias(new Alias("my_alias").filter(FilterBuilders.termFilter("field", "value2")))
|
||||
.get();
|
||||
|
||||
GetIndexTemplatesResponse response = client().admin().indices().prepareGetTemplates("template_1").get();
|
||||
assertThat(response.getIndexTemplates().size(), equalTo(1));
|
||||
assertThat(response.getIndexTemplates().get(0).getAliases().size(), equalTo(1));
|
||||
assertThat(response.getIndexTemplates().get(0).getAliases().get("my_alias").filter().string(), containsString("\"value1\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliasInvalidFilterValidJson() throws Exception {
|
||||
|
||||
//invalid filter but valid json: put index template works fine, fails during index creation
|
||||
client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias("invalid_alias").filter("{ \"invalid\": {} }")).get();
|
||||
|
||||
GetIndexTemplatesResponse response = client().admin().indices().prepareGetTemplates("template_1").get();
|
||||
assertThat(response.getIndexTemplates().size(), equalTo(1));
|
||||
assertThat(response.getIndexTemplates().get(0).getAliases().size(), equalTo(1));
|
||||
assertThat(response.getIndexTemplates().get(0).getAliases().get("invalid_alias").filter().string(), equalTo("{\"invalid\":{}}"));
|
||||
|
||||
try {
|
||||
createIndex("test");
|
||||
fail("index creation should have failed due to invalid alias filter in matching index template");
|
||||
} catch(ElasticsearchIllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [invalid_alias]"));
|
||||
assertThat(e.getCause(), instanceOf(QueryParsingException.class));
|
||||
assertThat(e.getCause().getMessage(), equalTo("[test] No filter registered for [invalid]"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliasInvalidFilterInvalidJson() throws Exception {
|
||||
|
||||
//invalid json: put index template fails
|
||||
PutIndexTemplateRequestBuilder putIndexTemplateRequestBuilder = client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias("invalid_alias").filter("abcde"));
|
||||
|
||||
try {
|
||||
putIndexTemplateRequestBuilder.get();
|
||||
} catch(ElasticsearchIllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [invalid_alias]"));
|
||||
}
|
||||
|
||||
GetIndexTemplatesResponse response = client().admin().indices().prepareGetTemplates("template_1").get();
|
||||
assertThat(response.getIndexTemplates().size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliasNameExistingIndex() throws Exception {
|
||||
|
||||
createIndex("index");
|
||||
|
||||
client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias("index")).get();
|
||||
|
||||
try {
|
||||
createIndex("test");
|
||||
fail("index creation should have failed due to alias with existing index name in mathching index template");
|
||||
} catch(InvalidAliasNameException e) {
|
||||
assertThat(e.getMessage(), equalTo("[test] Invalid alias name [index], an index exists with the same name as the alias"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliasEmptyName() throws Exception {
|
||||
PutIndexTemplateRequestBuilder putIndexTemplateRequestBuilder = client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias(" ").indexRouting("1,2,3"));
|
||||
|
||||
try {
|
||||
putIndexTemplateRequestBuilder.get();
|
||||
fail("put template should have failed due to alias with empty name");
|
||||
} catch (ElasticsearchIllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), equalTo("alias name is required"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAliasWithMultipleIndexRoutings() throws Exception {
|
||||
PutIndexTemplateRequestBuilder putIndexTemplateRequestBuilder = client().admin().indices().preparePutTemplate("template_1")
|
||||
.setTemplate("te*")
|
||||
.addAlias(new Alias("alias").indexRouting("1,2,3"));
|
||||
|
||||
try {
|
||||
putIndexTemplateRequestBuilder.get();
|
||||
fail("put template should have failed due to alias with multiple index routings");
|
||||
} catch (ElasticsearchIllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), equalTo("alias [alias] has several index routing values associated with it"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
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(FilterBuilders.missingFilter("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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,8 @@
|
|||
"settings" : {
|
||||
"index.number_of_shards": 10,
|
||||
"index.number_of_replicas": 0
|
||||
},
|
||||
"aliases" : {
|
||||
"{index}-alias" : {}
|
||||
}
|
||||
}
|
|
@ -3,5 +3,8 @@
|
|||
"settings" : {
|
||||
"number_of_shards": 10,
|
||||
"number_of_replicas": 0
|
||||
},
|
||||
"aliases" : {
|
||||
"{index}-alias" : {}
|
||||
}
|
||||
}
|
|
@ -5,5 +5,8 @@
|
|||
"number_of_shards": 10,
|
||||
"number_of_replicas": 0
|
||||
}
|
||||
},
|
||||
"aliases" : {
|
||||
"{index}-alias" : {}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@
|
|||
"settings" : {
|
||||
"index.number_of_shards": 10,
|
||||
"index.number_of_replicas": 0
|
||||
},
|
||||
"aliases" : {
|
||||
"{index}-alias" : {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@
|
|||
"settings" : {
|
||||
"number_of_shards": 10,
|
||||
"number_of_replicas": 0
|
||||
},
|
||||
"aliases" : {
|
||||
"{index}-alias" : {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,9 @@
|
|||
"number_of_shards": 10,
|
||||
"number_of_replicas": 0
|
||||
}
|
||||
},
|
||||
"aliases" : {
|
||||
"{index}-alias" : {}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue