ProvidedIdFieldMapper.java 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
  3. * or more contributor license agreements. Licensed under the Elastic License
  4. * 2.0 and the Server Side Public License, v 1; you may not use this file except
  5. * in compliance with, at your election, the Elastic License 2.0 or the Server
  6. * Side Public License, v 1.
  7. */
  8. package org.elasticsearch.index.mapper;
  9. import org.apache.lucene.index.LeafReaderContext;
  10. import org.apache.lucene.search.SortField;
  11. import org.apache.lucene.util.BytesRef;
  12. import org.elasticsearch.common.logging.DeprecationCategory;
  13. import org.elasticsearch.common.logging.DeprecationLogger;
  14. import org.elasticsearch.common.util.BigArrays;
  15. import org.elasticsearch.index.fielddata.FieldData;
  16. import org.elasticsearch.index.fielddata.FieldDataContext;
  17. import org.elasticsearch.index.fielddata.IndexFieldData;
  18. import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
  19. import org.elasticsearch.index.fielddata.IndexFieldDataCache;
  20. import org.elasticsearch.index.fielddata.LeafFieldData;
  21. import org.elasticsearch.index.fielddata.ScriptDocValues;
  22. import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
  23. import org.elasticsearch.index.fielddata.fieldcomparator.BytesRefFieldComparatorSource;
  24. import org.elasticsearch.index.fielddata.plain.PagedBytesIndexFieldData;
  25. import org.elasticsearch.index.query.SearchExecutionContext;
  26. import org.elasticsearch.indices.IndicesService;
  27. import org.elasticsearch.indices.breaker.CircuitBreakerService;
  28. import org.elasticsearch.script.field.DelegateDocValuesField;
  29. import org.elasticsearch.script.field.DocValuesScriptFieldFactory;
  30. import org.elasticsearch.search.DocValueFormat;
  31. import org.elasticsearch.search.MultiValueMode;
  32. import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
  33. import org.elasticsearch.search.aggregations.support.ValuesSourceType;
  34. import org.elasticsearch.search.sort.BucketedSort;
  35. import org.elasticsearch.search.sort.SortOrder;
  36. import java.io.IOException;
  37. import java.util.Arrays;
  38. import java.util.function.BooleanSupplier;
  39. /**
  40. * A mapper for the {@code _id} field that reads the from the
  41. * {@link SourceToParse#id()}. It also supports field data
  42. * if the cluster is configured to allow it.
  43. */
  44. public class ProvidedIdFieldMapper extends IdFieldMapper {
  45. private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(ProvidedIdFieldMapper.class);
  46. static final String ID_FIELD_DATA_DEPRECATION_MESSAGE =
  47. "Loading the fielddata on the _id field is deprecated and will be removed in future versions. "
  48. + "If you require sorting or aggregating on this field you should also include the id in the "
  49. + "body of your documents, and map this field as a keyword field that has [doc_values] enabled";
  50. public static final ProvidedIdFieldMapper NO_FIELD_DATA = new ProvidedIdFieldMapper(() -> false);
  51. static final class IdFieldType extends AbstractIdFieldType {
  52. private final BooleanSupplier fieldDataEnabled;
  53. IdFieldType(BooleanSupplier fieldDataEnabled) {
  54. this.fieldDataEnabled = fieldDataEnabled;
  55. }
  56. @Override
  57. public boolean mayExistInIndex(SearchExecutionContext context) {
  58. return true;
  59. }
  60. @Override
  61. public boolean isAggregatable() {
  62. return fieldDataEnabled.getAsBoolean();
  63. }
  64. @Override
  65. public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) {
  66. if (fieldDataEnabled.getAsBoolean() == false) {
  67. throw new IllegalArgumentException(
  68. "Fielddata access on the _id field is disallowed, "
  69. + "you can re-enable it by updating the dynamic cluster setting: "
  70. + IndicesService.INDICES_ID_FIELD_DATA_ENABLED_SETTING.getKey()
  71. );
  72. }
  73. final IndexFieldData.Builder fieldDataBuilder = new PagedBytesIndexFieldData.Builder(
  74. name(),
  75. TextFieldMapper.Defaults.FIELDDATA_MIN_FREQUENCY,
  76. TextFieldMapper.Defaults.FIELDDATA_MAX_FREQUENCY,
  77. TextFieldMapper.Defaults.FIELDDATA_MIN_SEGMENT_SIZE,
  78. CoreValuesSourceType.KEYWORD,
  79. (dv, n) -> new DelegateDocValuesField(
  80. new ScriptDocValues.Strings(new ScriptDocValues.StringsSupplier(FieldData.toString(dv))),
  81. n
  82. )
  83. );
  84. return new IndexFieldData.Builder() {
  85. @Override
  86. public IndexFieldData<?> build(IndexFieldDataCache cache, CircuitBreakerService breakerService) {
  87. deprecationLogger.warn(DeprecationCategory.AGGREGATIONS, "id_field_data", ID_FIELD_DATA_DEPRECATION_MESSAGE);
  88. final IndexFieldData<?> fieldData = fieldDataBuilder.build(cache, breakerService);
  89. return new IndexFieldData<>() {
  90. @Override
  91. public String getFieldName() {
  92. return fieldData.getFieldName();
  93. }
  94. @Override
  95. public ValuesSourceType getValuesSourceType() {
  96. return fieldData.getValuesSourceType();
  97. }
  98. @Override
  99. public LeafFieldData load(LeafReaderContext context) {
  100. return wrap(fieldData.load(context));
  101. }
  102. @Override
  103. public LeafFieldData loadDirect(LeafReaderContext context) throws Exception {
  104. return wrap(fieldData.loadDirect(context));
  105. }
  106. @Override
  107. public SortField sortField(Object missingValue, MultiValueMode sortMode, Nested nested, boolean reverse) {
  108. XFieldComparatorSource source = new BytesRefFieldComparatorSource(this, missingValue, sortMode, nested);
  109. return new SortField(getFieldName(), source, reverse);
  110. }
  111. @Override
  112. public BucketedSort newBucketedSort(
  113. BigArrays bigArrays,
  114. Object missingValue,
  115. MultiValueMode sortMode,
  116. Nested nested,
  117. SortOrder sortOrder,
  118. DocValueFormat format,
  119. int bucketSize,
  120. BucketedSort.ExtraData extra
  121. ) {
  122. throw new UnsupportedOperationException("can't sort on the [" + CONTENT_TYPE + "] field");
  123. }
  124. };
  125. }
  126. };
  127. }
  128. }
  129. private static LeafFieldData wrap(LeafFieldData in) {
  130. return new LeafFieldData() {
  131. @Override
  132. public void close() {
  133. in.close();
  134. }
  135. @Override
  136. public long ramBytesUsed() {
  137. return in.ramBytesUsed();
  138. }
  139. @Override
  140. public DocValuesScriptFieldFactory getScriptFieldFactory(String name) {
  141. return new DelegateDocValuesField(new ScriptDocValues.Strings(new ScriptDocValues.StringsSupplier(getBytesValues())), name);
  142. }
  143. @Override
  144. public SortedBinaryDocValues getBytesValues() {
  145. SortedBinaryDocValues inValues = in.getBytesValues();
  146. return new SortedBinaryDocValues() {
  147. @Override
  148. public BytesRef nextValue() throws IOException {
  149. BytesRef encoded = inValues.nextValue();
  150. return new BytesRef(
  151. Uid.decodeId(Arrays.copyOfRange(encoded.bytes, encoded.offset, encoded.offset + encoded.length))
  152. );
  153. }
  154. @Override
  155. public int docValueCount() {
  156. final int count = inValues.docValueCount();
  157. // If the count is not 1 then the impl is not correct as the binary representation
  158. // does not preserve order. But id fields only have one value per doc so we are good.
  159. assert count == 1;
  160. return inValues.docValueCount();
  161. }
  162. @Override
  163. public boolean advanceExact(int doc) throws IOException {
  164. return inValues.advanceExact(doc);
  165. }
  166. };
  167. }
  168. };
  169. }
  170. public ProvidedIdFieldMapper(BooleanSupplier fieldDataEnabled) {
  171. super(new IdFieldType(fieldDataEnabled));
  172. }
  173. @Override
  174. public void preParse(DocumentParserContext context) {
  175. if (context.sourceToParse().id() == null) {
  176. throw new IllegalStateException("_id should have been set on the coordinating node");
  177. }
  178. context.id(context.sourceToParse().id());
  179. context.doc().add(standardIdField(context.id()));
  180. }
  181. @Override
  182. public String documentDescription(DocumentParserContext context) {
  183. return "document with id '" + context.sourceToParse().id() + "'";
  184. }
  185. @Override
  186. public String documentDescription(ParsedDocument parsedDocument) {
  187. return "[" + parsedDocument.id() + "]";
  188. }
  189. @Override
  190. public String reindexId(String id) {
  191. return id;
  192. }
  193. }