Browse Source

Support fetching _tier field value (#71379)

Now that the `fields` option allows fetching metadata fields, we can support
loading the new `_tier` metadata field.

Relates to #63569 and #68135.
Julie Tibshirani 4 years ago
parent
commit
3da738e5db

+ 6 - 7
docs/reference/mapping/fields.asciidoc

@@ -13,11 +13,6 @@ fields can be customized when a mapping is created.
 
     The index to which the document belongs.
 
-<<mapping-tier-field,`_tier`>>::
-
-    The current data tier preference of the index to which the document belongs.
-
-
 <<mapping-id-field,`_id`>>::
 
     The document's ID.
@@ -67,6 +62,10 @@ fields can be customized when a mapping is created.
 
     Application specific metadata.
 
+<<mapping-tier-field,`_tier`>>::
+
+    The current data tier preference of the index to which the document belongs.
+
 include::fields/doc-count-field.asciidoc[]
 
 include::fields/field-names-field.asciidoc[]
@@ -77,10 +76,10 @@ include::fields/id-field.asciidoc[]
 
 include::fields/index-field.asciidoc[]
 
-include::fields/tier-field.asciidoc[]
-
 include::fields/meta-field.asciidoc[]
 
 include::fields/routing-field.asciidoc[]
 
 include::fields/source-field.asciidoc[]
+
+include::fields/tier-field.asciidoc[]

+ 33 - 9
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/mapper/DataTierFieldMapper.java

@@ -12,6 +12,7 @@ import org.apache.lucene.search.MatchNoDocsQuery;
 import org.apache.lucene.search.Query;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.regex.Regex;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.mapper.ConstantFieldType;
 import org.elasticsearch.index.mapper.KeywordFieldMapper;
 import org.elasticsearch.index.mapper.MetadataFieldMapper;
@@ -20,6 +21,7 @@ import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.xpack.cluster.routing.allocation.DataTierAllocationDecider;
 
 import java.util.Collections;
+import java.util.List;
 
 public class DataTierFieldMapper extends MetadataFieldMapper {
 
@@ -52,20 +54,18 @@ public class DataTierFieldMapper extends MetadataFieldMapper {
             if (caseInsensitive) {
                 pattern = Strings.toLowercaseAscii(pattern);
             }
-            String tierPreference = DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(context.getIndexSettings().getSettings());
-            if (Strings.hasText(tierPreference) == false) {
+
+            String tierPreference = getTierPreference(context);
+            if (tierPreference == null) {
                 return false;
             }
-            // Tier preference can be a comma-delimited list of tiers, ordered by preference
-            // It was decided we should only test the first of these potentially multiple preferences.
-            String firstPreference = tierPreference.split(",")[0].trim();
-            return Regex.simpleMatch(pattern, firstPreference);
+            return Regex.simpleMatch(pattern, tierPreference);
         }
 
         @Override
         public Query existsQuery(SearchExecutionContext context) {
-            String tierPreference = DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(context.getIndexSettings().getSettings());
-            if (Strings.hasText(tierPreference) == false) {
+            String tierPreference = getTierPreference(context);
+            if (tierPreference == null) {
                 return new MatchNoDocsQuery();
             }
             return new MatchAllDocsQuery();
@@ -73,7 +73,31 @@ public class DataTierFieldMapper extends MetadataFieldMapper {
 
         @Override
         public ValueFetcher valueFetcher(SearchExecutionContext context, String format) {
-            throw new UnsupportedOperationException("Cannot fetch values for internal field [" + name() + "].");
+            if (format != null) {
+                throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats.");
+            }
+
+            String tierPreference = getTierPreference(context);
+            return tierPreference == null
+                ? lookup -> List.of()
+                : lookup -> List.of(tierPreference);
+        }
+
+        /**
+         * Retrieve the first tier preference from the index setting. If the setting is not
+         * present, then return null.
+         */
+        private String getTierPreference(SearchExecutionContext context) {
+            Settings settings = context.getIndexSettings().getSettings();
+            String value = DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings);
+
+            if (Strings.hasText(value) == false) {
+                return null;
+            }
+
+            // Tier preference can be a comma-delimited list of tiers, ordered by preference
+            // It was decided we should only test the first of these potentially multiple preferences.
+            return value.split(",")[0].trim();
         }
     }
 

+ 14 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/mapper/DataTierFieldTypeTests.java

@@ -16,8 +16,10 @@ import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.MapperServiceTestCase;
+import org.elasticsearch.index.mapper.ValueFetcher;
 import org.elasticsearch.index.query.QueryShardException;
 import org.elasticsearch.index.query.SearchExecutionContext;
+import org.elasticsearch.search.lookup.SourceLookup;
 import org.elasticsearch.xpack.cluster.routing.allocation.DataTierAllocationDecider;
 
 import java.io.IOException;
@@ -25,6 +27,7 @@ import java.util.Arrays;
 import java.util.function.Predicate;
 
 import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonList;
 import static org.hamcrest.Matchers.containsString;
 
 public class DataTierFieldTypeTests extends MapperServiceTestCase {
@@ -81,6 +84,17 @@ public class DataTierFieldTypeTests extends MapperServiceTestCase {
         assertThat(e.getMessage(), containsString("Can only use regexp queries on keyword and text fields"));
     }
 
+    public void testFetchValue() throws IOException {
+        MappedFieldType ft = DataTierFieldMapper.DataTierFieldType.INSTANCE;
+        SourceLookup lookup = new SourceLookup();
+
+        ValueFetcher valueFetcher = ft.valueFetcher(createContext(), null);
+        assertEquals(singletonList("data_warm"), valueFetcher.fetchValues(lookup));
+
+        ValueFetcher emptyValueFetcher = ft.valueFetcher(createContextWithoutSetting(), null);
+        assertTrue(emptyValueFetcher.fetchValues(lookup).isEmpty());
+    }
+
     private SearchExecutionContext createContext() {
         IndexMetadata indexMetadata = IndexMetadata.builder("index")
             .settings(