Browse Source

Add wildcard support to field resolving in the Get Field Mapping API

Closes #4367
Boaz Leskes 12 years ago
parent
commit
99b421925f

+ 5 - 2
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

+ 58 - 10
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<String, FieldMappingMetaData> findFieldMappingsByType(DocumentMapper documentMapper, String[] fields,
                                                                                boolean includeDefaults) throws ElasticSearchException {
         MapBuilder<String, FieldMappingMetaData> fieldMappings = new MapBuilder<String, FieldMappingMetaData>();
+        ImmutableList<FieldMapper> 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<String, FieldMappingMetaData> 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);
+        }
+    }
+
 
 }