77 */
88package org .elasticsearch .index .mapper ;
99
10- import org .apache .lucene .index .IndexableField ;
1110import org .apache .lucene .search .Query ;
11+ import org .apache .lucene .util .SetOnce ;
12+ import org .elasticsearch .common .CheckedConsumer ;
1213import org .elasticsearch .common .Explicit ;
1314import org .elasticsearch .common .geo .GeoJsonGeometryFormat ;
14- import org .elasticsearch .common .xcontent .LoggingDeprecationHandler ;
15- import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
1615import org .elasticsearch .common .xcontent .XContentParser ;
17- import org .elasticsearch .common .xcontent .XContentType ;
1816import org .elasticsearch .common .xcontent .support .MapXContentParser ;
1917import org .elasticsearch .index .analysis .NamedAnalyzer ;
2018import org .elasticsearch .index .query .SearchExecutionContext ;
2119
2220import java .io .IOException ;
2321import java .io .UncheckedIOException ;
24- import java .text .ParseException ;
2522import java .util .ArrayList ;
2623import java .util .Collections ;
2724import java .util .List ;
2825import java .util .Map ;
26+ import java .util .function .Consumer ;
2927import java .util .function .Function ;
3028
3129/**
3230 * Base field mapper class for all spatial field types
3331 */
34- public abstract class AbstractGeometryFieldMapper <Parsed , Processed > extends FieldMapper {
32+ public abstract class AbstractGeometryFieldMapper <T > extends FieldMapper {
3533
3634 public static Parameter <Explicit <Boolean >> ignoreMalformedParam (Function <FieldMapper , Explicit <Boolean >> initializer ,
3735 boolean ignoreMalformedByDefault ) {
@@ -42,52 +40,33 @@ public static Parameter<Explicit<Boolean>> ignoreZValueParam(Function<FieldMappe
4240 return Parameter .explicitBoolParam ("ignore_z_value" , true , initializer , true );
4341 }
4442
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-
5443 /**
5544 * Interface representing parser in geometry indexing pipeline.
5645 */
57- public abstract static class Parser <Parsed > {
46+ public abstract static class Parser <T > {
5847 /**
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
6049 * in any supported format.
6150 */
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 ;
6355
6456 /**
6557 * Given a parsed value and a format string, formats the value into a plain Java object.
6658 *
6759 * Supported formats include 'geojson' and 'wkt'. The different formats are defined
6860 * as subclasses of {@link org.elasticsearch.common.geo.GeometryFormat}.
6961 */
70- public abstract Object format (Parsed value , String format );
62+ public abstract Object format (T value , String format );
7163
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 */
8567 } catch (IOException e ) {
8668 throw new UncheckedIOException (e );
87- } catch (ParseException e ) {
88- throw new RuntimeException (e );
8969 }
90- return format (geometry , format );
9170 }
9271 }
9372
@@ -113,19 +92,22 @@ public final Query termQuery(Object value, SearchExecutionContext context) {
11392 public final ValueFetcher valueFetcher (SearchExecutionContext context , String format ) {
11493 String geoFormat = format != null ? format : GeoJsonGeometryFormat .NAME ;
11594
116- Function <Object , Object > valueParser = value -> geometryParser .parseAndFormatObject (value , geoFormat );
11795 if (parsesArrayValue ) {
11896 return new ArraySourceValueFetcher (name (), context ) {
11997 @ Override
12098 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 ;
122102 }
123103 };
124104 } else {
125105 return new SourceValueFetcher (name (), context ) {
126106 @ Override
127107 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 ();
129111 }
130112 };
131113 }
@@ -134,26 +116,24 @@ protected Object parseSourceValue(Object value) {
134116
135117 private final Explicit <Boolean > ignoreMalformed ;
136118 private final Explicit <Boolean > ignoreZValue ;
137- private final Indexer <Parsed , Processed > indexer ;
138- private final Parser <Parsed > parser ;
119+ private final Parser <T > parser ;
139120
140121 protected AbstractGeometryFieldMapper (String simpleName , MappedFieldType mappedFieldType ,
141122 Map <String , NamedAnalyzer > indexAnalyzers ,
142123 Explicit <Boolean > ignoreMalformed , Explicit <Boolean > ignoreZValue ,
143124 MultiFields multiFields , CopyTo copyTo ,
144- Indexer < Parsed , Processed > indexer , Parser <Parsed > parser ) {
125+ Parser <T > parser ) {
145126 super (simpleName , mappedFieldType , indexAnalyzers , multiFields , copyTo , false , null );
146127 this .ignoreMalformed = ignoreMalformed ;
147128 this .ignoreZValue = ignoreZValue ;
148- this .indexer = indexer ;
149129 this .parser = parser ;
150130 }
151131
152132 protected AbstractGeometryFieldMapper (String simpleName , MappedFieldType mappedFieldType ,
153133 Explicit <Boolean > ignoreMalformed , Explicit <Boolean > ignoreZValue ,
154134 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 );
157137 }
158138
159139 @ Override
@@ -166,60 +146,25 @@ protected void parseCreateField(ParseContext context) throws IOException {
166146 throw new UnsupportedOperationException ("Parsing is implemented in parse(), this method should NEVER be called" );
167147 }
168148
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 ;
172155
173- /** parsing logic for geometry indexing */
174156 @ 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+ });
223168 }
224169
225170 public boolean ignoreMalformed () {
0 commit comments