From 99b421925fee14603944f373030c474f6d8e6901 Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Fri, 6 Dec 2013 21:40:54 +0100 Subject: [PATCH] Add wildcard support to field resolving in the Get Field Mapping API Closes #4367 --- .../indices/get-field-mapping.asciidoc | 7 +- .../get/TransportGetFieldMappingsAction.java | 68 ++++++++++++++++--- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/docs/reference/indices/get-field-mapping.asciidoc b/docs/reference/indices/get-field-mapping.asciidoc index f1ec45b2135..0633744f845 100644 --- a/docs/reference/indices/get-field-mapping.asciidoc +++ b/docs/reference/indices/get-field-mapping.asciidoc @@ -38,7 +38,7 @@ For which the response is (assuming `text` is a default string field): The get field mapping API can be used to get the mapping of multiple fields from more than one index or type with a single call. General usage of the API follows the following syntax: `host:port/{index}/{type}/_mapping/field/{field}` where -`{index}`, `{type}` and `{field}` can stand for comma-separated list of names. To +`{index}`, `{type}` and `{field}` can stand for comma-separated list of names or wild cards. To get mappings for all indices you can use `_all` for `{index}`. The following are some examples: @@ -47,12 +47,15 @@ following are some examples: curl -XGET 'http://localhost:9200/twitter,kimchy/_mapping/field/message' curl -XGET 'http://localhost:9200/_all/tweet,book/_mapping/field/message,user.id' + +curl -XGET 'http://localhost:9200/_all/tw*/_mapping/field/*.id' -------------------------------------------------- [float] === Specifying fields -The get mapping api allows you to specify fields using any of the following: +The get mapping api allows you to specify one or more fields separated with by a comma. +You can also use wildcards. The field names can be any of the following: [horizontal] Full names:: the full path, including any parent object name the field is diff --git a/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java b/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java index d37a446abe4..51f6833f9dc 100644 --- a/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java +++ b/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java @@ -21,6 +21,7 @@ package org.elasticsearch.action.admin.indices.mapping.get; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import org.elasticsearch.ElasticSearchException; @@ -168,22 +169,69 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction< private ImmutableMap findFieldMappingsByType(DocumentMapper documentMapper, String[] fields, boolean includeDefaults) throws ElasticSearchException { MapBuilder fieldMappings = new MapBuilder(); + ImmutableList allFieldMappers = documentMapper.mappers().mappers(); for (String field : fields) { - FieldMapper fieldMapper = documentMapper.mappers().smartNameFieldMapper(field); - if (fieldMapper != null) { - try { - XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); - builder.startObject(); - fieldMapper.toXContent(builder, includeDefaults ? includeDefaultsParams : ToXContent.EMPTY_PARAMS); - builder.endObject(); - fieldMappings.put(field, new FieldMappingMetaData(fieldMapper.names().fullName(), builder.bytes())); - } catch (IOException e) { - throw new ElasticSearchException("failed to serialize XContent of field [" + field + "]", e); + if (Regex.isMatchAllPattern(field)) { + for (FieldMapper fieldMapper : allFieldMappers) { + addFieldMapper(fieldMapper.names().fullName(), fieldMapper, fieldMappings, includeDefaults); + } + } else if (Regex.isSimpleMatchPattern(field)) { + // go through the field mappers 3 times, to make sure we give preference to the resolve order: full name, index name, name. + // also make sure we only store each mapper once. + boolean[] resolved = new boolean[allFieldMappers.size()]; + for (int i = 0; i < allFieldMappers.size(); i++) { + FieldMapper fieldMapper = allFieldMappers.get(i); + if (Regex.simpleMatch(field, fieldMapper.names().fullName())) { + addFieldMapper(fieldMapper.names().fullName(), fieldMapper, fieldMappings, includeDefaults); + resolved[i] = true; + } + } + for (int i = 0; i < allFieldMappers.size(); i++) { + if (resolved[i]) { + continue; + } + FieldMapper fieldMapper = allFieldMappers.get(i); + if (Regex.simpleMatch(field, fieldMapper.names().indexName())) { + addFieldMapper(fieldMapper.names().indexName(), fieldMapper, fieldMappings, includeDefaults); + resolved[i] = true; + } + } + for (int i = 0; i < allFieldMappers.size(); i++) { + if (resolved[i]) { + continue; + } + FieldMapper fieldMapper = allFieldMappers.get(i); + if (Regex.simpleMatch(field, fieldMapper.names().name())) { + addFieldMapper(fieldMapper.names().name(), fieldMapper, fieldMappings, includeDefaults); + resolved[i] = true; + } + } + + } else { + // not a pattern + FieldMapper fieldMapper = documentMapper.mappers().smartNameFieldMapper(field); + if (fieldMapper != null) { + addFieldMapper(field, fieldMapper, fieldMappings, includeDefaults); } } } return fieldMappings.immutableMap(); } + private void addFieldMapper(String field, FieldMapper fieldMapper, MapBuilder fieldMappings, boolean includeDefaults) { + if (fieldMappings.containsKey(field)) { + return; + } + try { + XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); + builder.startObject(); + fieldMapper.toXContent(builder, includeDefaults ? includeDefaultsParams : ToXContent.EMPTY_PARAMS); + builder.endObject(); + fieldMappings.put(field, new FieldMappingMetaData(fieldMapper.names().fullName(), builder.bytes())); + } catch (IOException e) { + throw new ElasticSearchException("failed to serialize XContent of field [" + field + "]", e); + } + } + } \ No newline at end of file