|
| 1 | +/* |
| 2 | + * Licensed to Elasticsearch under one or more contributor |
| 3 | + * license agreements. See the NOTICE file distributed with |
| 4 | + * this work for additional information regarding copyright |
| 5 | + * ownership. Elasticsearch licenses this file to you under |
| 6 | + * the Apache License, Version 2.0 (the "License"); you may |
| 7 | + * not use this file except in compliance with the License. |
| 8 | + * You may obtain a copy of the License at |
| 9 | + * |
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | + * |
| 12 | + * Unless required by applicable law or agreed to in writing, |
| 13 | + * software distributed under the License is distributed on an |
| 14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | + * KIND, either express or implied. See the License for the |
| 16 | + * specific language governing permissions and limitations |
| 17 | + * under the License. |
| 18 | + */ |
| 19 | + |
| 20 | +package org.elasticsearch.index.mapper; |
| 21 | + |
| 22 | +import org.elasticsearch.Version; |
| 23 | +import org.elasticsearch.common.settings.Settings; |
| 24 | +import org.elasticsearch.index.fielddata.AtomicFieldData; |
| 25 | +import org.elasticsearch.index.fielddata.IndexFieldData; |
| 26 | +import org.elasticsearch.index.fielddata.ScriptDocValues; |
| 27 | +import org.elasticsearch.index.mapper.FlatObjectFieldMapper.KeyedFlatObjectFieldType; |
| 28 | +import org.elasticsearch.search.lookup.LeafDocLookup; |
| 29 | +import org.elasticsearch.search.lookup.SearchLookup; |
| 30 | +import org.elasticsearch.test.ESTestCase; |
| 31 | + |
| 32 | +import java.util.Arrays; |
| 33 | +import java.util.HashSet; |
| 34 | +import java.util.Set; |
| 35 | +import java.util.function.Function; |
| 36 | + |
| 37 | +import static java.util.Collections.emptyList; |
| 38 | +import static java.util.Collections.singletonList; |
| 39 | +import static org.hamcrest.Matchers.instanceOf; |
| 40 | +import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; |
| 41 | +import static org.mockito.Matchers.anyObject; |
| 42 | +import static org.mockito.Mockito.doReturn; |
| 43 | +import static org.mockito.Mockito.mock; |
| 44 | +import static org.mockito.Mockito.when; |
| 45 | + |
| 46 | +public class FlatObjectFieldLookupTests extends ESTestCase { |
| 47 | + |
| 48 | + public void testFieldTypeLookup() { |
| 49 | + String fieldName = "object1.object2.field"; |
| 50 | + FlatObjectFieldMapper mapper = createFlatObjectMapper(fieldName); |
| 51 | + |
| 52 | + FieldTypeLookup lookup = new FieldTypeLookup() |
| 53 | + .copyAndAddAll("type", singletonList(mapper), emptyList()); |
| 54 | + assertEquals(mapper.fieldType(), lookup.get(fieldName)); |
| 55 | + |
| 56 | + String objectKey = "key1.key2"; |
| 57 | + String searchFieldName = fieldName + "." + objectKey; |
| 58 | + |
| 59 | + MappedFieldType searchFieldType = lookup.get(searchFieldName); |
| 60 | + assertEquals(mapper.keyedFieldName(), searchFieldType.name()); |
| 61 | + assertThat(searchFieldType, instanceOf(KeyedFlatObjectFieldType.class)); |
| 62 | + |
| 63 | + FlatObjectFieldMapper.KeyedFlatObjectFieldType keyedFieldType = (KeyedFlatObjectFieldType) searchFieldType; |
| 64 | + assertEquals(objectKey, keyedFieldType.key()); |
| 65 | + } |
| 66 | + |
| 67 | + public void testFieldTypeLookupWithAlias() { |
| 68 | + String fieldName = "object1.object2.field"; |
| 69 | + FlatObjectFieldMapper mapper = createFlatObjectMapper(fieldName); |
| 70 | + |
| 71 | + String aliasName = "alias"; |
| 72 | + FieldAliasMapper alias = new FieldAliasMapper(aliasName, aliasName, fieldName); |
| 73 | + |
| 74 | + FieldTypeLookup lookup = new FieldTypeLookup() |
| 75 | + .copyAndAddAll("type", singletonList(mapper), singletonList(alias)); |
| 76 | + assertEquals(mapper.fieldType(), lookup.get(aliasName)); |
| 77 | + |
| 78 | + String objectKey = "key1.key2"; |
| 79 | + String searchFieldName = aliasName + "." + objectKey; |
| 80 | + |
| 81 | + MappedFieldType searchFieldType = lookup.get(searchFieldName); |
| 82 | + assertEquals(mapper.keyedFieldName(), searchFieldType.name()); |
| 83 | + assertThat(searchFieldType, instanceOf(KeyedFlatObjectFieldType.class)); |
| 84 | + |
| 85 | + KeyedFlatObjectFieldType keyedFieldType = (KeyedFlatObjectFieldType) searchFieldType; |
| 86 | + assertEquals(objectKey, keyedFieldType.key()); |
| 87 | + } |
| 88 | + |
| 89 | + public void testFieldTypeLookupWithMultipleFields() { |
| 90 | + String field1 = "object1.object2.field"; |
| 91 | + String field2 = "object1.field"; |
| 92 | + String field3 = "object2.field"; |
| 93 | + |
| 94 | + FlatObjectFieldMapper mapper1 = createFlatObjectMapper(field1); |
| 95 | + FlatObjectFieldMapper mapper2 = createFlatObjectMapper(field2); |
| 96 | + FlatObjectFieldMapper mapper3 = createFlatObjectMapper(field3); |
| 97 | + |
| 98 | + FieldTypeLookup lookup = new FieldTypeLookup() |
| 99 | + .copyAndAddAll("type", Arrays.asList(mapper1, mapper2), emptyList()); |
| 100 | + assertNotNull(lookup.get(field1 + ".some.key")); |
| 101 | + assertNotNull(lookup.get(field2 + ".some.key")); |
| 102 | + |
| 103 | + lookup = lookup.copyAndAddAll("type", singletonList(mapper3), emptyList()); |
| 104 | + assertNotNull(lookup.get(field1 + ".some.key")); |
| 105 | + assertNotNull(lookup.get(field2 + ".some.key")); |
| 106 | + assertNotNull(lookup.get(field3 + ".some.key")); |
| 107 | + } |
| 108 | + |
| 109 | + public void testMaxDynamicKeyDepth() { |
| 110 | + FieldTypeLookup lookup = new FieldTypeLookup(); |
| 111 | + assertEquals(0, lookup.maxKeyedLookupDepth()); |
| 112 | + |
| 113 | + // Add a flattened object field. |
| 114 | + String flatObjectName = "object1.object2.field"; |
| 115 | + FlatObjectFieldMapper flatObjectField = createFlatObjectMapper(flatObjectName); |
| 116 | + lookup = lookup.copyAndAddAll("type", singletonList(flatObjectField), emptyList()); |
| 117 | + assertEquals(3, lookup.maxKeyedLookupDepth()); |
| 118 | + |
| 119 | + // Add a short alias to that field. |
| 120 | + String aliasName = "alias"; |
| 121 | + FieldAliasMapper alias = new FieldAliasMapper(aliasName, aliasName, flatObjectName); |
| 122 | + lookup = lookup.copyAndAddAll("type", emptyList(), singletonList(alias)); |
| 123 | + assertEquals(3, lookup.maxKeyedLookupDepth()); |
| 124 | + |
| 125 | + // Add a longer alias to that field. |
| 126 | + String longAliasName = "object1.object2.object3.alias"; |
| 127 | + FieldAliasMapper longAlias = new FieldAliasMapper(longAliasName, longAliasName, flatObjectName); |
| 128 | + lookup = lookup.copyAndAddAll("type", emptyList(), singletonList(longAlias)); |
| 129 | + assertEquals(4, lookup.maxKeyedLookupDepth()); |
| 130 | + |
| 131 | + // Update the long alias to refer to a non-flattened object field. |
| 132 | + String fieldName = "field"; |
| 133 | + MockFieldMapper field = new MockFieldMapper(fieldName); |
| 134 | + longAlias = new FieldAliasMapper(longAliasName, longAliasName, fieldName); |
| 135 | + lookup = lookup.copyAndAddAll("type", singletonList(field), singletonList(longAlias)); |
| 136 | + assertEquals(3, lookup.maxKeyedLookupDepth()); |
| 137 | + } |
| 138 | + |
| 139 | + public void testFieldLookupIterator() { |
| 140 | + MockFieldMapper mapper = new MockFieldMapper("foo"); |
| 141 | + FlatObjectFieldMapper flatObjectMapper = createFlatObjectMapper("object1.object2.field"); |
| 142 | + |
| 143 | + FieldTypeLookup lookup = new FieldTypeLookup() |
| 144 | + .copyAndAddAll("type", Arrays.asList(mapper, flatObjectMapper), emptyList()); |
| 145 | + |
| 146 | + Set<String> fieldNames = new HashSet<>(); |
| 147 | + for (MappedFieldType fieldType : lookup) { |
| 148 | + fieldNames.add(fieldType.name()); |
| 149 | + } |
| 150 | + |
| 151 | + assertThat(fieldNames, containsInAnyOrder( |
| 152 | + mapper.name(), flatObjectMapper.name(), flatObjectMapper.keyedFieldName())); |
| 153 | + } |
| 154 | + |
| 155 | + private FlatObjectFieldMapper createFlatObjectMapper(String fieldName) { |
| 156 | + Settings settings = Settings.builder() |
| 157 | + .put("index.version.created", Version.CURRENT) |
| 158 | + .build(); |
| 159 | + Mapper.BuilderContext context = new Mapper.BuilderContext(settings, new ContentPath()); |
| 160 | + return new FlatObjectFieldMapper.Builder(fieldName).build(context); |
| 161 | + } |
| 162 | + |
| 163 | + public void testScriptDocValuesLookup() { |
| 164 | + MapperService mapperService = mock(MapperService.class); |
| 165 | + |
| 166 | + ScriptDocValues<?> docValues1 = mock(ScriptDocValues.class); |
| 167 | + IndexFieldData<?> fieldData1 = createFieldData(docValues1); |
| 168 | + |
| 169 | + ScriptDocValues<?> docValues2 = mock(ScriptDocValues.class); |
| 170 | + IndexFieldData<?> fieldData2 = createFieldData(docValues2); |
| 171 | + |
| 172 | + KeyedFlatObjectFieldType fieldType1 = new KeyedFlatObjectFieldType("key1"); |
| 173 | + when(mapperService.fullName("json.key1")).thenReturn(fieldType1); |
| 174 | + |
| 175 | + KeyedFlatObjectFieldType fieldType2 = new KeyedFlatObjectFieldType( "key2"); |
| 176 | + when(mapperService.fullName("json.key2")).thenReturn(fieldType2); |
| 177 | + |
| 178 | + Function<MappedFieldType, IndexFieldData<?>> fieldDataSupplier = fieldType -> { |
| 179 | + KeyedFlatObjectFieldType keyedFieldType = (KeyedFlatObjectFieldType) fieldType; |
| 180 | + return keyedFieldType.key().equals("key1") ? fieldData1 : fieldData2; |
| 181 | + }; |
| 182 | + |
| 183 | + SearchLookup searchLookup = new SearchLookup(mapperService, fieldDataSupplier); |
| 184 | + LeafDocLookup docLookup = searchLookup.doc().getLeafDocLookup(null); |
| 185 | + |
| 186 | + assertEquals(docValues1, docLookup.get("json.key1")); |
| 187 | + assertEquals(docValues2, docLookup.get("json.key2")); |
| 188 | + } |
| 189 | + |
| 190 | + private IndexFieldData<?> createFieldData(ScriptDocValues<?> scriptDocValues) { |
| 191 | + AtomicFieldData atomicFieldData = mock(AtomicFieldData.class); |
| 192 | + doReturn(scriptDocValues).when(atomicFieldData).getScriptValues(); |
| 193 | + |
| 194 | + IndexFieldData<?> fieldData = mock(IndexFieldData.class); |
| 195 | + when(fieldData.getFieldName()).thenReturn("field"); |
| 196 | + doReturn(atomicFieldData).when(fieldData).load(anyObject()); |
| 197 | + |
| 198 | + return fieldData; |
| 199 | + } |
| 200 | +} |
0 commit comments