-
Notifications
You must be signed in to change notification settings - Fork 25.2k
Rework geo mappers to index value by value #71696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
28552b7
Rework geo mappers to index value by value
romseygeek 6b6ad29
tests; feedback
romseygeek f2cdb81
unlock test
romseygeek 7415732
Merge remote-tracking branch 'origin/master' into mapper/geo-indexing
romseygeek f45a756
Merge remote-tracking branch 'origin/master' into mapper/geo-indexing
romseygeek aae6f69
tests
romseygeek 7239f79
Merge remote-tracking branch 'origin/master' into mapper/geo-indexing
romseygeek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,8 +7,8 @@ | |
*/ | ||
package org.elasticsearch.index.mapper; | ||
|
||
import org.apache.lucene.index.IndexableField; | ||
import org.apache.lucene.search.Query; | ||
import org.elasticsearch.common.CheckedConsumer; | ||
import org.elasticsearch.common.Explicit; | ||
import org.elasticsearch.common.geo.GeoJsonGeometryFormat; | ||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; | ||
|
@@ -21,17 +21,15 @@ | |
|
||
import java.io.IOException; | ||
import java.io.UncheckedIOException; | ||
import java.text.ParseException; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
|
||
/** | ||
* Base field mapper class for all spatial field types | ||
*/ | ||
public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends FieldMapper { | ||
public abstract class AbstractGeometryFieldMapper<T> extends FieldMapper { | ||
|
||
public static Parameter<Explicit<Boolean>> ignoreMalformedParam(Function<FieldMapper, Explicit<Boolean>> initializer, | ||
boolean ignoreMalformedByDefault) { | ||
|
@@ -42,52 +40,46 @@ public static Parameter<Explicit<Boolean>> ignoreZValueParam(Function<FieldMappe | |
return Parameter.explicitBoolParam("ignore_z_value", true, initializer, true); | ||
} | ||
|
||
/** | ||
* Interface representing an preprocessor in geometry indexing pipeline | ||
*/ | ||
public interface Indexer<Parsed, Processed> { | ||
Processed prepareForIndexing(Parsed geometry); | ||
Class<Processed> processedClass(); | ||
List<IndexableField> indexShape(ParseContext context, Processed shape); | ||
} | ||
|
||
/** | ||
* Interface representing parser in geometry indexing pipeline. | ||
*/ | ||
public abstract static class Parser<Parsed> { | ||
public abstract static class Parser<T> { | ||
/** | ||
* Parse the given xContent value to an object of type {@link Parsed}. The value can be | ||
* Parse the given xContent value to one or more objects of type {@link T}. The value can be | ||
* in any supported format. | ||
*/ | ||
public abstract Parsed parse(XContentParser parser) throws IOException, ParseException; | ||
public abstract void parse( | ||
XContentParser parser, | ||
CheckedConsumer<T, IOException> consumer, | ||
Consumer<Exception> onMalformed) throws IOException; | ||
|
||
/** | ||
* Given a parsed value and a format string, formats the value into a plain Java object. | ||
* | ||
* Supported formats include 'geojson' and 'wkt'. The different formats are defined | ||
* as subclasses of {@link org.elasticsearch.common.geo.GeometryFormat}. | ||
*/ | ||
public abstract Object format(Parsed value, String format); | ||
public abstract Object format(T value, String format); | ||
|
||
/** | ||
* Parses the given value, then formats it according to the 'format' string. | ||
* | ||
* Used by value fetchers to validate and format geo objects | ||
*/ | ||
public Object parseAndFormatObject(Object value, String format) { | ||
Parsed geometry; | ||
Object[] formatted = new Object[1]; | ||
try (XContentParser parser = new MapXContentParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, | ||
Collections.singletonMap("dummy_field", value), XContentType.JSON)) { | ||
parser.nextToken(); // start object | ||
parser.nextToken(); // field name | ||
parser.nextToken(); // field value | ||
geometry = parse(parser); | ||
parse(parser, v -> { | ||
formatted[0] = format(v, format); | ||
}, e -> {} /* ignore malformed */); | ||
} catch (IOException e) { | ||
throw new UncheckedIOException(e); | ||
} catch (ParseException e) { | ||
throw new RuntimeException(e); | ||
} | ||
return format(geometry, format); | ||
return formatted[0]; | ||
} | ||
} | ||
|
||
|
@@ -134,26 +126,24 @@ protected Object parseSourceValue(Object value) { | |
|
||
private final Explicit<Boolean> ignoreMalformed; | ||
private final Explicit<Boolean> ignoreZValue; | ||
private final Indexer<Parsed, Processed> indexer; | ||
private final Parser<Parsed> parser; | ||
private final Parser<T> parser; | ||
|
||
protected AbstractGeometryFieldMapper(String simpleName, MappedFieldType mappedFieldType, | ||
Map<String, NamedAnalyzer> indexAnalyzers, | ||
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> ignoreZValue, | ||
MultiFields multiFields, CopyTo copyTo, | ||
Indexer<Parsed, Processed> indexer, Parser<Parsed> parser) { | ||
Parser<T> parser) { | ||
super(simpleName, mappedFieldType, indexAnalyzers, multiFields, copyTo, false, null); | ||
this.ignoreMalformed = ignoreMalformed; | ||
this.ignoreZValue = ignoreZValue; | ||
this.indexer = indexer; | ||
this.parser = parser; | ||
} | ||
|
||
protected AbstractGeometryFieldMapper(String simpleName, MappedFieldType mappedFieldType, | ||
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> ignoreZValue, | ||
MultiFields multiFields, CopyTo copyTo, | ||
Indexer<Parsed, Processed> indexer, Parser<Parsed> parser) { | ||
this(simpleName, mappedFieldType, Collections.emptyMap(), ignoreMalformed, ignoreZValue, multiFields, copyTo, indexer, parser); | ||
Parser<T> parser) { | ||
this(simpleName, mappedFieldType, Collections.emptyMap(), ignoreMalformed, ignoreZValue, multiFields, copyTo, parser); | ||
} | ||
|
||
@Override | ||
|
@@ -166,60 +156,21 @@ protected void parseCreateField(ParseContext context) throws IOException { | |
throw new UnsupportedOperationException("Parsing is implemented in parse(), this method should NEVER be called"); | ||
} | ||
|
||
protected abstract void addStoredFields(ParseContext context, Processed geometry); | ||
protected abstract void addDocValuesFields(String name, Processed geometry, List<IndexableField> fields, ParseContext context); | ||
protected abstract void addMultiFields(ParseContext context, Processed geometry) throws IOException; | ||
protected abstract void index(ParseContext context, T geometry) throws IOException; | ||
|
||
/** parsing logic for geometry indexing */ | ||
@Override | ||
public void parse(ParseContext context) throws IOException { | ||
MappedFieldType mappedFieldType = fieldType(); | ||
|
||
try { | ||
Processed shape = context.parseExternalValue(indexer.processedClass()); | ||
if (shape == null) { | ||
Parsed geometry = parser.parse(context.parser()); | ||
if (geometry == null) { | ||
return; | ||
} | ||
shape = indexer.prepareForIndexing(geometry); | ||
} | ||
|
||
List<IndexableField> fields = new ArrayList<>(); | ||
if (mappedFieldType.isSearchable() || mappedFieldType.hasDocValues()) { | ||
fields.addAll(indexer.indexShape(context, shape)); | ||
} | ||
|
||
// indexed: | ||
List<IndexableField> indexedFields = new ArrayList<>(); | ||
if (mappedFieldType.isSearchable()) { | ||
indexedFields.addAll(fields); | ||
} | ||
// stored: | ||
if (fieldType().isStored()) { | ||
addStoredFields(context, shape); | ||
} | ||
// docValues: | ||
if (fieldType().hasDocValues()) { | ||
addDocValuesFields(mappedFieldType.name(), shape, fields, context); | ||
} else if (fieldType().isStored() || fieldType().isSearchable()) { | ||
createFieldNamesField(context); | ||
} | ||
|
||
// add the indexed fields to the doc: | ||
for (IndexableField field : indexedFields) { | ||
context.doc().add(field); | ||
} | ||
|
||
// add multifields (e.g., used for completion suggester) | ||
addMultiFields(context, shape); | ||
} catch (Exception e) { | ||
if (ignoreMalformed.value() == false) { | ||
throw new MapperParsingException("failed to parse field [{}] of type [{}]", e, fieldType().name(), | ||
fieldType().typeName()); | ||
} | ||
context.addIgnoredField(mappedFieldType.name()); | ||
} | ||
public final void parse(ParseContext context) throws IOException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should remove the comment on this method as there is not parsing logic and add documentation ton the new index() method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ++ |
||
parser.parse(context.parser(), v -> index(context, v), e -> { | ||
if (ignoreMalformed()) { | ||
context.addIgnoredField(fieldType().name()); | ||
} else { | ||
throw new MapperParsingException( | ||
"Failed to parse field [" + fieldType().name() + "] of type [" + contentType() + "]", | ||
e | ||
); | ||
} | ||
}); | ||
} | ||
|
||
public boolean ignoreMalformed() { | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it'd be more straightforward to use
SetOnce
instead of an array.