7
7
*/
8
8
package org .elasticsearch .index .mapper ;
9
9
10
- import org .apache .lucene .index .IndexableField ;
11
10
import org .apache .lucene .search .Query ;
11
+ import org .apache .lucene .util .SetOnce ;
12
+ import org .elasticsearch .common .CheckedConsumer ;
12
13
import org .elasticsearch .common .Explicit ;
13
14
import org .elasticsearch .common .geo .GeoJsonGeometryFormat ;
14
- import org .elasticsearch .common .xcontent .LoggingDeprecationHandler ;
15
- import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
16
15
import org .elasticsearch .common .xcontent .XContentParser ;
17
- import org .elasticsearch .common .xcontent .XContentType ;
18
16
import org .elasticsearch .common .xcontent .support .MapXContentParser ;
19
17
import org .elasticsearch .index .analysis .NamedAnalyzer ;
20
18
import org .elasticsearch .index .query .SearchExecutionContext ;
21
19
22
20
import java .io .IOException ;
23
21
import java .io .UncheckedIOException ;
24
- import java .text .ParseException ;
25
22
import java .util .ArrayList ;
26
23
import java .util .Collections ;
27
24
import java .util .List ;
28
25
import java .util .Map ;
26
+ import java .util .function .Consumer ;
29
27
import java .util .function .Function ;
30
28
31
29
/**
32
30
* Base field mapper class for all spatial field types
33
31
*/
34
- public abstract class AbstractGeometryFieldMapper <Parsed , Processed > extends FieldMapper {
32
+ public abstract class AbstractGeometryFieldMapper <T > extends FieldMapper {
35
33
36
34
public static Parameter <Explicit <Boolean >> ignoreMalformedParam (Function <FieldMapper , Explicit <Boolean >> initializer ,
37
35
boolean ignoreMalformedByDefault ) {
@@ -42,52 +40,33 @@ public static Parameter<Explicit<Boolean>> ignoreZValueParam(Function<FieldMappe
42
40
return Parameter .explicitBoolParam ("ignore_z_value" , true , initializer , true );
43
41
}
44
42
45
- /**
46
- * Interface representing an preprocessor in geometry indexing pipeline
47
- */
48
- public interface Indexer <Parsed , Processed > {
49
- Processed prepareForIndexing (Parsed geometry );
50
- Class <Processed > processedClass ();
51
- List <IndexableField > indexShape (ParseContext context , Processed shape );
52
- }
53
-
54
43
/**
55
44
* Interface representing parser in geometry indexing pipeline.
56
45
*/
57
- public abstract static class Parser <Parsed > {
46
+ public abstract static class Parser <T > {
58
47
/**
59
- * Parse the given xContent value to an object of type {@link Parsed }. The value can be
48
+ * Parse the given xContent value to one or more objects of type {@link T }. The value can be
60
49
* in any supported format.
61
50
*/
62
- public abstract Parsed parse (XContentParser parser ) throws IOException , ParseException ;
51
+ public abstract void parse (
52
+ XContentParser parser ,
53
+ CheckedConsumer <T , IOException > consumer ,
54
+ Consumer <Exception > onMalformed ) throws IOException ;
63
55
64
56
/**
65
57
* Given a parsed value and a format string, formats the value into a plain Java object.
66
58
*
67
59
* Supported formats include 'geojson' and 'wkt'. The different formats are defined
68
60
* as subclasses of {@link org.elasticsearch.common.geo.GeometryFormat}.
69
61
*/
70
- public abstract Object format (Parsed value , String format );
62
+ public abstract Object format (T value , String format );
71
63
72
- /**
73
- * Parses the given value, then formats it according to the 'format' string.
74
- *
75
- * Used by value fetchers to validate and format geo objects
76
- */
77
- public Object parseAndFormatObject (Object value , String format ) {
78
- Parsed geometry ;
79
- try (XContentParser parser = new MapXContentParser (NamedXContentRegistry .EMPTY , LoggingDeprecationHandler .INSTANCE ,
80
- Collections .singletonMap ("dummy_field" , value ), XContentType .JSON )) {
81
- parser .nextToken (); // start object
82
- parser .nextToken (); // field name
83
- parser .nextToken (); // field value
84
- geometry = parse (parser );
64
+ private void fetchFromSource (Object sourceMap , Consumer <Object > consumer , String format ) {
65
+ try (XContentParser parser = MapXContentParser .wrapObject (sourceMap )) {
66
+ parse (parser , v -> consumer .accept (format (v , format )), e -> {}); /* ignore malformed */
85
67
} catch (IOException e ) {
86
68
throw new UncheckedIOException (e );
87
- } catch (ParseException e ) {
88
- throw new RuntimeException (e );
89
69
}
90
- return format (geometry , format );
91
70
}
92
71
}
93
72
@@ -113,19 +92,22 @@ public final Query termQuery(Object value, SearchExecutionContext context) {
113
92
public final ValueFetcher valueFetcher (SearchExecutionContext context , String format ) {
114
93
String geoFormat = format != null ? format : GeoJsonGeometryFormat .NAME ;
115
94
116
- Function <Object , Object > valueParser = value -> geometryParser .parseAndFormatObject (value , geoFormat );
117
95
if (parsesArrayValue ) {
118
96
return new ArraySourceValueFetcher (name (), context ) {
119
97
@ Override
120
98
protected Object parseSourceValue (Object value ) {
121
- return valueParser .apply (value );
99
+ List <Object > values = new ArrayList <>();
100
+ geometryParser .fetchFromSource (value , values ::add , geoFormat );
101
+ return values ;
122
102
}
123
103
};
124
104
} else {
125
105
return new SourceValueFetcher (name (), context ) {
126
106
@ Override
127
107
protected Object parseSourceValue (Object value ) {
128
- return valueParser .apply (value );
108
+ SetOnce <Object > holder = new SetOnce <>();
109
+ geometryParser .fetchFromSource (value , holder ::set , geoFormat );
110
+ return holder .get ();
129
111
}
130
112
};
131
113
}
@@ -134,26 +116,24 @@ protected Object parseSourceValue(Object value) {
134
116
135
117
private final Explicit <Boolean > ignoreMalformed ;
136
118
private final Explicit <Boolean > ignoreZValue ;
137
- private final Indexer <Parsed , Processed > indexer ;
138
- private final Parser <Parsed > parser ;
119
+ private final Parser <T > parser ;
139
120
140
121
protected AbstractGeometryFieldMapper (String simpleName , MappedFieldType mappedFieldType ,
141
122
Map <String , NamedAnalyzer > indexAnalyzers ,
142
123
Explicit <Boolean > ignoreMalformed , Explicit <Boolean > ignoreZValue ,
143
124
MultiFields multiFields , CopyTo copyTo ,
144
- Indexer < Parsed , Processed > indexer , Parser <Parsed > parser ) {
125
+ Parser <T > parser ) {
145
126
super (simpleName , mappedFieldType , indexAnalyzers , multiFields , copyTo , false , null );
146
127
this .ignoreMalformed = ignoreMalformed ;
147
128
this .ignoreZValue = ignoreZValue ;
148
- this .indexer = indexer ;
149
129
this .parser = parser ;
150
130
}
151
131
152
132
protected AbstractGeometryFieldMapper (String simpleName , MappedFieldType mappedFieldType ,
153
133
Explicit <Boolean > ignoreMalformed , Explicit <Boolean > ignoreZValue ,
154
134
MultiFields multiFields , CopyTo copyTo ,
155
- Indexer < Parsed , Processed > indexer , Parser <Parsed > parser ) {
156
- this (simpleName , mappedFieldType , Collections .emptyMap (), ignoreMalformed , ignoreZValue , multiFields , copyTo , indexer , parser );
135
+ Parser <T > parser ) {
136
+ this (simpleName , mappedFieldType , Collections .emptyMap (), ignoreMalformed , ignoreZValue , multiFields , copyTo , parser );
157
137
}
158
138
159
139
@ Override
@@ -166,60 +146,25 @@ protected void parseCreateField(ParseContext context) throws IOException {
166
146
throw new UnsupportedOperationException ("Parsing is implemented in parse(), this method should NEVER be called" );
167
147
}
168
148
169
- protected abstract void addStoredFields (ParseContext context , Processed geometry );
170
- protected abstract void addDocValuesFields (String name , Processed geometry , List <IndexableField > fields , ParseContext context );
171
- protected abstract void addMultiFields (ParseContext context , Processed geometry ) throws IOException ;
149
+ /**
150
+ * Build an index document using a parsed geometry
151
+ * @param context the ParseContext holding the document
152
+ * @param geometry the parsed geometry object
153
+ */
154
+ protected abstract void index (ParseContext context , T geometry ) throws IOException ;
172
155
173
- /** parsing logic for geometry indexing */
174
156
@ Override
175
- public void parse (ParseContext context ) throws IOException {
176
- MappedFieldType mappedFieldType = fieldType ();
177
-
178
- try {
179
- Processed shape = context .parseExternalValue (indexer .processedClass ());
180
- if (shape == null ) {
181
- Parsed geometry = parser .parse (context .parser ());
182
- if (geometry == null ) {
183
- return ;
184
- }
185
- shape = indexer .prepareForIndexing (geometry );
186
- }
187
-
188
- List <IndexableField > fields = new ArrayList <>();
189
- if (mappedFieldType .isSearchable () || mappedFieldType .hasDocValues ()) {
190
- fields .addAll (indexer .indexShape (context , shape ));
191
- }
192
-
193
- // indexed:
194
- List <IndexableField > indexedFields = new ArrayList <>();
195
- if (mappedFieldType .isSearchable ()) {
196
- indexedFields .addAll (fields );
197
- }
198
- // stored:
199
- if (fieldType ().isStored ()) {
200
- addStoredFields (context , shape );
201
- }
202
- // docValues:
203
- if (fieldType ().hasDocValues ()) {
204
- addDocValuesFields (mappedFieldType .name (), shape , fields , context );
205
- } else if (fieldType ().isStored () || fieldType ().isSearchable ()) {
206
- createFieldNamesField (context );
207
- }
208
-
209
- // add the indexed fields to the doc:
210
- for (IndexableField field : indexedFields ) {
211
- context .doc ().add (field );
212
- }
213
-
214
- // add multifields (e.g., used for completion suggester)
215
- addMultiFields (context , shape );
216
- } catch (Exception e ) {
217
- if (ignoreMalformed .value () == false ) {
218
- throw new MapperParsingException ("failed to parse field [{}] of type [{}]" , e , fieldType ().name (),
219
- fieldType ().typeName ());
220
- }
221
- context .addIgnoredField (mappedFieldType .name ());
222
- }
157
+ public final void parse (ParseContext context ) throws IOException {
158
+ parser .parse (context .parser (), v -> index (context , v ), e -> {
159
+ if (ignoreMalformed ()) {
160
+ context .addIgnoredField (fieldType ().name ());
161
+ } else {
162
+ throw new MapperParsingException (
163
+ "Failed to parse field [" + fieldType ().name () + "] of type [" + contentType () + "]" ,
164
+ e
165
+ );
166
+ }
167
+ });
223
168
}
224
169
225
170
public boolean ignoreMalformed () {
0 commit comments