View Javadoc
1   package org.wikimedia.search.extra.util;
2   
3   import java.io.IOException;
4   import java.util.Collections;
5   import java.util.List;
6   import java.util.Map;
7   import java.util.stream.Collectors;
8   
9   import org.apache.lucene.index.IndexReader;
10  import org.elasticsearch.common.bytes.BytesReference;
11  import org.elasticsearch.common.xcontent.XContentHelper;
12  import org.elasticsearch.common.xcontent.support.XContentMapValues;
13  import org.elasticsearch.index.fieldvisitor.CustomFieldsVisitor;
14  
15  import com.google.common.collect.ImmutableSet;
16  
17  /**
18   * Hub for fetching field values.
19   */
20  public abstract class FieldValues {
21      /**
22       * Loads field values.
23       */
24      public interface Loader {
25          /**
26           * Load the value of the string at path from reader for docId.
27           */
28          List<String> load(String path, IndexReader reader, int docId) throws IOException;
29      }
30  
31      /**
32       * Load field values from source. Note that values aren't cached between
33       * calls so providing the same arguments over and over again would call down
34       * into Lucene every time.
35       */
36      public static FieldValues.Loader loadFromSource() {
37          return Source.INSTANCE;
38      }
39  
40      /**
41       * Load field values from a stored field. Note that values aren't cached
42       * between calls so providing the same arguments over and over again would
43       * call down into Lucene every time.
44       */
45      public static FieldValues.Loader loadFromStoredField() {
46          return Stored.INSTANCE;
47      }
48  
49      private FieldValues() {
50          // Util class
51      }
52  
53      private static final class Source implements FieldValues.Loader {
54          private static final FieldValues.Loader INSTANCE = new Source();
55          @Override
56          public List<String> load(String path, IndexReader reader, int docId) throws IOException {
57              CustomFieldsVisitor visitor = new CustomFieldsVisitor(Collections.emptySet(), true);
58              reader.document(docId, visitor);
59              BytesReference source = visitor.source();
60              // deprecated but still in use in core
61              // Monitor how it evolves in core and FetchSubPhase.java
62              // https://github.com/elastic/elasticsearch/blob/master/server/src/main/java/org/elasticsearch/search/fetch/FetchPhase.java#L290
63              Map<String, Object> map = XContentHelper.convertToMap(source, false).v2();
64              return XContentMapValues.extractRawValues(path, map).stream()
65                      .map(Object::toString)
66                      .collect(Collectors.toList());
67          }
68      }
69  
70      private static final class Stored implements FieldValues.Loader {
71          private static final FieldValues.Loader INSTANCE = new Stored();
72          @Override
73          public List<String> load(String path, IndexReader reader, int docId) throws IOException {
74              CustomFieldsVisitor visitor = new CustomFieldsVisitor(ImmutableSet.of(path), false);
75              reader.document(docId, visitor);
76              return visitor.fields().get(path).stream().map(Object::toString).collect(Collectors.toList());
77          }
78      }
79  }