Skip to content

Commit 4cb4303

Browse files
committed
Code refactor to split classes
1 parent 848cf49 commit 4cb4303

File tree

5 files changed

+353
-257
lines changed

5 files changed

+353
-257
lines changed

server/src/main/java/org/opensearch/index/mapper/DerivedFieldMapper.java

Lines changed: 4 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,15 @@
88

99
package org.opensearch.index.mapper;
1010

11-
import org.apache.lucene.document.DoubleField;
12-
import org.apache.lucene.document.Field;
1311
import org.apache.lucene.document.FieldType;
14-
import org.apache.lucene.document.KeywordField;
15-
import org.apache.lucene.document.LongField;
1612
import org.apache.lucene.index.IndexOptions;
1713
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;
2514
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;
2915
import org.opensearch.script.Script;
30-
import org.opensearch.search.lookup.SearchLookup;
31-
import org.opensearch.search.lookup.SourceLookup;
3216

3317
import java.io.IOException;
34-
import java.time.ZoneId;
3518
import java.util.Arrays;
36-
import java.util.Collections;
3719
import java.util.List;
38-
import java.util.Map;
3920
import java.util.function.Function;
4021

4122
/**
@@ -94,216 +75,23 @@ public Builder(String name) {
9475
super(name);
9576
}
9677

97-
9878
@Override
9979
protected List<Parameter<?>> getParameters() {
10080
return Arrays.asList(type, script);
10181
}
10282

10383
@Override
10484
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);
14389
return new DerivedFieldMapper(name, ft, multiFieldsBuilder.build(this, context), copyTo.build(), this);
14490
}
14591
}
14692

147-
14893
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-
30594
private final String type;
306-
30795
private final Script script;
30896

30997
protected DerivedFieldMapper(
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.index.mapper;
10+
11+
import org.apache.lucene.document.DoubleField;
12+
import org.apache.lucene.document.Field;
13+
import org.apache.lucene.document.FieldType;
14+
import org.apache.lucene.document.KeywordField;
15+
import org.apache.lucene.document.LongField;
16+
import org.apache.lucene.index.IndexOptions;
17+
import org.apache.lucene.index.IndexableField;
18+
import org.opensearch.common.lucene.Lucene;
19+
20+
import java.util.Arrays;
21+
import java.util.Map;
22+
import java.util.function.BiFunction;
23+
import java.util.function.Function;
24+
import java.util.stream.Collectors;
25+
26+
public enum DerivedFieldSupportedTypes {
27+
KEYWORD (
28+
"keyword",
29+
(name, context) -> {
30+
FieldType dummyFieldType = new FieldType();
31+
dummyFieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
32+
KeywordFieldMapper.Builder keywordBuilder = new KeywordFieldMapper.Builder(name);
33+
KeywordFieldMapper.KeywordFieldType keywordFieldType = keywordBuilder.buildFieldType(context, dummyFieldType);
34+
keywordFieldType.setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
35+
return new KeywordFieldMapper(
36+
name, dummyFieldType, keywordFieldType,
37+
keywordBuilder.multiFieldsBuilder.build(keywordBuilder, context),
38+
keywordBuilder.copyTo.build(),
39+
keywordBuilder
40+
);
41+
},
42+
name -> o -> new KeywordField(name, (String) o, Field.Store.NO)
43+
),
44+
LONG (
45+
"long",
46+
(name, context) -> {
47+
NumberFieldMapper.Builder longBuilder = new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.LONG, false, false);
48+
return longBuilder.build(context);
49+
},
50+
name -> o -> new LongField(name, Long.parseLong(o.toString()), Field.Store.NO)
51+
),
52+
DOUBLE (
53+
"double",
54+
(name, context) -> {
55+
NumberFieldMapper.Builder doubleBuilder = new NumberFieldMapper.Builder(name, NumberFieldMapper.NumberType.DOUBLE, false, false);
56+
return doubleBuilder.build(context);
57+
},
58+
name -> o -> new DoubleField(name, Double.parseDouble(o.toString()), Field.Store.NO)
59+
);
60+
// TODO: add logic all supported type in derived fields
61+
// TODO: should we support mapping settings exposed by a given field type from derived fields too?
62+
// for example, support `format` for date type?
63+
final String name;
64+
private final BiFunction<String, Mapper.BuilderContext, FieldMapper> builder;
65+
66+
private final Function<String, Function<Object, IndexableField>> indexableFieldBuilder;
67+
68+
DerivedFieldSupportedTypes(String name, BiFunction<String, Mapper.BuilderContext, FieldMapper> builder,
69+
Function<String, Function<Object, IndexableField>> indexableFieldBuilder){
70+
this.name = name;
71+
this.builder = builder;
72+
this.indexableFieldBuilder = indexableFieldBuilder;
73+
}
74+
75+
public String getName() {
76+
return name;
77+
}
78+
private FieldMapper getFieldMapper(String name, Mapper.BuilderContext context) {
79+
return builder.apply(name, context);
80+
}
81+
82+
private Function<Object, IndexableField> getIndexableFieldGenerator(String name) {
83+
return indexableFieldBuilder.apply(name);
84+
}
85+
private static final Map<String, DerivedFieldSupportedTypes> enumMap = Arrays.stream(DerivedFieldSupportedTypes.values())
86+
.collect(Collectors.toMap(DerivedFieldSupportedTypes::getName, enumValue -> enumValue));
87+
88+
public static FieldMapper getFieldMapperFromType(String type, String name, Mapper.BuilderContext context) {
89+
if (!enumMap.containsKey(type)) {
90+
throw new IllegalArgumentException("Type [" + type + "] isn't supported in Derived field context.");
91+
}
92+
return enumMap.get(type).getFieldMapper(name, context);
93+
}
94+
95+
public static Function<Object, IndexableField> getIndexableFieldGeneratorType(String type, String name) {
96+
if (!enumMap.containsKey(type)) {
97+
throw new IllegalArgumentException("Type [" + type + "] isn't supported in Derived field context.");
98+
}
99+
return enumMap.get(type).getIndexableFieldGenerator(name);
100+
}
101+
}

0 commit comments

Comments
 (0)