|
8 | 8 |
|
9 | 9 | package org.opensearch.index.mapper; |
10 | 10 |
|
11 | | -import org.apache.lucene.document.DoubleField; |
12 | | -import org.apache.lucene.document.Field; |
13 | 11 | import org.apache.lucene.document.FieldType; |
14 | | -import org.apache.lucene.document.KeywordField; |
15 | | -import org.apache.lucene.document.LongField; |
16 | 12 | import org.apache.lucene.index.IndexOptions; |
17 | 13 | import org.apache.lucene.index.IndexableField; |
18 | | -import org.apache.lucene.index.LeafReaderContext; |
19 | | -import org.apache.lucene.search.MultiTermQuery; |
20 | | -import org.apache.lucene.search.Query; |
21 | | -import org.opensearch.common.Nullable; |
22 | | -import org.opensearch.common.geo.ShapeRelation; |
23 | | -import org.opensearch.common.lucene.Lucene; |
24 | | -import org.opensearch.common.time.DateMathParser; |
25 | 14 | import org.opensearch.core.xcontent.XContentBuilder; |
26 | | -import org.opensearch.index.query.DerivedFieldQuery; |
27 | | -import org.opensearch.index.query.DerivedFieldScript; |
28 | | -import org.opensearch.index.query.QueryShardContext; |
29 | 15 | import org.opensearch.script.Script; |
30 | | -import org.opensearch.search.lookup.SearchLookup; |
31 | | -import org.opensearch.search.lookup.SourceLookup; |
32 | 16 |
|
33 | 17 | import java.io.IOException; |
34 | | -import java.time.ZoneId; |
35 | 18 | import java.util.Arrays; |
36 | | -import java.util.Collections; |
37 | 19 | import java.util.List; |
38 | | -import java.util.Map; |
39 | 20 | import java.util.function.Function; |
40 | 21 |
|
41 | 22 | /** |
@@ -94,216 +75,23 @@ public Builder(String name) { |
94 | 75 | super(name); |
95 | 76 | } |
96 | 77 |
|
97 | | - |
98 | 78 | @Override |
99 | 79 | protected List<Parameter<?>> getParameters() { |
100 | 80 | return Arrays.asList(type, script); |
101 | 81 | } |
102 | 82 |
|
103 | 83 | @Override |
104 | 84 | public DerivedFieldMapper build(BuilderContext context) { |
105 | | - FieldMapper typeFieldMapper; |
106 | | - Function<Object, IndexableField> fieldFunction; |
107 | | - switch (type.getValue()) { |
108 | | - // TODO: add logic all supported type in derived fields |
109 | | - // TODO: should we support mapping settings exposed by a given field type from derived fields too? |
110 | | - // for example, support `format` for date type? |
111 | | - case KeywordFieldMapper.CONTENT_TYPE: |
112 | | - FieldType dummyFieldType = new FieldType(); |
113 | | - dummyFieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS); |
114 | | - KeywordFieldMapper.Builder keywordBuilder = new KeywordFieldMapper.Builder(name()); |
115 | | - KeywordFieldMapper.KeywordFieldType keywordFieldType = keywordBuilder.buildFieldType(context, dummyFieldType); |
116 | | - keywordFieldType.setIndexAnalyzer(Lucene.KEYWORD_ANALYZER); |
117 | | - typeFieldMapper = new KeywordFieldMapper( |
118 | | - name(), dummyFieldType, keywordFieldType, |
119 | | - keywordBuilder.multiFieldsBuilder.build(this, context), |
120 | | - keywordBuilder.copyTo.build(), |
121 | | - keywordBuilder |
122 | | - ); |
123 | | - fieldFunction = o -> new KeywordField(name(), (String) o, Field.Store.NO); |
124 | | - break; |
125 | | - case "long": |
126 | | - // ignoreMalformed? |
127 | | - NumberFieldMapper.Builder longBuilder = new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.LONG, false, false); |
128 | | - typeFieldMapper = longBuilder.build(context); |
129 | | - fieldFunction = o -> new LongField(name(), Long.parseLong(o.toString()), Field.Store.NO); |
130 | | - break; |
131 | | - case "double": |
132 | | - // ignoreMalformed? |
133 | | - NumberFieldMapper.Builder doubleBuilder = new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.DOUBLE, false, false); |
134 | | - typeFieldMapper = doubleBuilder.build(context); |
135 | | - fieldFunction = o -> new DoubleField(name(), Double.parseDouble(o.toString()), Field.Store.NO); |
136 | | - break; |
137 | | - default: |
138 | | - throw new IllegalArgumentException("Field [" + name() + "] of type [" + type + "] isn't supported " + |
139 | | - "in Derived field context."); |
140 | | - |
141 | | - } |
142 | | - MappedFieldType ft = new DerivedFieldType(buildFullName(context), type.getValue(), script.getValue(), typeFieldMapper, fieldFunction); |
| 85 | + FieldMapper fieldMapper = DerivedFieldSupportedTypes.getFieldMapperFromType(type.getValue(), name, context); |
| 86 | + Function<Object, IndexableField> fieldFunction = |
| 87 | + DerivedFieldSupportedTypes.getIndexableFieldGeneratorType(type.getValue(), name); |
| 88 | + DerivedFieldType ft = new DerivedFieldType(buildFullName(context), type.getValue(), script.getValue(), fieldMapper, fieldFunction); |
143 | 89 | return new DerivedFieldMapper(name, ft, multiFieldsBuilder.build(this, context), copyTo.build(), this); |
144 | 90 | } |
145 | 91 | } |
146 | 92 |
|
147 | | - |
148 | 93 | public static final TypeParser PARSER = new TypeParser((n, c) -> new Builder(n)); |
149 | | - |
150 | | - /** |
151 | | - * Field type for derived field mapper |
152 | | - * |
153 | | - * @opensearch.internal |
154 | | - */ |
155 | | - public static final class DerivedFieldType extends MappedFieldType { |
156 | | - private final String type; |
157 | | - |
158 | | - private final Script script; |
159 | | - |
160 | | - FieldMapper typeFieldMapper; |
161 | | - |
162 | | - private final Function<Object, IndexableField> fieldFunction; |
163 | | - |
164 | | - public DerivedFieldType( |
165 | | - String name, |
166 | | - String type, |
167 | | - Script script, |
168 | | - boolean isIndexed, |
169 | | - boolean isStored, |
170 | | - boolean hasDocValues, |
171 | | - Map<String, String> meta, |
172 | | - FieldMapper typeFieldMapper, |
173 | | - Function<Object, IndexableField> fieldFunction |
174 | | - ) { |
175 | | - super(name, isIndexed, isStored, hasDocValues, typeFieldMapper.fieldType().getTextSearchInfo(), meta); |
176 | | - this.type = type; |
177 | | - this.script = script; |
178 | | - this.typeFieldMapper = typeFieldMapper; |
179 | | - this.fieldFunction = fieldFunction; |
180 | | - } |
181 | | - |
182 | | - public DerivedFieldType(String name, String type, Script script, FieldMapper typeFieldMapper, Function<Object, IndexableField> fieldFunction) { |
183 | | - this(name, type, script, false, false, false, Collections.emptyMap(), typeFieldMapper, fieldFunction); |
184 | | - } |
185 | | - |
186 | | - @Override |
187 | | - public String typeName() { |
188 | | - return CONTENT_TYPE; |
189 | | - } |
190 | | - |
191 | | - @Override |
192 | | - public ValueFetcher valueFetcher(QueryShardContext context, SearchLookup searchLookup, String format) { |
193 | | - if (format != null) { |
194 | | - throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support formats."); |
195 | | - } |
196 | | - DerivedFieldScript.Factory factory = context.compile(script, DerivedFieldScript.CONTEXT); |
197 | | - DerivedFieldScript.LeafFactory derivedFieldScriptFactory = factory.newFactory(script.getParams(), context.lookup()); |
198 | | - |
199 | | - return new SourceValueFetcher(name(), context) { |
200 | | - DerivedFieldScript derivedFieldScript; |
201 | | - |
202 | | - @Override |
203 | | - public List<Object> fetchValues(SourceLookup lookup) { |
204 | | - derivedFieldScript.setDocument(lookup.docId()); |
205 | | - // TODO: remove List.of() when derivedFieldScript.execute() returns list of objects. |
206 | | - return List.of(derivedFieldScript.execute()); |
207 | | - } |
208 | | - |
209 | | - @Override |
210 | | - protected Object parseSourceValue(Object value) { |
211 | | - return value; |
212 | | - } |
213 | | - |
214 | | - public void setNextReader(LeafReaderContext context) { |
215 | | - try { |
216 | | - derivedFieldScript = derivedFieldScriptFactory.newInstance(context); |
217 | | - } catch (IOException e) { |
218 | | - throw new RuntimeException(e); |
219 | | - } |
220 | | - } |
221 | | - }; |
222 | | - } |
223 | | - |
224 | | - @Override |
225 | | - public Query termQuery(Object value, @Nullable QueryShardContext context) { |
226 | | - Query query = typeFieldMapper.mappedFieldType.termQuery(value, context); |
227 | | - DerivedFieldScript.Factory factory = context.compile(script, DerivedFieldScript.CONTEXT); |
228 | | - DerivedFieldScript.LeafFactory derivedFieldScript = factory.newFactory(script.getParams(), context.lookup()); |
229 | | - return new DerivedFieldQuery(query, derivedFieldScript, typeFieldMapper.mappedFieldType.indexAnalyzer(), fieldFunction, context); |
230 | | - } |
231 | | - |
232 | | - @Override |
233 | | - public Query prefixQuery( |
234 | | - String value, |
235 | | - @Nullable MultiTermQuery.RewriteMethod method, |
236 | | - boolean caseInsensitive, |
237 | | - QueryShardContext context |
238 | | - ) { |
239 | | - Query query = typeFieldMapper.mappedFieldType.prefixQuery(value, method, caseInsensitive, context); |
240 | | - DerivedFieldScript.Factory factory = context.compile(script, DerivedFieldScript.CONTEXT); |
241 | | - DerivedFieldScript.LeafFactory derivedFieldScript = factory.newFactory(script.getParams(), context.lookup()); |
242 | | - return new DerivedFieldQuery(query, derivedFieldScript, typeFieldMapper.mappedFieldType.indexAnalyzer(), fieldFunction, context); |
243 | | - } |
244 | | - |
245 | | - @Override |
246 | | - public Query wildcardQuery( |
247 | | - String value, |
248 | | - @Nullable MultiTermQuery.RewriteMethod method, |
249 | | - boolean caseInsensitive, |
250 | | - QueryShardContext context |
251 | | - ) { |
252 | | - Query query = typeFieldMapper.mappedFieldType.wildcardQuery(value, method, caseInsensitive, context); |
253 | | - DerivedFieldScript.Factory factory = context.compile(script, DerivedFieldScript.CONTEXT); |
254 | | - DerivedFieldScript.LeafFactory derivedFieldScript = factory.newFactory(script.getParams(), context.lookup()); |
255 | | - return new DerivedFieldQuery(query, derivedFieldScript, typeFieldMapper.mappedFieldType.indexAnalyzer(), fieldFunction, context); |
256 | | - } |
257 | | - |
258 | | - @Override |
259 | | - public Query regexpQuery( |
260 | | - String value, |
261 | | - int syntaxFlags, |
262 | | - int matchFlags, |
263 | | - int maxDeterminizedStates, |
264 | | - @Nullable MultiTermQuery.RewriteMethod method, |
265 | | - QueryShardContext context |
266 | | - ) { |
267 | | - Query query = typeFieldMapper.mappedFieldType.regexpQuery(value, syntaxFlags, matchFlags, |
268 | | - maxDeterminizedStates, method, context); |
269 | | - DerivedFieldScript.Factory factory = context.compile(script, DerivedFieldScript.CONTEXT); |
270 | | - DerivedFieldScript.LeafFactory derivedFieldScript = factory.newFactory(script.getParams(), context.lookup()); |
271 | | - return new DerivedFieldQuery(query, derivedFieldScript, typeFieldMapper.mappedFieldType.indexAnalyzer(), fieldFunction, context); |
272 | | - } |
273 | | - |
274 | | - // TODO: Override all types of queries which can be supported by all types supported within derived fields. |
275 | | - @Override |
276 | | - public Query rangeQuery( |
277 | | - Object lowerTerm, |
278 | | - Object upperTerm, |
279 | | - boolean includeLower, |
280 | | - boolean includeUpper, |
281 | | - ShapeRelation relation, |
282 | | - ZoneId timeZone, |
283 | | - DateMathParser parser, |
284 | | - QueryShardContext context |
285 | | - ) { |
286 | | - Query query = typeFieldMapper.mappedFieldType.rangeQuery(lowerTerm, upperTerm, includeLower, includeUpper, |
287 | | - relation, timeZone, parser, context); |
288 | | - DerivedFieldScript.Factory factory = context.compile(script, DerivedFieldScript.CONTEXT); |
289 | | - DerivedFieldScript.LeafFactory derivedFieldScript = factory.newFactory(script.getParams(), context.lookup()); |
290 | | - return new DerivedFieldQuery(query, derivedFieldScript, typeFieldMapper.mappedFieldType.indexAnalyzer(), fieldFunction, context); |
291 | | - } |
292 | | - |
293 | | - @Override |
294 | | - public Query existsQuery(QueryShardContext context) { |
295 | | - throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] does not support exist queries"); |
296 | | - } |
297 | | - |
298 | | - @Override |
299 | | - public boolean isAggregatable() { |
300 | | - return false; |
301 | | - } |
302 | | - } |
303 | | - |
304 | | - |
305 | 94 | private final String type; |
306 | | - |
307 | 95 | private final Script script; |
308 | 96 |
|
309 | 97 | protected DerivedFieldMapper( |
|
0 commit comments