AbstractFieldDataTestCase.java 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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.fielddata;
  9. import org.apache.lucene.analysis.standard.StandardAnalyzer;
  10. import org.apache.lucene.document.Document;
  11. import org.apache.lucene.document.Field;
  12. import org.apache.lucene.document.StringField;
  13. import org.apache.lucene.index.DirectoryReader;
  14. import org.apache.lucene.index.IndexWriter;
  15. import org.apache.lucene.index.IndexWriterConfig;
  16. import org.apache.lucene.index.LeafReaderContext;
  17. import org.apache.lucene.index.LogByteSizeMergePolicy;
  18. import org.apache.lucene.search.IndexSearcher;
  19. import org.apache.lucene.search.Query;
  20. import org.apache.lucene.store.ByteBuffersDirectory;
  21. import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
  22. import org.elasticsearch.common.settings.Settings;
  23. import org.elasticsearch.index.IndexService;
  24. import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
  25. import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
  26. import org.elasticsearch.index.mapper.BinaryFieldMapper;
  27. import org.elasticsearch.index.mapper.ContentPath;
  28. import org.elasticsearch.index.mapper.GeoPointFieldMapper;
  29. import org.elasticsearch.index.mapper.KeywordFieldMapper;
  30. import org.elasticsearch.index.mapper.MappedFieldType;
  31. import org.elasticsearch.index.mapper.MapperService;
  32. import org.elasticsearch.index.mapper.NumberFieldMapper;
  33. import org.elasticsearch.index.mapper.TextFieldMapper;
  34. import org.elasticsearch.index.query.SearchExecutionContext;
  35. import org.elasticsearch.index.shard.ShardId;
  36. import org.elasticsearch.indices.IndicesService;
  37. import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
  38. import org.elasticsearch.plugins.Plugin;
  39. import org.elasticsearch.script.ScriptCompiler;
  40. import org.elasticsearch.test.ESSingleNodeTestCase;
  41. import org.elasticsearch.test.InternalSettingsPlugin;
  42. import org.junit.After;
  43. import org.junit.Before;
  44. import java.io.IOException;
  45. import java.util.Collection;
  46. import java.util.List;
  47. import static java.util.Collections.emptyMap;
  48. import static org.hamcrest.Matchers.equalTo;
  49. import static org.hamcrest.Matchers.not;
  50. import static org.hamcrest.Matchers.sameInstance;
  51. public abstract class AbstractFieldDataTestCase extends ESSingleNodeTestCase {
  52. protected IndexService indexService;
  53. protected MapperService mapperService;
  54. protected IndexWriter writer;
  55. protected List<LeafReaderContext> readerContexts = null;
  56. protected DirectoryReader topLevelReader = null;
  57. protected IndicesFieldDataCache indicesFieldDataCache;
  58. protected SearchExecutionContext searchExecutionContext;
  59. protected abstract String getFieldDataType();
  60. protected boolean hasDocValues() {
  61. return false;
  62. }
  63. public <IFD extends IndexFieldData<?>> IFD getForField(String fieldName) {
  64. return getForField(getFieldDataType(), fieldName, hasDocValues());
  65. }
  66. public <IFD extends IndexFieldData<?>> IFD getForField(String type, String fieldName) {
  67. return getForField(type, fieldName, hasDocValues());
  68. }
  69. @Override
  70. protected Collection<Class<? extends Plugin>> getPlugins() {
  71. return pluginList(InternalSettingsPlugin.class);
  72. }
  73. public <IFD extends IndexFieldData<?>> IFD getForField(String type, String fieldName, boolean docValues) {
  74. final MappedFieldType fieldType;
  75. final ContentPath contentPath = new ContentPath(1);
  76. if (type.equals("string")) {
  77. if (docValues) {
  78. fieldType = new KeywordFieldMapper.Builder(fieldName).build(contentPath).fieldType();
  79. } else {
  80. fieldType = new TextFieldMapper.Builder(fieldName, createDefaultIndexAnalyzers())
  81. .fielddata(true).build(contentPath).fieldType();
  82. }
  83. } else if (type.equals("float")) {
  84. fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.FLOAT, ScriptCompiler.NONE, false, true)
  85. .docValues(docValues).build(contentPath).fieldType();
  86. } else if (type.equals("double")) {
  87. fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.DOUBLE, ScriptCompiler.NONE, false, true)
  88. .docValues(docValues).build(contentPath).fieldType();
  89. } else if (type.equals("long")) {
  90. fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.LONG, ScriptCompiler.NONE, false, true)
  91. .docValues(docValues).build(contentPath).fieldType();
  92. } else if (type.equals("int")) {
  93. fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.INTEGER, ScriptCompiler.NONE, false, true)
  94. .docValues(docValues).build(contentPath).fieldType();
  95. } else if (type.equals("short")) {
  96. fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.SHORT, ScriptCompiler.NONE, false, true)
  97. .docValues(docValues).build(contentPath).fieldType();
  98. } else if (type.equals("byte")) {
  99. fieldType = new NumberFieldMapper.Builder(fieldName, NumberFieldMapper.NumberType.BYTE, ScriptCompiler.NONE, false, true)
  100. .docValues(docValues).build(contentPath).fieldType();
  101. } else if (type.equals("geo_point")) {
  102. fieldType = new GeoPointFieldMapper.Builder(fieldName, ScriptCompiler.NONE, false)
  103. .docValues(docValues)
  104. .build(contentPath)
  105. .fieldType();
  106. } else if (type.equals("binary")) {
  107. fieldType = new BinaryFieldMapper.Builder(fieldName, docValues).build(contentPath).fieldType();
  108. } else {
  109. throw new UnsupportedOperationException(type);
  110. }
  111. return searchExecutionContext.getForField(fieldType);
  112. }
  113. @Before
  114. public void setup() throws Exception {
  115. indexService = createIndex("test", Settings.builder().build());
  116. mapperService = indexService.mapperService();
  117. indicesFieldDataCache = getInstanceFromNode(IndicesService.class).getIndicesFieldDataCache();
  118. // LogByteSizeMP to preserve doc ID order
  119. writer = new IndexWriter(
  120. new ByteBuffersDirectory(), new IndexWriterConfig(new StandardAnalyzer()).setMergePolicy(new LogByteSizeMergePolicy())
  121. );
  122. searchExecutionContext = indexService.newSearchExecutionContext(0, 0, null, () -> 0, null, emptyMap());
  123. }
  124. protected final List<LeafReaderContext> refreshReader() throws Exception {
  125. if (readerContexts != null && topLevelReader != null) {
  126. topLevelReader.close();
  127. }
  128. topLevelReader = ElasticsearchDirectoryReader.wrap(DirectoryReader.open(writer), new ShardId("foo", "_na_", 1));
  129. readerContexts = topLevelReader.leaves();
  130. return readerContexts;
  131. }
  132. @Override
  133. @After
  134. public void tearDown() throws Exception {
  135. super.tearDown();
  136. if (topLevelReader != null) {
  137. topLevelReader.close();
  138. }
  139. writer.close();
  140. searchExecutionContext = null;
  141. }
  142. protected Nested createNested(IndexSearcher searcher, Query parentFilter, Query childFilter) throws IOException {
  143. BitsetFilterCache s = indexService.cache().bitsetFilterCache();
  144. return new Nested(s.getBitSetProducer(parentFilter), childFilter, null, searcher);
  145. }
  146. public void testEmpty() throws Exception {
  147. Document d = new Document();
  148. d.add(new StringField("field", "value", Field.Store.NO));
  149. writer.addDocument(d);
  150. refreshReader();
  151. IndexFieldData<?> fieldData = getForField("non_existing_field");
  152. int max = randomInt(7);
  153. for (LeafReaderContext readerContext : readerContexts) {
  154. LeafFieldData previous = null;
  155. for (int i = 0; i < max; i++) {
  156. LeafFieldData current = fieldData.load(readerContext);
  157. assertThat(current.ramBytesUsed(), equalTo(0L));
  158. if (previous != null) {
  159. assertThat(current, not(sameInstance(previous)));
  160. }
  161. previous = current;
  162. }
  163. }
  164. }
  165. }