Skip to content

Commit a586a62

Browse files
authored
Add FilterFieldType (#17627)
This class allows developers (in core or plugins) to wrap an existing field type, delegating all behavior by default, overriding specific methods as needed. --------- Signed-off-by: Michael Froh <froh@amazon.com>
1 parent a64bfdb commit a586a62

File tree

4 files changed

+390
-0
lines changed

4 files changed

+390
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1212
- Fix systemd integTest on deb regarding path ownership check ([#17641](https://github.com/opensearch-project/OpenSearch/pull/17641))
1313
- Add dfs transformation function in XContentMapValues ([#17612](https://github.com/opensearch-project/OpenSearch/pull/17612))
1414
- Added Kinesis support as a plugin for the pull-based ingestion ([#17615](https://github.com/opensearch-project/OpenSearch/pull/17615))
15+
- Add FilterFieldType for developers who want to wrap MappedFieldType ([#17627](https://github.com/opensearch-project/OpenSearch/pull/17627))
1516
- [Security Manager Replacement] Create initial Java Agent to intercept Socket::connect calls ([#17724](https://github.com/opensearch-project/OpenSearch/pull/17724))
1617
- Add ingestion management APIs for pause, resume and get ingestion state ([#17631](https://github.com/opensearch-project/OpenSearch/pull/17631))
1718
- [Security Manager Replacement] Enhance Java Agent to intercept System::exit ([#17746](https://github.com/opensearch-project/OpenSearch/pull/17746))
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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.opensearch.test.OpenSearchTestCase;
12+
13+
import java.lang.reflect.Method;
14+
import java.lang.reflect.Modifier;
15+
import java.util.Arrays;
16+
import java.util.HashSet;
17+
import java.util.Objects;
18+
import java.util.Set;
19+
20+
public class FilterFieldTypeTest extends OpenSearchTestCase {
21+
22+
private static final class MethodSignature {
23+
private final String name;
24+
private final Class<?> returnType;
25+
private final Class<?>[] parameterTypes;
26+
27+
public MethodSignature(String name, Class<?> returnType, Class<?>[] parameterTypes) {
28+
this.name = name;
29+
this.returnType = returnType;
30+
this.parameterTypes = parameterTypes;
31+
}
32+
33+
@Override
34+
public boolean equals(Object o) {
35+
if (o == null || getClass() != o.getClass()) return false;
36+
MethodSignature that = (MethodSignature) o;
37+
return Objects.equals(name, that.name)
38+
&& Objects.equals(returnType, that.returnType)
39+
&& Objects.deepEquals(parameterTypes, that.parameterTypes);
40+
}
41+
42+
@Override
43+
public int hashCode() {
44+
return Objects.hash(name, returnType, Arrays.hashCode(parameterTypes));
45+
}
46+
}
47+
48+
private static final Set<MethodSignature> EXCLUDED_SIGNATURES = Set.of(new MethodSignature("typeName", String.class, new Class<?>[0]));
49+
50+
public void testAllMethodsDelegated() {
51+
Method[] mappedFieldTypeMethods = MappedFieldType.class.getMethods();
52+
Method[] filterFieldTypeMethods = FilterFieldType.class.getMethods();
53+
54+
Set<MethodSignature> mappedFieldTypeMethodSignatures = new HashSet<>();
55+
for (Method method : mappedFieldTypeMethods) {
56+
if (method.getDeclaringClass() == MappedFieldType.class
57+
&& Modifier.isFinal(method.getModifiers()) == false
58+
&& Modifier.isStatic(method.getModifiers()) == false) {
59+
mappedFieldTypeMethodSignatures.add(
60+
new MethodSignature(method.getName(), method.getReturnType(), method.getParameterTypes())
61+
);
62+
}
63+
}
64+
65+
Set<MethodSignature> filterFieldTypeMethodSignatures = new HashSet<>();
66+
for (Method method : filterFieldTypeMethods) {
67+
if (method.getDeclaringClass() == FilterFieldType.class) {
68+
filterFieldTypeMethodSignatures.add(
69+
new MethodSignature(method.getName(), method.getReturnType(), method.getParameterTypes())
70+
);
71+
}
72+
}
73+
for (MethodSignature methodSignature : mappedFieldTypeMethodSignatures) {
74+
if (filterFieldTypeMethodSignatures.contains(methodSignature)) {
75+
assertFalse(
76+
"Method " + methodSignature.name + " should NOT be implemented in " + FilterFieldType.class.getSimpleName(),
77+
EXCLUDED_SIGNATURES.contains(methodSignature)
78+
);
79+
} else {
80+
assertTrue(
81+
"Method " + methodSignature.name + " should be implemented in " + FilterFieldType.class.getSimpleName(),
82+
EXCLUDED_SIGNATURES.contains(methodSignature)
83+
);
84+
}
85+
}
86+
}
87+
88+
}
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
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.analysis.TokenStream;
12+
import org.apache.lucene.index.IndexReader;
13+
import org.apache.lucene.queries.intervals.IntervalsSource;
14+
import org.apache.lucene.queries.spans.SpanMultiTermQueryWrapper;
15+
import org.apache.lucene.queries.spans.SpanQuery;
16+
import org.apache.lucene.search.MultiTermQuery;
17+
import org.apache.lucene.search.Query;
18+
import org.opensearch.common.annotation.PublicApi;
19+
import org.opensearch.common.geo.ShapeRelation;
20+
import org.opensearch.common.time.DateMathParser;
21+
import org.opensearch.common.unit.Fuzziness;
22+
import org.opensearch.index.analysis.NamedAnalyzer;
23+
import org.opensearch.index.fielddata.IndexFieldData;
24+
import org.opensearch.index.query.IntervalMode;
25+
import org.opensearch.index.query.QueryRewriteContext;
26+
import org.opensearch.index.query.QueryShardContext;
27+
import org.opensearch.search.DocValueFormat;
28+
import org.opensearch.search.lookup.SearchLookup;
29+
30+
import java.io.IOException;
31+
import java.time.ZoneId;
32+
import java.util.List;
33+
import java.util.Map;
34+
import java.util.function.Function;
35+
import java.util.function.Supplier;
36+
37+
/**
38+
* Wraps a {@link MappedFieldType}, delegating all methods (except typeName).
39+
* <p>
40+
* Subclasses can extend this class to wrap an existing {@link MappedFieldType} to reuse most functionality, while
41+
* customizing/modifying some specific behavior by overriding the relevant methods.
42+
*/
43+
@PublicApi(since = "3.0.0")
44+
public abstract class FilterFieldType extends MappedFieldType {
45+
protected final MappedFieldType delegate;
46+
47+
public FilterFieldType(MappedFieldType delegate) {
48+
super(
49+
delegate.name(),
50+
delegate.isSearchable(),
51+
delegate.isStored(),
52+
delegate.hasDocValues(),
53+
delegate.getTextSearchInfo(),
54+
delegate.meta()
55+
);
56+
this.delegate = delegate;
57+
}
58+
59+
@Override
60+
public ValueFetcher valueFetcher(QueryShardContext context, SearchLookup searchLookup, String format) {
61+
return delegate.valueFetcher(context, searchLookup, format);
62+
}
63+
64+
@Override
65+
public Query termQuery(Object value, QueryShardContext context) {
66+
return delegate.termQuery(value, context);
67+
}
68+
69+
@Override
70+
public String familyTypeName() {
71+
return delegate.familyTypeName();
72+
}
73+
74+
@Override
75+
public String name() {
76+
return delegate.name();
77+
}
78+
79+
@Override
80+
public float boost() {
81+
return delegate.boost();
82+
}
83+
84+
@Override
85+
public void setBoost(float boost) {
86+
delegate.setBoost(boost);
87+
}
88+
89+
@Override
90+
public boolean hasDocValues() {
91+
return delegate.hasDocValues();
92+
}
93+
94+
@Override
95+
public NamedAnalyzer indexAnalyzer() {
96+
return delegate.indexAnalyzer();
97+
}
98+
99+
@Override
100+
public void setIndexAnalyzer(NamedAnalyzer analyzer) {
101+
delegate.setIndexAnalyzer(analyzer);
102+
}
103+
104+
@Override
105+
public Object valueForDisplay(Object value) {
106+
return delegate.valueForDisplay(value);
107+
}
108+
109+
@Override
110+
public boolean isSearchable() {
111+
return delegate.isSearchable();
112+
}
113+
114+
@Override
115+
public boolean isStored() {
116+
return delegate.isStored();
117+
}
118+
119+
@Override
120+
public Function<byte[], Number> pointReaderIfPossible() {
121+
return delegate.pointReaderIfPossible();
122+
}
123+
124+
@Override
125+
public boolean isAggregatable() {
126+
return delegate.isAggregatable();
127+
}
128+
129+
@Override
130+
public Query termQueryCaseInsensitive(Object value, QueryShardContext context) {
131+
return delegate.termQueryCaseInsensitive(value, context);
132+
}
133+
134+
@Override
135+
public Query termsQuery(List<?> values, QueryShardContext context) {
136+
return delegate.termsQuery(values, context);
137+
}
138+
139+
@Override
140+
public Query rangeQuery(
141+
Object lowerTerm,
142+
Object upperTerm,
143+
boolean includeLower,
144+
boolean includeUpper,
145+
ShapeRelation relation,
146+
ZoneId timeZone,
147+
DateMathParser parser,
148+
QueryShardContext context
149+
) {
150+
return delegate.rangeQuery(lowerTerm, upperTerm, includeLower, includeUpper, relation, timeZone, parser, context);
151+
}
152+
153+
@Override
154+
public Query fuzzyQuery(
155+
Object value,
156+
Fuzziness fuzziness,
157+
int prefixLength,
158+
int maxExpansions,
159+
boolean transpositions,
160+
MultiTermQuery.RewriteMethod method,
161+
QueryShardContext context
162+
) {
163+
return delegate.fuzzyQuery(value, fuzziness, prefixLength, maxExpansions, transpositions, method, context);
164+
}
165+
166+
@Override
167+
public Query prefixQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitve, QueryShardContext context) {
168+
return delegate.prefixQuery(value, method, caseInsensitve, context);
169+
}
170+
171+
@Override
172+
public Query wildcardQuery(String value, MultiTermQuery.RewriteMethod method, boolean caseInsensitve, QueryShardContext context) {
173+
return delegate.wildcardQuery(value, method, caseInsensitve, context);
174+
}
175+
176+
@Override
177+
public Query normalizedWildcardQuery(String value, MultiTermQuery.RewriteMethod method, QueryShardContext context) {
178+
return delegate.normalizedWildcardQuery(value, method, context);
179+
}
180+
181+
@Override
182+
public Query regexpQuery(
183+
String value,
184+
int syntaxFlags,
185+
int matchFlags,
186+
int maxDeterminizedStates,
187+
MultiTermQuery.RewriteMethod method,
188+
QueryShardContext context
189+
) {
190+
return delegate.regexpQuery(value, syntaxFlags, matchFlags, maxDeterminizedStates, method, context);
191+
}
192+
193+
@Override
194+
public Query existsQuery(QueryShardContext context) {
195+
return delegate.existsQuery(context);
196+
}
197+
198+
@Override
199+
public Query phraseQuery(TokenStream stream, int slop, boolean enablePositionIncrements) throws IOException {
200+
return delegate.phraseQuery(stream, slop, enablePositionIncrements);
201+
}
202+
203+
@Override
204+
public Query phraseQuery(TokenStream stream, int slop, boolean enablePositionIncrements, QueryShardContext context) throws IOException {
205+
return delegate.phraseQuery(stream, slop, enablePositionIncrements, context);
206+
}
207+
208+
@Override
209+
public Query multiPhraseQuery(TokenStream stream, int slop, boolean enablePositionIncrements) throws IOException {
210+
return delegate.multiPhraseQuery(stream, slop, enablePositionIncrements);
211+
}
212+
213+
@Override
214+
public Query multiPhraseQuery(TokenStream stream, int slop, boolean enablePositionIncrements, QueryShardContext context)
215+
throws IOException {
216+
return delegate.multiPhraseQuery(stream, slop, enablePositionIncrements, context);
217+
}
218+
219+
@Override
220+
public Query phrasePrefixQuery(TokenStream stream, int slop, int maxExpansions) throws IOException {
221+
return delegate.phrasePrefixQuery(stream, slop, maxExpansions);
222+
}
223+
224+
@Override
225+
public Query phrasePrefixQuery(TokenStream stream, int slop, int maxExpansions, QueryShardContext context) throws IOException {
226+
return delegate.phrasePrefixQuery(stream, slop, maxExpansions, context);
227+
}
228+
229+
@Override
230+
public SpanQuery spanPrefixQuery(String value, SpanMultiTermQueryWrapper.SpanRewriteMethod method, QueryShardContext context) {
231+
return delegate.spanPrefixQuery(value, method, context);
232+
}
233+
234+
@Override
235+
public Query distanceFeatureQuery(Object origin, String pivot, float boost, QueryShardContext context) {
236+
return delegate.distanceFeatureQuery(origin, pivot, boost, context);
237+
}
238+
239+
@Override
240+
public IntervalsSource intervals(String query, int max_gaps, IntervalMode mode, NamedAnalyzer analyzer, boolean prefix)
241+
throws IOException {
242+
return delegate.intervals(query, max_gaps, mode, analyzer, prefix);
243+
}
244+
245+
@Override
246+
public Relation isFieldWithinQuery(
247+
IndexReader reader,
248+
Object from,
249+
Object to,
250+
boolean includeLower,
251+
boolean includeUpper,
252+
ZoneId timeZone,
253+
DateMathParser dateMathParser,
254+
QueryRewriteContext context
255+
) throws IOException {
256+
return delegate.isFieldWithinQuery(reader, from, to, includeLower, includeUpper, timeZone, dateMathParser, context);
257+
}
258+
259+
@Override
260+
public boolean eagerGlobalOrdinals() {
261+
return delegate.eagerGlobalOrdinals();
262+
}
263+
264+
@Override
265+
public void setEagerGlobalOrdinals(boolean eagerGlobalOrdinals) {
266+
delegate.setEagerGlobalOrdinals(eagerGlobalOrdinals);
267+
}
268+
269+
@Override
270+
public DocValueFormat docValueFormat(String format, ZoneId timeZone) {
271+
return delegate.docValueFormat(format, timeZone);
272+
}
273+
274+
@Override
275+
public Map<String, String> meta() {
276+
return delegate.meta();
277+
}
278+
279+
@Override
280+
public TextSearchInfo getTextSearchInfo() {
281+
return delegate.getTextSearchInfo();
282+
}
283+
284+
@Override
285+
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
286+
return delegate.fielddataBuilder(fullyQualifiedIndexName, searchLookup);
287+
}
288+
289+
@Override
290+
public MappedFieldType unwrap() {
291+
return delegate.unwrap();
292+
}
293+
}

0 commit comments

Comments
 (0)