[Backport] Refactor Spatial Field Mappers (#55696)

This commit refactors all spatial Field Mappers to a common
AbstractGeometryFieldMapper that implements shared parameter functionality
(e.g., ignore_malformed, ignore_z_value) and provides a common framework for
overriding type parsing, and building in xpack. Common shape functionality is
implemented in a new AbstractShapeGeometryFieldMapper that is reused and
overridden in GeoShapeFieldMapper, GeoShapeFieldMapperWithDocValues,
LegacyGeoShapeFieldMapper, and ShapeFieldMapper. This abstraction provides a
reusable foundation for adding new xpack features; such as coordinate reference
system support.
This commit is contained in:
Nick Knize 2020-04-24 14:05:16 -05:00 committed by GitHub
parent e4ebe55d04
commit b0e8a8a4d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 542 additions and 623 deletions

View File

@ -29,7 +29,7 @@ import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentSubParser;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.locationtech.jts.geom.Coordinate;
import java.io.IOException;
@ -42,7 +42,7 @@ import java.util.List;
* complies with geojson specification: https://tools.ietf.org/html/rfc7946
*/
abstract class GeoJsonParser {
protected static ShapeBuilder parse(XContentParser parser, AbstractGeometryFieldMapper shapeMapper)
protected static ShapeBuilder parse(XContentParser parser, AbstractShapeGeometryFieldMapper shapeMapper)
throws IOException {
GeoShapeType shapeType = null;
DistanceUnit.Distance radius = null;
@ -50,13 +50,13 @@ abstract class GeoJsonParser {
GeometryCollectionBuilder geometryCollections = null;
Orientation orientation = (shapeMapper == null)
? AbstractGeometryFieldMapper.Defaults.ORIENTATION.value()
? AbstractShapeGeometryFieldMapper.Defaults.ORIENTATION.value()
: shapeMapper.orientation();
Explicit<Boolean> coerce = (shapeMapper == null)
? AbstractGeometryFieldMapper.Defaults.COERCE
? AbstractShapeGeometryFieldMapper.Defaults.COERCE
: shapeMapper.coerce();
Explicit<Boolean> ignoreZValue = (shapeMapper == null)
? AbstractGeometryFieldMapper.Defaults.IGNORE_Z_VALUE
? AbstractShapeGeometryFieldMapper.Defaults.IGNORE_Z_VALUE
: shapeMapper.ignoreZValue();
String malformedException = null;
@ -208,7 +208,7 @@ abstract class GeoJsonParser {
* @return Geometry[] geometries of the GeometryCollection
* @throws IOException Thrown if an error occurs while reading from the XContentParser
*/
static GeometryCollectionBuilder parseGeometries(XContentParser parser, AbstractGeometryFieldMapper mapper) throws
static GeometryCollectionBuilder parseGeometries(XContentParser parser, AbstractShapeGeometryFieldMapper mapper) throws
IOException {
if (parser.currentToken() != XContentParser.Token.START_ARRAY) {
throw new ElasticsearchParseException("geometries must be an array of geojson objects");

View File

@ -34,7 +34,7 @@ import org.elasticsearch.common.geo.builders.PolygonBuilder;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.locationtech.jts.geom.Coordinate;
import java.io.IOException;
@ -63,7 +63,7 @@ public class GeoWKTParser {
// no instance
private GeoWKTParser() {}
public static ShapeBuilder parse(XContentParser parser, final AbstractGeometryFieldMapper shapeMapper)
public static ShapeBuilder parse(XContentParser parser, final AbstractShapeGeometryFieldMapper shapeMapper)
throws IOException, ElasticsearchParseException {
return parseExpectedType(parser, null, shapeMapper);
}
@ -75,12 +75,12 @@ public class GeoWKTParser {
/** throws an exception if the parsed geometry type does not match the expected shape type */
public static ShapeBuilder parseExpectedType(XContentParser parser, final GeoShapeType shapeType,
final AbstractGeometryFieldMapper shapeMapper)
final AbstractShapeGeometryFieldMapper shapeMapper)
throws IOException, ElasticsearchParseException {
try (StringReader reader = new StringReader(parser.text())) {
Explicit<Boolean> ignoreZValue = (shapeMapper == null) ? AbstractGeometryFieldMapper.Defaults.IGNORE_Z_VALUE :
Explicit<Boolean> ignoreZValue = (shapeMapper == null) ? AbstractShapeGeometryFieldMapper.Defaults.IGNORE_Z_VALUE :
shapeMapper.ignoreZValue();
Explicit<Boolean> coerce = (shapeMapper == null) ? AbstractGeometryFieldMapper.Defaults.COERCE : shapeMapper.coerce();
Explicit<Boolean> coerce = (shapeMapper == null) ? AbstractShapeGeometryFieldMapper.Defaults.COERCE : shapeMapper.coerce();
// setup the tokenizer; configured to read words w/o numbers
StreamTokenizer tokenizer = new StreamTokenizer(reader);
tokenizer.resetSyntax();
@ -258,7 +258,7 @@ public class GeoWKTParser {
return null;
}
PolygonBuilder builder = new PolygonBuilder(parseLinearRing(stream, ignoreZValue, coerce),
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value());
AbstractShapeGeometryFieldMapper.Defaults.ORIENTATION.value());
while (nextCloserOrComma(stream).equals(COMMA)) {
builder.hole(parseLinearRing(stream, ignoreZValue, coerce));
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.MapXContentParser;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import java.io.IOException;
import java.util.Collections;
@ -50,7 +50,7 @@ public interface ShapeParser {
* if the parsers current token has been <code>null</code>
* @throws IOException if the input could not be read
*/
static ShapeBuilder parse(XContentParser parser, AbstractGeometryFieldMapper shapeMapper) throws IOException {
static ShapeBuilder parse(XContentParser parser, AbstractShapeGeometryFieldMapper shapeMapper) throws IOException {
if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
return null;
} if (parser.currentToken() == XContentParser.Token.START_OBJECT) {

View File

@ -23,122 +23,53 @@ import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.Version;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.SpatialStrategy;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper.DeprecatedParameters;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.index.mapper.GeoPointFieldMapper.Names.IGNORE_MALFORMED;
/**
* Base class for {@link GeoShapeFieldMapper} and {@link LegacyGeoShapeFieldMapper}
* Base field mapper class for all spatial field types
*/
public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends FieldMapper {
public abstract class AbstractGeometryFieldMapper extends FieldMapper {
public static class Names {
public static final ParseField ORIENTATION = new ParseField("orientation");
public static final ParseField COERCE = new ParseField("coerce");
public static final ParseField IGNORE_MALFORMED = new ParseField("ignore_malformed");
public static final ParseField IGNORE_Z_VALUE = new ParseField("ignore_z_value");
}
public static class Defaults {
public static final Explicit<Orientation> ORIENTATION = new Explicit<>(Orientation.RIGHT, false);
public static final Explicit<Boolean> COERCE = new Explicit<>(false, false);
public static final Explicit<Boolean> IGNORE_MALFORMED = new Explicit<>(false, false);
public static final Explicit<Boolean> IGNORE_Z_VALUE = new Explicit<>(true, false);
}
/**
* Interface representing an preprocessor in geo-shape 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 geo shape indexing pipeline
*/
public interface Parser<Parsed> {
Parsed parse(XContentParser parser, AbstractGeometryFieldMapper mapper) throws IOException, ParseException;
}
public abstract static class Builder<T extends Builder, Y extends AbstractGeometryFieldMapper>
extends FieldMapper.Builder<T, Y> {
protected Boolean coerce;
protected Boolean ignoreMalformed;
protected Boolean ignoreZValue;
protected Orientation orientation;
/** default builder - used for external mapper*/
public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType) {
super(name, fieldType, defaultFieldType);
}
public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType,
boolean coerce, boolean ignoreMalformed, Orientation orientation, boolean ignoreZ) {
public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType, boolean ignoreMalformed,
boolean ignoreZValue) {
super(name, fieldType, defaultFieldType);
this.coerce = coerce;
this.ignoreMalformed = ignoreMalformed;
this.orientation = orientation;
this.ignoreZValue = ignoreZ;
}
public Builder coerce(boolean coerce) {
this.coerce = coerce;
return this;
}
protected Explicit<Boolean> coerce(BuilderContext context) {
if (coerce != null) {
return new Explicit<>(coerce, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(COERCE_SETTING.get(context.indexSettings()), false);
}
return Defaults.COERCE;
}
public Builder orientation(Orientation orientation) {
this.orientation = orientation;
return this;
}
protected Explicit<Orientation> orientation() {
if (orientation != null) {
return new Explicit<>(orientation, true);
}
return Defaults.ORIENTATION;
}
@Override
protected boolean defaultDocValues(Version indexCreated) {
return false;
this.ignoreZValue = ignoreZValue;
}
public Builder ignoreMalformed(boolean ignoreMalformed) {
@ -156,13 +87,27 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
return Defaults.IGNORE_MALFORMED;
}
protected Explicit<Boolean> ignoreZValue() {
public Explicit<Boolean> ignoreMalformed() {
if (ignoreMalformed != null) {
return new Explicit<>(ignoreMalformed, true);
}
return AbstractShapeGeometryFieldMapper.Defaults.IGNORE_MALFORMED;
}
protected Explicit<Boolean> ignoreZValue(BuilderContext context) {
if (ignoreZValue != null) {
return new Explicit<>(ignoreZValue, true);
}
return Defaults.IGNORE_Z_VALUE;
}
public Explicit<Boolean> ignoreZValue() {
if (ignoreZValue != null) {
return new Explicit<>(ignoreZValue, true);
}
return AbstractShapeGeometryFieldMapper.Defaults.IGNORE_Z_VALUE;
}
public Builder ignoreZValue(final boolean ignoreZValue) {
this.ignoreZValue = ignoreZValue;
return this;
@ -177,88 +122,52 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
if (name().isEmpty()) {
throw new IllegalArgumentException("name cannot be empty string");
}
AbstractGeometryFieldType ft = (AbstractGeometryFieldType)fieldType();
ft.setOrientation(orientation().value());
}
}
protected static final String DEPRECATED_PARAMETERS_KEY = "deprecated_parameters";
public abstract static class TypeParser<T extends Builder> implements Mapper.TypeParser {
protected abstract T newBuilder(String name, Map<String, Object> params);
public abstract static class TypeParser implements Mapper.TypeParser {
protected abstract Builder newBuilder(String name, Map<String, Object> params);
protected boolean parseXContentParameters(String name, Map.Entry<String, Object> entry, Map<String, Object> params)
throws MapperParsingException {
if (DeprecatedParameters.parse(name, entry.getKey(), entry.getValue(),
(DeprecatedParameters)params.get(DEPRECATED_PARAMETERS_KEY))) {
return true;
}
return false;
}
@Override
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
Map<String, Object> params = new HashMap<>();
boolean parsedDeprecatedParameters = false;
params.put(DEPRECATED_PARAMETERS_KEY, new DeprecatedParameters());
public T parse(String name, Map<String, Object> node, Map<String, Object> params, ParserContext parserContext) {
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (parseXContentParameters(name, entry, params)) {
parsedDeprecatedParameters = true;
iterator.remove();
} else if (Names.ORIENTATION.match(fieldName, LoggingDeprecationHandler.INSTANCE)) {
params.put(Names.ORIENTATION.getPreferredName(), ShapeBuilder.Orientation.fromString(fieldNode.toString()));
iterator.remove();
} else if (IGNORE_MALFORMED.equals(fieldName)) {
params.put(IGNORE_MALFORMED, XContentMapValues.nodeBooleanValue(fieldNode, name + ".ignore_malformed"));
iterator.remove();
} else if (Names.COERCE.match(fieldName, LoggingDeprecationHandler.INSTANCE)) {
params.put(Names.COERCE.getPreferredName(),
XContentMapValues.nodeBooleanValue(fieldNode, name + "." + Names.COERCE.getPreferredName()));
iterator.remove();
} else if (GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName().equals(fieldName)) {
params.put(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName(),
XContentMapValues.nodeBooleanValue(fieldNode,
name + "." + GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName()));
iterator.remove();
}
}
if (parserContext.indexVersionCreated().onOrAfter(Version.V_6_6_0) && parsedDeprecatedParameters == false) {
params.remove(DEPRECATED_PARAMETERS_KEY);
}
Builder builder = newBuilder(name, params);
String propName = entry.getKey();
Object propNode = entry.getValue();
if (params.containsKey(Names.COERCE.getPreferredName())) {
builder.coerce((Boolean)params.get(Names.COERCE.getPreferredName()));
if (Names.IGNORE_MALFORMED.match(propName, LoggingDeprecationHandler.INSTANCE)) {
params.put(Names.IGNORE_MALFORMED.getPreferredName(), XContentMapValues.nodeBooleanValue(propNode,
name + ".ignore_malformed"));
iterator.remove();
} else if (Names.IGNORE_Z_VALUE.getPreferredName().equals(propName)) {
params.put(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName(),
XContentMapValues.nodeBooleanValue(propNode, name + "." + Names.IGNORE_Z_VALUE.getPreferredName()));
iterator.remove();
}
}
T builder = newBuilder(name, params);
if (params.containsKey(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName())) {
builder.ignoreZValue((Boolean)params.get(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName()));
}
if (params.containsKey(IGNORE_MALFORMED)) {
builder.ignoreMalformed((Boolean)params.get(IGNORE_MALFORMED));
if (params.containsKey(Names.IGNORE_MALFORMED.getPreferredName())) {
builder.ignoreMalformed((Boolean)params.get(Names.IGNORE_MALFORMED.getPreferredName()));
}
if (params.containsKey(Names.ORIENTATION.getPreferredName())) {
builder.orientation((Orientation)params.get(Names.ORIENTATION.getPreferredName()));
}
return builder;
}
@Override
@SuppressWarnings("rawtypes")
public T parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
Map<String, Object> params = new HashMap<>();
return parse(name, node, params, parserContext);
}
}
public abstract static class AbstractGeometryFieldType<Parsed, Processed> extends AbstractSearchableGeometryFieldType {
protected Orientation orientation = Defaults.ORIENTATION.value();
protected Indexer<Parsed, Processed> geometryIndexer;
protected Parser<Parsed> geometryParser;
public abstract static class AbstractGeometryFieldType extends MappedFieldType {
protected QueryProcessor geometryQueryBuilder;
protected AbstractGeometryFieldType() {
setIndexOptions(IndexOptions.DOCS);
@ -270,26 +179,27 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
protected AbstractGeometryFieldType(AbstractGeometryFieldType ref) {
super(ref);
this.orientation = ref.orientation;
}
@Override
public boolean equals(Object o) {
if (!super.equals(o)) return false;
AbstractGeometryFieldType that = (AbstractGeometryFieldType) o;
return orientation == that.orientation;
public void setGeometryQueryBuilder(QueryProcessor geometryQueryBuilder) {
this.geometryQueryBuilder = geometryQueryBuilder;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), orientation);
public QueryProcessor geometryQueryBuilder() {
return geometryQueryBuilder;
}
public Orientation orientation() { return this.orientation; }
/**
* interface representing a query builder that generates a query from the given geometry
*/
public interface QueryProcessor {
Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context);
public void setOrientation(Orientation orientation) {
checkIfFrozen();
this.orientation = orientation;
@Deprecated
default Query process(Geometry shape, String fieldName, SpatialStrategy strategy, ShapeRelation relation,
QueryShardContext context) {
return process(shape, fieldName, relation, context);
}
}
@Override
@ -300,36 +210,18 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
@Override
public Query termQuery(Object value, QueryShardContext context) {
throw new QueryShardException(context,
"Geometry fields do not support exact searching, use dedicated geometry queries instead");
}
public void setGeometryIndexer(Indexer<Parsed, Processed> geometryIndexer) {
this.geometryIndexer = geometryIndexer;
}
protected Indexer<Parsed, Processed> geometryIndexer() {
return geometryIndexer;
}
public void setGeometryParser(Parser<Parsed> geometryParser) {
this.geometryParser = geometryParser;
}
protected Parser<Parsed> geometryParser() {
return geometryParser;
"Geometry fields do not support exact searching, use dedicated geometry queries instead: ["
+ name() + "]");
}
}
protected Explicit<Boolean> coerce;
protected Explicit<Boolean> ignoreMalformed;
protected Explicit<Boolean> ignoreZValue;
protected AbstractGeometryFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
Explicit<Boolean> ignoreZValue, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
Settings indexSettings, Explicit<Boolean> ignoreMalformed,
Explicit<Boolean> ignoreZValue, MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo);
this.coerce = coerce;
this.ignoreMalformed = ignoreMalformed;
this.ignoreZValue = ignoreZValue;
}
@ -338,9 +230,7 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
protected void doMerge(Mapper mergeWith) {
super.doMerge(mergeWith);
AbstractGeometryFieldMapper gsfm = (AbstractGeometryFieldMapper)mergeWith;
if (gsfm.coerce.explicit()) {
this.coerce = gsfm.coerce;
}
if (gsfm.ignoreMalformed.explicit()) {
this.ignoreMalformed = gsfm.ignoreMalformed;
}
@ -356,26 +246,15 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
@Override
public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType());
AbstractGeometryFieldType ft = (AbstractGeometryFieldType)fieldType();
if (includeDefaults || ft.orientation() != Defaults.ORIENTATION.value()) {
builder.field(Names.ORIENTATION.getPreferredName(), ft.orientation());
}
if (includeDefaults || coerce.explicit()) {
builder.field(Names.COERCE.getPreferredName(), coerce.value());
}
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || ignoreMalformed.explicit()) {
builder.field(IGNORE_MALFORMED, ignoreMalformed.value());
builder.field(Names.IGNORE_MALFORMED.getPreferredName(), ignoreMalformed.value());
}
if (includeDefaults || ignoreZValue.explicit()) {
builder.field(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName(), ignoreZValue.value());
builder.field(Names.IGNORE_Z_VALUE.getPreferredName(), ignoreZValue.value());
}
}
public Explicit<Boolean> coerce() {
return coerce;
}
public Explicit<Boolean> ignoreMalformed() {
return ignoreMalformed;
}
@ -383,41 +262,4 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
public Explicit<Boolean> ignoreZValue() {
return ignoreZValue;
}
public Orientation orientation() {
return ((AbstractGeometryFieldType)fieldType).orientation();
}
/** parsing logic for geometry indexing */
@Override
public void parse(ParseContext context) throws IOException {
AbstractGeometryFieldType fieldType = (AbstractGeometryFieldType)fieldType();
@SuppressWarnings("unchecked") Indexer<Parsed, Processed> geometryIndexer = fieldType.geometryIndexer();
@SuppressWarnings("unchecked") Parser<Parsed> geometryParser = fieldType.geometryParser();
try {
Processed shape = context.parseExternalValue(geometryIndexer.processedClass());
if (shape == null) {
Parsed geometry = geometryParser.parse(context.parser(), this);
if (geometry == null) {
return;
}
shape = geometryIndexer.prepareForIndexing(geometry);
}
List<IndexableField> fields = new ArrayList<>();
fields.addAll(geometryIndexer.indexShape(context, shape));
createFieldNamesField(context, fields);
for (IndexableField field : fields) {
context.doc().add(field);
}
} catch (Exception e) {
if (ignoreMalformed.value() == false) {
throw new MapperParsingException("failed to parse field [{}] of type [{}]", e, fieldType().name(),
fieldType().typeName());
}
context.addIgnoredField(fieldType().name());
}
}
}

View File

@ -1,63 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.SpatialStrategy;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.query.QueryShardContext;
/**
* a base class for geometry types that support shape query builder
*/
public abstract class AbstractSearchableGeometryFieldType extends MappedFieldType {
protected QueryProcessor geometryQueryBuilder;
protected AbstractSearchableGeometryFieldType() {
}
protected AbstractSearchableGeometryFieldType(AbstractSearchableGeometryFieldType ref) {
super(ref);
}
public void setGeometryQueryBuilder(QueryProcessor geometryQueryBuilder) {
this.geometryQueryBuilder = geometryQueryBuilder;
}
public QueryProcessor geometryQueryBuilder() {
return geometryQueryBuilder;
}
/**
* interface representing a query builder that generates a query from the given shape
*/
public interface QueryProcessor {
Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context);
@Deprecated
default Query process(Geometry shape, String fieldName, SpatialStrategy strategy, ShapeRelation relation,
QueryShardContext context) {
return process(shape, fieldName, relation, context);
}
}
}

View File

@ -0,0 +1,316 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.Version;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper.DeprecatedParameters;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Base class for {@link GeoShapeFieldMapper} and {@link LegacyGeoShapeFieldMapper}
*/
public abstract class AbstractShapeGeometryFieldMapper<Parsed, Processed> extends AbstractGeometryFieldMapper {
public static class Names extends AbstractGeometryFieldMapper.Names {
public static final ParseField ORIENTATION = new ParseField("orientation");
public static final ParseField COERCE = new ParseField("coerce");
}
public static class Defaults extends AbstractGeometryFieldMapper.Defaults {
public static final Explicit<Orientation> ORIENTATION = new Explicit<>(Orientation.RIGHT, false);
public static final Explicit<Boolean> COERCE = new Explicit<>(false, false);
}
/**
* Interface representing an preprocessor in geo-shape 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 geo shape indexing pipeline
*/
public interface Parser<Parsed> {
Parsed parse(XContentParser parser, AbstractShapeGeometryFieldMapper mapper) throws IOException, ParseException;
}
public abstract static class Builder<T extends Builder, Y extends AbstractShapeGeometryFieldMapper>
extends AbstractGeometryFieldMapper.Builder<T, Y> {
protected Boolean coerce;
protected Orientation orientation;
/** default builder - used for external mapper*/
public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType) {
super(name, fieldType, defaultFieldType);
}
public Builder(String name, MappedFieldType fieldType, MappedFieldType defaultFieldType,
boolean coerce, boolean ignoreMalformed, Orientation orientation, boolean ignoreZ) {
super(name, fieldType, defaultFieldType, ignoreMalformed, ignoreZ);
this.coerce = coerce;
this.orientation = orientation;
}
public Builder coerce(boolean coerce) {
this.coerce = coerce;
return this;
}
protected Explicit<Boolean> coerce(BuilderContext context) {
if (coerce != null) {
return new Explicit<>(coerce, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(COERCE_SETTING.get(context.indexSettings()), false);
}
return Defaults.COERCE;
}
public Builder orientation(Orientation orientation) {
this.orientation = orientation;
return this;
}
protected Explicit<Orientation> orientation() {
if (orientation != null) {
return new Explicit<>(orientation, true);
}
return Defaults.ORIENTATION;
}
@Override
protected boolean defaultDocValues(Version indexCreated) {
return false;
}
@Override
protected void setupFieldType(BuilderContext context) {
super.setupFieldType(context);
AbstractShapeGeometryFieldType ft = (AbstractShapeGeometryFieldType)fieldType();
ft.setOrientation(orientation().value());
}
}
protected static final String DEPRECATED_PARAMETERS_KEY = "deprecated_parameters";
public abstract static class TypeParser extends AbstractGeometryFieldMapper.TypeParser<Builder> {
protected abstract Builder newBuilder(String name, Map<String, Object> params);
protected boolean parseXContentParameters(String name, Map.Entry<String, Object> entry, Map<String, Object> params)
throws MapperParsingException {
if (DeprecatedParameters.parse(name, entry.getKey(), entry.getValue(),
(DeprecatedParameters)params.get(DEPRECATED_PARAMETERS_KEY))) {
return true;
}
return false;
}
@Override
public Builder parse(String name, Map<String, Object> node, Map<String, Object> params, ParserContext parserContext) {
boolean parsedDeprecatedParameters = false;
params.put(DEPRECATED_PARAMETERS_KEY, new DeprecatedParameters());
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
String fieldName = entry.getKey();
Object fieldNode = entry.getValue();
if (parseXContentParameters(name, entry, params)) {
parsedDeprecatedParameters = true;
iterator.remove();
} else if (Names.ORIENTATION.match(fieldName, LoggingDeprecationHandler.INSTANCE)) {
params.put(Names.ORIENTATION.getPreferredName(), ShapeBuilder.Orientation.fromString(fieldNode.toString()));
iterator.remove();
} else if (Names.COERCE.match(fieldName, LoggingDeprecationHandler.INSTANCE)) {
params.put(Names.COERCE.getPreferredName(),
XContentMapValues.nodeBooleanValue(fieldNode, name + "." + Names.COERCE.getPreferredName()));
iterator.remove();
}
}
if (parserContext.indexVersionCreated().onOrAfter(Version.V_6_6_0) && parsedDeprecatedParameters == false) {
params.remove(DEPRECATED_PARAMETERS_KEY);
}
Builder builder = super.parse(name, node, params, parserContext);
if (params.containsKey(Names.COERCE.getPreferredName())) {
builder.coerce((Boolean)params.get(Names.COERCE.getPreferredName()));
}
if (params.containsKey(Names.ORIENTATION.getPreferredName())) {
builder.orientation((Orientation)params.get(Names.ORIENTATION.getPreferredName()));
}
return builder;
}
}
public abstract static class AbstractShapeGeometryFieldType<Parsed, Processed> extends AbstractGeometryFieldType {
protected Orientation orientation = Defaults.ORIENTATION.value();
protected Indexer<Parsed, Processed> geometryIndexer;
protected Parser<Parsed> geometryParser;
protected AbstractShapeGeometryFieldType() {
super();
}
protected AbstractShapeGeometryFieldType(AbstractShapeGeometryFieldType ref) {
super(ref);
this.orientation = ref.orientation;
}
@Override
public boolean equals(Object o) {
if (!super.equals(o)) return false;
AbstractShapeGeometryFieldType that = (AbstractShapeGeometryFieldType) o;
return orientation == that.orientation;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), orientation);
}
public Orientation orientation() { return this.orientation; }
public void setOrientation(Orientation orientation) {
checkIfFrozen();
this.orientation = orientation;
}
public void setGeometryIndexer(Indexer<Parsed, Processed> geometryIndexer) {
this.geometryIndexer = geometryIndexer;
}
protected Indexer<Parsed, Processed> geometryIndexer() {
return geometryIndexer;
}
public void setGeometryParser(Parser<Parsed> geometryParser) {
this.geometryParser = geometryParser;
}
protected Parser<Parsed> geometryParser() {
return geometryParser;
}
}
protected Explicit<Boolean> coerce;
protected Explicit<Orientation> orientation;
protected AbstractShapeGeometryFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
Explicit<Boolean> ignoreZValue, Explicit<Orientation> orientation, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, indexSettings, ignoreMalformed, ignoreZValue, multiFields, copyTo);
this.coerce = coerce;
this.orientation = orientation;
}
@Override
protected void doMerge(Mapper mergeWith) {
super.doMerge(mergeWith);
AbstractShapeGeometryFieldMapper gsfm = (AbstractShapeGeometryFieldMapper)mergeWith;
if (gsfm.coerce.explicit()) {
this.coerce = gsfm.coerce;
}
if (gsfm.orientation.explicit()) {
this.orientation = gsfm.orientation;
}
}
@Override
public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
AbstractShapeGeometryFieldType ft = (AbstractShapeGeometryFieldType)fieldType();
if (includeDefaults || coerce.explicit()) {
builder.field(AbstractShapeGeometryFieldMapper.Names.COERCE.getPreferredName(), coerce.value());
}
if (includeDefaults || ft.orientation() != Defaults.ORIENTATION.value()) {
builder.field(Names.ORIENTATION.getPreferredName(), ft.orientation());
}
}
public Explicit<Boolean> coerce() {
return coerce;
}
public Orientation orientation() {
return ((AbstractShapeGeometryFieldType)fieldType).orientation();
}
/** parsing logic for geometry indexing */
@Override
public void parse(ParseContext context) throws IOException {
AbstractShapeGeometryFieldType fieldType = (AbstractShapeGeometryFieldType)fieldType();
@SuppressWarnings("unchecked") Indexer<Parsed, Processed> geometryIndexer = fieldType.geometryIndexer();
@SuppressWarnings("unchecked") Parser<Parsed> geometryParser = fieldType.geometryParser();
try {
Processed shape = context.parseExternalValue(geometryIndexer.processedClass());
if (shape == null) {
Parsed geometry = geometryParser.parse(context.parser(), this);
if (geometry == null) {
return;
}
shape = geometryIndexer.prepareForIndexing(geometry);
}
List<IndexableField> fields = new ArrayList<>();
fields.addAll(geometryIndexer.indexShape(context, shape));
createFieldNamesField(context, fields);
for (IndexableField field : fields) {
context.doc().add(field);
}
} catch (Exception e) {
if (ignoreMalformed.value() == false) {
throw new MapperParsingException("failed to parse field [{}] of type [{}]", e, fieldType().name(),
fieldType().typeName());
}
context.addIgnoredField(fieldType().name());
}
}
}

View File

@ -23,23 +23,20 @@ import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.AbstractLatLonPointDVIndexFieldData;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.index.query.VectorGeoPointShapeQueryProcessor;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
@ -57,64 +54,19 @@ import static org.elasticsearch.index.mapper.TypeParsers.parseField;
*
* Uses lucene 6 LatLonPoint encoding
*/
public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapperParser {
public class GeoPointFieldMapper extends AbstractGeometryFieldMapper implements ArrayValueMapperParser {
public static final String CONTENT_TYPE = "geo_point";
public static class Names {
public static final String IGNORE_MALFORMED = "ignore_malformed";
public static final ParseField IGNORE_Z_VALUE = new ParseField("ignore_z_value");
public static final String NULL_VALUE = "null_value";
public static class Names extends AbstractGeometryFieldMapper.Names {
public static final ParseField NULL_VALUE = new ParseField("null_value");
}
public static class Defaults {
public static final Explicit<Boolean> IGNORE_MALFORMED = new Explicit<>(false, false);
public static final GeoPointFieldType FIELD_TYPE = new GeoPointFieldType();
public static final Explicit<Boolean> IGNORE_Z_VALUE = new Explicit<>(true, false);
static {
FIELD_TYPE.setTokenized(false);
FIELD_TYPE.setHasDocValues(true);
FIELD_TYPE.setDimensions(2, Integer.BYTES);
FIELD_TYPE.freeze();
}
}
public static class Builder extends FieldMapper.Builder<Builder, GeoPointFieldMapper> {
protected Boolean ignoreMalformed;
private Boolean ignoreZValue;
public static class Builder extends AbstractGeometryFieldMapper.Builder<Builder, GeoPointFieldMapper> {
public Builder(String name) {
super(name, Defaults.FIELD_TYPE, Defaults.FIELD_TYPE);
super(name, new GeoPointFieldType(), new GeoPointFieldType());
builder = this;
}
public Builder ignoreMalformed(boolean ignoreMalformed) {
this.ignoreMalformed = ignoreMalformed;
return builder;
}
protected Explicit<Boolean> ignoreMalformed(BuilderContext context) {
if (ignoreMalformed != null) {
return new Explicit<>(ignoreMalformed, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(IGNORE_MALFORMED_SETTING.get(context.indexSettings()), false);
}
return GeoPointFieldMapper.Defaults.IGNORE_MALFORMED;
}
protected Explicit<Boolean> ignoreZValue(BuilderContext context) {
if (ignoreZValue != null) {
return new Explicit<>(ignoreZValue, true);
}
return Defaults.IGNORE_Z_VALUE;
}
public Builder ignoreZValue(final boolean ignoreZValue) {
this.ignoreZValue = ignoreZValue;
return this;
}
public GeoPointFieldMapper build(BuilderContext context, String simpleName, MappedFieldType fieldType,
MappedFieldType defaultFieldType, Settings indexSettings,
MultiFields multiFields, Explicit<Boolean> ignoreMalformed,
@ -138,13 +90,23 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
multiFieldsBuilder.build(this, context), ignoreMalformed(context),
ignoreZValue(context), copyTo);
}
@Override
public GeoPointFieldType fieldType() {
return (GeoPointFieldType)fieldType;
}
}
public static class TypeParser implements Mapper.TypeParser {
public static class TypeParser extends AbstractGeometryFieldMapper.TypeParser<Builder> {
@Override
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
Builder builder = new GeoPointFieldMapper.Builder(name);
protected Builder newBuilder(String name, Map<String, Object> params) {
return new GeoPointFieldMapper.Builder(name);
}
@Override
public Builder parse(String name, Map<String, Object> node, Map<String, Object> params, ParserContext parserContext) {
Builder builder = super.parse(name, node, params, parserContext);
parseField(builder, name, node, parserContext);
Object nullValue = null;
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
@ -152,14 +114,7 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
String propName = entry.getKey();
Object propNode = entry.getValue();
if (propName.equals(Names.IGNORE_MALFORMED)) {
builder.ignoreMalformed(XContentMapValues.nodeBooleanValue(propNode, name + "." + Names.IGNORE_MALFORMED));
iterator.remove();
} else if (propName.equals(Names.IGNORE_Z_VALUE.getPreferredName())) {
builder.ignoreZValue(XContentMapValues.nodeBooleanValue(propNode,
name + "." + Names.IGNORE_Z_VALUE.getPreferredName()));
iterator.remove();
} else if (propName.equals(Names.NULL_VALUE)) {
if (Names.NULL_VALUE.match(propName, LoggingDeprecationHandler.INSTANCE)) {
if (propNode == null) {
throw new MapperParsingException("Property [null_value] cannot be null.");
}
@ -169,8 +124,8 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
}
if (nullValue != null) {
boolean ignoreZValue = builder.ignoreZValue == null ? Defaults.IGNORE_Z_VALUE.value() : builder.ignoreZValue;
boolean ignoreMalformed = builder.ignoreMalformed == null ? Defaults.IGNORE_MALFORMED.value() : builder.ignoreMalformed;
boolean ignoreZValue = builder.ignoreZValue().value();
boolean ignoreMalformed = builder.ignoreMalformed().value();
GeoPoint point = GeoUtils.parseGeoPoint(nullValue, ignoreZValue);
if (ignoreMalformed == false) {
if (point.lat() > 90.0 || point.lat() < -90.0) {
@ -188,27 +143,15 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
}
}
protected Explicit<Boolean> ignoreMalformed;
protected Explicit<Boolean> ignoreZValue;
public GeoPointFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Settings indexSettings, MultiFields multiFields, Explicit<Boolean> ignoreMalformed,
Explicit<Boolean> ignoreZValue, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo);
this.ignoreMalformed = ignoreMalformed;
this.ignoreZValue = ignoreZValue;
super(simpleName, fieldType, defaultFieldType, indexSettings, ignoreMalformed, ignoreZValue, multiFields, copyTo);
}
@Override
protected void doMerge(Mapper mergeWith) {
super.doMerge(mergeWith);
GeoPointFieldMapper gpfmMergeWith = (GeoPointFieldMapper) mergeWith;
if (gpfmMergeWith.ignoreMalformed.explicit()) {
this.ignoreMalformed = gpfmMergeWith.ignoreMalformed;
}
if (gpfmMergeWith.ignoreZValue.explicit()) {
this.ignoreZValue = gpfmMergeWith.ignoreZValue;
}
}
@Override
@ -216,13 +159,11 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
return CONTENT_TYPE;
}
@Override
protected void parseCreateField(ParseContext context, List<IndexableField> fields) throws IOException {
throw new UnsupportedOperationException("Parsing is implemented in parse(), this method should NEVER be called");
}
public static class GeoPointFieldType extends AbstractSearchableGeometryFieldType {
public static class GeoPointFieldType extends AbstractGeometryFieldType {
public GeoPointFieldType() {
super();
setHasDocValues(true);
setDimensions(2, Integer.BYTES);
}
GeoPointFieldType(GeoPointFieldType ref) {
@ -255,15 +196,9 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
if (hasDocValues()) {
return new DocValuesFieldExistsQuery(name());
} else {
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
return super.existsQuery(context);
}
}
@Override
public Query termQuery(Object value, QueryShardContext context) {
throw new QueryShardException(context, "Geo fields do not support exact searching, use dedicated geo queries instead: ["
+ name() + "]");
}
}
protected void parse(ParseContext context, GeoPoint point) throws IOException {
@ -364,24 +299,13 @@ public class GeoPointFieldMapper extends FieldMapper implements ArrayValueMapper
}
@Override
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || ignoreMalformed.explicit()) {
builder.field(Names.IGNORE_MALFORMED, ignoreMalformed.value());
}
if (includeDefaults || ignoreZValue.explicit()) {
builder.field(Names.IGNORE_Z_VALUE.getPreferredName(), ignoreZValue.value());
}
if (includeDefaults || fieldType().nullValue() != null) {
builder.field(Names.NULL_VALUE, fieldType().nullValue());
builder.field(Names.NULL_VALUE.getPreferredName(), fieldType().nullValue());
}
}
public Explicit<Boolean> ignoreZValue() {
return ignoreZValue;
}
private boolean isNormalizable(double coord) {
return Double.isNaN(coord) == false && Double.isInfinite(coord) == false;
}

View File

@ -48,10 +48,11 @@ import java.util.Map;
* <p>
* "field" : "POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))
*/
public class GeoShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geometry> {
public class GeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<Geometry, Geometry> {
public static final String CONTENT_TYPE = "geo_shape";
public static class Builder extends AbstractGeometryFieldMapper.Builder<AbstractGeometryFieldMapper.Builder, GeoShapeFieldMapper> {
public static class Builder extends AbstractShapeGeometryFieldMapper.Builder<AbstractShapeGeometryFieldMapper.Builder,
GeoShapeFieldMapper> {
public Builder(String name) {
super (name, new GeoShapeFieldType(), new GeoShapeFieldType());
}
@ -60,7 +61,7 @@ public class GeoShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, G
public GeoShapeFieldMapper build(BuilderContext context) {
setupFieldType(context);
return new GeoShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), coerce(context),
ignoreZValue(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo);
ignoreZValue(), orientation(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo);
}
@Override
@ -78,9 +79,10 @@ public class GeoShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, G
}
}
public static class GeoShapeFieldType extends AbstractGeometryFieldType<Geometry, Geometry> {
public static class GeoShapeFieldType extends AbstractShapeGeometryFieldType<Geometry, Geometry> {
public GeoShapeFieldType() {
super();
setDimensions(7, 4, Integer.BYTES);
}
protected GeoShapeFieldType(GeoShapeFieldType ref) {
@ -98,10 +100,10 @@ public class GeoShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, G
}
}
public static final class TypeParser extends AbstractGeometryFieldMapper.TypeParser {
public static final class TypeParser extends AbstractShapeGeometryFieldMapper.TypeParser {
@Override
protected AbstractGeometryFieldMapper.Builder newBuilder(String name, Map<String, Object> params) {
protected AbstractShapeGeometryFieldMapper.Builder newBuilder(String name, Map<String, Object> params) {
if (params.containsKey(DEPRECATED_PARAMETERS_KEY)) {
return new LegacyGeoShapeFieldMapper.Builder(name,
(LegacyGeoShapeFieldMapper.DeprecatedParameters)params.get(DEPRECATED_PARAMETERS_KEY));
@ -112,9 +114,9 @@ public class GeoShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, G
public GeoShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
Explicit<Boolean> ignoreZValue, Settings indexSettings,
Explicit<Boolean> ignoreZValue, Explicit<ShapeBuilder.Orientation> orientation, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings,
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, orientation, indexSettings,
multiFields, copyTo);
}

View File

@ -49,7 +49,7 @@ import static org.elasticsearch.common.geo.GeoUtils.normalizePoint;
/**
* Utility class that converts geometries into Lucene-compatible form for indexing in a geo_shape field.
*/
public class GeoShapeIndexer implements AbstractGeometryFieldMapper.Indexer<Geometry, Geometry> {
public class GeoShapeIndexer implements AbstractShapeGeometryFieldMapper.Indexer<Geometry, Geometry> {
private final boolean orientation;
private final String name;

View File

@ -74,7 +74,7 @@ import java.util.Objects;
* @deprecated use {@link GeoShapeFieldMapper}
*/
@Deprecated
public class LegacyGeoShapeFieldMapper extends AbstractGeometryFieldMapper<ShapeBuilder<?, ?, ?>, Shape> {
public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<ShapeBuilder<?, ?, ?>, Shape> {
public static final String CONTENT_TYPE = "geo_shape";
@ -178,7 +178,7 @@ public class LegacyGeoShapeFieldMapper extends AbstractGeometryFieldMapper<Shape
private static final Logger logger = LogManager.getLogger(LegacyGeoShapeFieldMapper.class);
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(logger);
public static class Builder extends AbstractGeometryFieldMapper.Builder<AbstractGeometryFieldMapper.Builder,
public static class Builder extends AbstractShapeGeometryFieldMapper.Builder<AbstractShapeGeometryFieldMapper.Builder,
LegacyGeoShapeFieldMapper> {
DeprecatedParameters deprecatedParameters;
@ -299,7 +299,7 @@ public class LegacyGeoShapeFieldMapper extends AbstractGeometryFieldMapper<Shape
}
}
public static final class GeoShapeFieldType extends AbstractGeometryFieldType {
public static final class GeoShapeFieldType extends AbstractShapeGeometryFieldType {
private String tree = DeprecatedParameters.Defaults.TREE;
private SpatialStrategy strategy = DeprecatedParameters.Defaults.STRATEGY;
@ -474,7 +474,7 @@ public class LegacyGeoShapeFieldMapper extends AbstractGeometryFieldMapper<Shape
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce, Explicit<Orientation> orientation,
Explicit<Boolean> ignoreZValue, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings,
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, orientation, indexSettings,
multiFields, copyTo);
}

View File

@ -30,7 +30,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LegacyGeoShapeIndexer implements AbstractGeometryFieldMapper.Indexer<ShapeBuilder<?, ?, ?>, Shape> {
public class LegacyGeoShapeIndexer implements AbstractShapeGeometryFieldMapper.Indexer<ShapeBuilder<?, ?, ?>, Shape> {
private LegacyGeoShapeFieldMapper.GeoShapeFieldType fieldType;

View File

@ -35,7 +35,7 @@ import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType;
import org.elasticsearch.index.mapper.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
@ -220,8 +220,8 @@ public class GeoShapeQueryBuilder extends AbstractGeometryQueryBuilder<GeoShapeQ
+ String.join(",", validContentTypes()) + "]");
}
final AbstractSearchableGeometryFieldType ft =
(AbstractSearchableGeometryFieldType) fieldType;
final AbstractGeometryFieldType ft =
(AbstractGeometryFieldType) fieldType;
return new ConstantScoreQuery(ft.geometryQueryBuilder().process(shape, fieldName, strategy, relation, context));
}

View File

@ -52,8 +52,8 @@ import org.elasticsearch.geometry.MultiPolygon;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType.QueryProcessor;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.spatial4j.shape.Shape;
@ -63,11 +63,11 @@ import java.util.List;
import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
public class LegacyGeoShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
public class LegacyGeoShapeQueryProcessor implements QueryProcessor {
private AbstractGeometryFieldMapper.AbstractGeometryFieldType ft;
private AbstractShapeGeometryFieldMapper.AbstractShapeGeometryFieldType ft;
public LegacyGeoShapeQueryProcessor(AbstractGeometryFieldMapper.AbstractGeometryFieldType ft) {
public LegacyGeoShapeQueryProcessor(AbstractShapeGeometryFieldMapper.AbstractShapeGeometryFieldType ft) {
this.ft = ft;
}

View File

@ -41,13 +41,13 @@ import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.geometry.ShapeType;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType.QueryProcessor;
import org.elasticsearch.index.mapper.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import java.util.ArrayList;
public class VectorGeoPointShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
public class VectorGeoPointShapeQueryProcessor implements QueryProcessor {
@Override
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {

View File

@ -40,14 +40,14 @@ import org.elasticsearch.geometry.MultiPolygon;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType.QueryProcessor;
import java.util.ArrayList;
import java.util.List;
public class VectorGeoShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
public class VectorGeoShapeQueryProcessor implements QueryProcessor {
@Override
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {

View File

@ -88,7 +88,7 @@ public class ExternalMapper extends FieldMapper {
BinaryFieldMapper binMapper = binBuilder.build(context);
BooleanFieldMapper boolMapper = boolBuilder.build(context);
GeoPointFieldMapper pointMapper = latLonPointBuilder.build(context);
AbstractGeometryFieldMapper shapeMapper = (context.indexCreatedVersion().before(Version.V_6_6_0))
AbstractShapeGeometryFieldMapper shapeMapper = (context.indexCreatedVersion().before(Version.V_6_6_0))
? legacyShapeBuilder.build(context)
: shapeBuilder.build(context);
FieldMapper stringMapper = (FieldMapper)stringBuilder.build(context);
@ -154,13 +154,13 @@ public class ExternalMapper extends FieldMapper {
private BinaryFieldMapper binMapper;
private BooleanFieldMapper boolMapper;
private GeoPointFieldMapper pointMapper;
private AbstractGeometryFieldMapper shapeMapper;
private AbstractShapeGeometryFieldMapper shapeMapper;
private FieldMapper stringMapper;
public ExternalMapper(String simpleName, MappedFieldType fieldType,
String generatedValue, String mapperName,
BinaryFieldMapper binMapper, BooleanFieldMapper boolMapper, GeoPointFieldMapper pointMapper,
AbstractGeometryFieldMapper shapeMapper, FieldMapper stringMapper, Settings indexSettings,
AbstractShapeGeometryFieldMapper shapeMapper, FieldMapper stringMapper, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, new ExternalFieldType(), indexSettings, multiFields, copyTo);
this.generatedValue = generatedValue;
@ -218,7 +218,8 @@ public class ExternalMapper extends FieldMapper {
BinaryFieldMapper binMapperUpdate = (BinaryFieldMapper) binMapper.updateFieldType(fullNameToFieldType);
BooleanFieldMapper boolMapperUpdate = (BooleanFieldMapper) boolMapper.updateFieldType(fullNameToFieldType);
GeoPointFieldMapper pointMapperUpdate = (GeoPointFieldMapper) pointMapper.updateFieldType(fullNameToFieldType);
AbstractGeometryFieldMapper shapeMapperUpdate = (AbstractGeometryFieldMapper) shapeMapper.updateFieldType(fullNameToFieldType);
AbstractShapeGeometryFieldMapper shapeMapperUpdate =
(AbstractShapeGeometryFieldMapper) shapeMapper.updateFieldType(fullNameToFieldType);
TextFieldMapper stringMapperUpdate = (TextFieldMapper) stringMapper.updateFieldType(fullNameToFieldType);
if (update == this
&& multiFieldsUpdate == multiFields

View File

@ -387,7 +387,7 @@ public class GeoPointFieldMapperTests extends ESSingleNodeTestCase {
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("location")
.field("type", "geo_point")
.field(NULL_VALUE, "1,2")
.field(NULL_VALUE.getPreferredName(), "1,2")
.endObject().endObject()
.endObject().endObject());
@ -439,8 +439,8 @@ public class GeoPointFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("location")
.field("type", "geo_point")
.field(IGNORE_Z_VALUE.getPreferredName(), false)
.field(IGNORE_MALFORMED, true)
.field(NULL_VALUE, "91,181")
.field(IGNORE_MALFORMED.getPreferredName(), true)
.field(NULL_VALUE.getPreferredName(), "91,181")
.endObject().endObject()
.endObject().endObject());

View File

@ -283,7 +283,7 @@ public class GeoShapeFieldMapperTests extends ESSingleNodeTestCase {
DocumentMapper defaultMapper = parser.parse("type1", new CompressedXContent(mapping));
String serialized = toXContentString((GeoShapeFieldMapper) defaultMapper.mappers().getMapper("location"));
assertTrue(serialized, serialized.contains("\"orientation\":\"" +
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
AbstractShapeGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
}
}

View File

@ -304,7 +304,8 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase<MatchQueryBuil
MatchQueryBuilder query = new MatchQueryBuilder(GEO_POINT_FIELD_NAME, "2,3");
QueryShardContext context = createShardContext();
QueryShardException e = expectThrows(QueryShardException.class, () -> query.toQuery(context));
assertEquals("Geo fields do not support exact searching, use dedicated geo queries instead: [mapped_geo_point]", e.getMessage());
assertEquals("Geometry fields do not support exact searching, use dedicated geometry queries instead: " +
"[mapped_geo_point]", e.getMessage());
query.lenient(true);
query.toQuery(context); // no exception
}

View File

@ -827,8 +827,8 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
QueryShardContext context = createShardContext();
QueryShardException e = expectThrows(QueryShardException.class,
() -> query.toQuery(context));
assertEquals("Geo fields do not support exact searching, use dedicated geo queries instead: [mapped_geo_point]",
e.getMessage());
assertEquals("Geometry fields do not support exact searching, use dedicated geometry queries instead: "
+ "[mapped_geo_point]", e.getMessage());
query.lenient(true);
query.toQuery(context); // no exception
}

View File

@ -138,8 +138,8 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
TermQueryBuilder query = new TermQueryBuilder(GEO_POINT_FIELD_NAME, "2,3");
QueryShardContext context = createShardContext();
QueryShardException e = expectThrows(QueryShardException.class, () -> query.toQuery(context));
assertEquals("Geo fields do not support exact searching, use dedicated geo queries instead: [mapped_geo_point]",
e.getMessage());
assertEquals("Geometry fields do not support exact searching, "
+ "use dedicated geometry queries instead: [mapped_geo_point]", e.getMessage());
}
public void testParseFailsWithMultipleFields() throws IOException {

View File

@ -293,8 +293,8 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
QueryShardContext context = createShardContext();
QueryShardException e = expectThrows(QueryShardException.class,
() -> query.toQuery(context));
assertEquals("Geo fields do not support exact searching, use dedicated geo queries instead: [mapped_geo_point]",
e.getMessage());
assertEquals("Geometry fields do not support exact searching, use dedicated geometry queries instead: "
+ "[mapped_geo_point]", e.getMessage());
}
public void testSerializationFailsUnlessFetched() throws IOException {

View File

@ -129,7 +129,7 @@ public class GeoDistanceSortBuilderTests extends AbstractSortTestCase<GeoDistanc
@Override
protected MappedFieldType provideMappedFieldType(String name) {
MappedFieldType clone = GeoPointFieldMapper.Defaults.FIELD_TYPE.clone();
MappedFieldType clone = new GeoPointFieldMapper.GeoPointFieldType();
clone.setName(name);
return clone;
}

View File

@ -19,17 +19,15 @@ import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.geo.GeometryParser;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
import org.elasticsearch.index.mapper.GeoShapeIndexer;
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TypeParsers;
@ -40,7 +38,6 @@ import org.elasticsearch.xpack.spatial.index.fielddata.AbstractLatLonShapeDVInde
import org.elasticsearch.xpack.spatial.index.fielddata.CentroidCalculator;
import org.elasticsearch.xpack.spatial.search.aggregations.support.GeoShapeValuesSourceType;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -74,16 +71,8 @@ public class GeoShapeWithDocValuesFieldMapper extends GeoShapeFieldMapper {
private Explicit<Boolean> docValues;
@Override
public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || docValues.explicit()) {
builder.field(TypeParsers.DOC_VALUES, docValues.value());
}
}
@SuppressWarnings("rawtypes")
public static class Builder extends AbstractGeometryFieldMapper.Builder<AbstractGeometryFieldMapper.Builder,
public static class Builder extends AbstractShapeGeometryFieldMapper.Builder<AbstractShapeGeometryFieldMapper.Builder,
GeoShapeWithDocValuesFieldMapper> {
public Builder(String name) {
super (name, new GeoShapeWithDocValuesFieldType(), new GeoShapeWithDocValuesFieldType());
@ -93,7 +82,7 @@ public class GeoShapeWithDocValuesFieldMapper extends GeoShapeFieldMapper {
public GeoShapeWithDocValuesFieldMapper build(BuilderContext context) {
setupFieldType(context);
return new GeoShapeWithDocValuesFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), coerce(context),
ignoreZValue(), docValues(), context.indexSettings(),
ignoreZValue(), orientation(), docValues(), context.indexSettings(),
multiFieldsBuilder.build(this, context), copyTo);
}
@ -185,11 +174,11 @@ public class GeoShapeWithDocValuesFieldMapper extends GeoShapeFieldMapper {
}
}
public static final class TypeParser extends AbstractGeometryFieldMapper.TypeParser {
public static final class TypeParser extends AbstractShapeGeometryFieldMapper.TypeParser {
@Override
@SuppressWarnings("rawtypes")
protected AbstractGeometryFieldMapper.Builder newBuilder(String name, Map<String, Object> params) {
protected AbstractShapeGeometryFieldMapper.Builder newBuilder(String name, Map<String, Object> params) {
if (params.containsKey(DEPRECATED_PARAMETERS_KEY)) {
return new LegacyGeoShapeFieldMapper.Builder(name,
(LegacyGeoShapeFieldMapper.DeprecatedParameters)params.get(DEPRECATED_PARAMETERS_KEY));
@ -199,8 +188,9 @@ public class GeoShapeWithDocValuesFieldMapper extends GeoShapeFieldMapper {
@Override
@SuppressWarnings("rawtypes")
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
AbstractGeometryFieldMapper.Builder builder = (AbstractGeometryFieldMapper.Builder) super.parse(name, node, parserContext);
public AbstractShapeGeometryFieldMapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
AbstractShapeGeometryFieldMapper.Builder builder = super.parse(name, node, parserContext);
Map<String, Object> params = new HashMap<>();
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, Object> entry = iterator.next();
@ -221,9 +211,10 @@ public class GeoShapeWithDocValuesFieldMapper extends GeoShapeFieldMapper {
public GeoShapeWithDocValuesFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
Explicit<Boolean> ignoreZValue, Explicit<Boolean> docValues, Settings indexSettings,
Explicit<Boolean> ignoreZValue, Explicit<ShapeBuilder.Orientation> orientation,
Explicit<Boolean> docValues, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings,
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, orientation, indexSettings,
multiFields, copyTo);
this.docValues = docValues;
}

View File

@ -10,28 +10,19 @@ import org.apache.lucene.document.XYDocValuesField;
import org.apache.lucene.document.XYPointField;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.ArrayValueMapperParser;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
import org.elasticsearch.index.mapper.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.xpack.spatial.common.CartesianPoint;
import org.elasticsearch.xpack.spatial.index.query.ShapeQueryPointProcessor;
@ -49,63 +40,19 @@ import static org.elasticsearch.index.mapper.TypeParsers.parseField;
*
* Uses lucene 8 XYPoint encoding
*/
public class PointFieldMapper extends FieldMapper implements ArrayValueMapperParser {
public class PointFieldMapper extends AbstractGeometryFieldMapper implements ArrayValueMapperParser {
public static final String CONTENT_TYPE = "point";
public static class Names {
public static final ParseField IGNORE_MALFORMED = new ParseField("ignore_malformed");
public static final ParseField IGNORE_Z_VALUE = new ParseField("ignore_z_value");
public static class Names extends AbstractGeometryFieldMapper.Names {
public static final ParseField NULL_VALUE = new ParseField("null_value");
}
public static class Defaults {
public static final Explicit<Boolean> IGNORE_MALFORMED = new Explicit<>(false, false);
public static final PointFieldType FIELD_TYPE = new PointFieldType();
public static final Explicit<Boolean> IGNORE_Z_VALUE = new Explicit<>(true, false);
static {
FIELD_TYPE.setTokenized(false);
FIELD_TYPE.setHasDocValues(true);
FIELD_TYPE.setDimensions(2, Integer.BYTES);
FIELD_TYPE.freeze();
}
}
public static class Builder extends FieldMapper.Builder<Builder, PointFieldMapper> {
protected Boolean ignoreMalformed;
private Boolean ignoreZValue;
public static class Builder extends AbstractGeometryFieldMapper.Builder<Builder, PointFieldMapper> {
public Builder(String name) {
super(name, Defaults.FIELD_TYPE, Defaults.FIELD_TYPE);
super(name, new PointFieldType(), new PointFieldType());
builder = this;
}
public Builder ignoreMalformed(boolean ignoreMalformed) {
this.ignoreMalformed = ignoreMalformed;
return builder;
}
protected Explicit<Boolean> ignoreMalformed(BuilderContext context) {
if (ignoreMalformed != null) {
return new Explicit<>(ignoreMalformed, true);
}
if (context.indexSettings() != null) {
return new Explicit<>(IGNORE_MALFORMED_SETTING.get(context.indexSettings()), false);
}
return PointFieldMapper.Defaults.IGNORE_MALFORMED;
}
protected Explicit<Boolean> ignoreZValue(BuilderContext context) {
if (ignoreZValue != null) {
return new Explicit<>(ignoreZValue, true);
}
return PointFieldMapper.Defaults.IGNORE_Z_VALUE;
}
public PointFieldMapper.Builder ignoreZValue(final boolean ignoreZValue) {
this.ignoreZValue = ignoreZValue;
return this;
}
public PointFieldMapper build(BuilderContext context, String simpleName, MappedFieldType fieldType,
MappedFieldType defaultFieldType, Settings indexSettings,
MultiFields multiFields, Explicit<Boolean> ignoreMalformed,
@ -134,12 +81,16 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
}
}
public static class TypeParser implements Mapper.TypeParser {
public static class TypeParser extends AbstractGeometryFieldMapper.TypeParser<Builder> {
@Override
protected Builder newBuilder(String name, Map<String, Object> params) {
return new PointFieldMapper.Builder(name);
}
@Override
@SuppressWarnings("rawtypes")
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
Builder builder = new PointFieldMapper.Builder(name);
public Builder parse(String name, Map<String, Object> node, Map<String, Object> params, ParserContext parserContext) {
Builder builder = super.parse(name, node, params, parserContext);
parseField(builder, name, node, parserContext);
Object nullValue = null;
for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext();) {
@ -147,14 +98,7 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
String propName = entry.getKey();
Object propNode = entry.getValue();
if (propName.equals(Names.IGNORE_MALFORMED.getPreferredName())) {
builder.ignoreMalformed(XContentMapValues.nodeBooleanValue(propNode, name + "." + Names.IGNORE_MALFORMED));
iterator.remove();
} else if (propName.equals(PointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName())) {
builder.ignoreZValue(XContentMapValues.nodeBooleanValue(propNode,
name + "." + PointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName()));
iterator.remove();
} else if (propName.equals(Names.NULL_VALUE.getPreferredName())) {
if (Names.NULL_VALUE.match(propName, LoggingDeprecationHandler.INSTANCE)) {
if (propNode == null) {
throw new MapperParsingException("Property [null_value] cannot be null.");
}
@ -164,10 +108,8 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
}
if (nullValue != null) {
boolean ignoreMalformed = builder.ignoreMalformed == null ?
Defaults.IGNORE_MALFORMED.value() : builder.ignoreMalformed;
boolean ignoreZValue = builder.ignoreZValue == null ?
Defaults.IGNORE_Z_VALUE.value() : builder.ignoreZValue;
boolean ignoreMalformed = builder.ignoreMalformed().value();
boolean ignoreZValue = builder.ignoreZValue().value();
CartesianPoint point = CartesianPoint.parsePoint(nullValue, ignoreZValue);
if (ignoreMalformed == false) {
if (Float.isFinite(point.getX()) == false) {
@ -183,27 +125,15 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
}
}
protected Explicit<Boolean> ignoreMalformed;
protected Explicit<Boolean> ignoreZValue;
public PointFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Settings indexSettings, MultiFields multiFields, Explicit<Boolean> ignoreMalformed,
Explicit<Boolean> ignoreZValue, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo);
this.ignoreMalformed = ignoreMalformed;
this.ignoreZValue = ignoreZValue;
super(simpleName, fieldType, defaultFieldType, indexSettings, ignoreMalformed, ignoreZValue, multiFields, copyTo);
}
@Override
protected void doMerge(Mapper mergeWith) {
super.doMerge(mergeWith);
PointFieldMapper gpfmMergeWith = (PointFieldMapper) mergeWith;
if (gpfmMergeWith.ignoreMalformed.explicit()) {
this.ignoreMalformed = gpfmMergeWith.ignoreMalformed;
}
if (gpfmMergeWith.ignoreZValue.explicit()) {
this.ignoreZValue = gpfmMergeWith.ignoreZValue;
}
}
@Override
@ -211,13 +141,11 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
return CONTENT_TYPE;
}
@Override
protected void parseCreateField(ParseContext context, List<IndexableField> fields) throws IOException {
throw new UnsupportedOperationException("Parsing is implemented in parse(), this method should NEVER be called");
}
public static class PointFieldType extends AbstractSearchableGeometryFieldType {
public static class PointFieldType extends AbstractGeometryFieldType {
public PointFieldType() {
super();
setHasDocValues(true);
setDimensions(2, Integer.BYTES);
}
PointFieldType(PointFieldType ref) {
@ -233,21 +161,6 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
public MappedFieldType clone() {
return new PointFieldType(this);
}
@Override
public Query existsQuery(QueryShardContext context) {
if (hasDocValues()) {
return new DocValuesFieldExistsQuery(name());
} else {
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
}
}
@Override
public Query termQuery(Object value, QueryShardContext context) {
throw new QueryShardException(context, "Spatial fields do not support exact searching, " +
"use dedicated spatial queries instead: [" + name() + "]");
}
}
protected void parse(ParseContext context, CartesianPoint point) throws IOException {
@ -334,20 +247,10 @@ public class PointFieldMapper extends FieldMapper implements ArrayValueMapperPar
}
@Override
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
public void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || ignoreMalformed.explicit()) {
builder.field(Names.IGNORE_MALFORMED.getPreferredName(), ignoreMalformed.value());
}
if (includeDefaults || ignoreZValue.explicit()) {
builder.field(GeoPointFieldMapper.Names.IGNORE_Z_VALUE.getPreferredName(), ignoreZValue.value());
}
if (includeDefaults || fieldType().nullValue() != null) {
builder.field(Names.NULL_VALUE.getPreferredName(), fieldType().nullValue());
}
}
public Explicit<Boolean> ignoreZValue() {
return ignoreZValue;
}
}

View File

@ -8,10 +8,10 @@ package org.elasticsearch.xpack.spatial.index.mapper;
import org.apache.lucene.document.XYShape;
import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.geo.GeometryParser;
import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.geo.builders.ShapeBuilder.Orientation;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.xpack.spatial.index.query.ShapeQueryProcessor;
@ -34,15 +34,16 @@ import java.util.Map;
* <p>
* "field" : "POLYGON ((1050.0 -1000.0, 1051.0 -1000.0, 1051.0 -1001.0, 1050.0 -1001.0, 1050.0 -1000.0))
*/
public class ShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geometry> {
public class ShapeFieldMapper extends AbstractShapeGeometryFieldMapper<Geometry, Geometry> {
public static final String CONTENT_TYPE = "shape";
public static class Defaults extends AbstractGeometryFieldMapper.Defaults {
public static class Defaults extends AbstractShapeGeometryFieldMapper.Defaults {
public static final ShapeFieldType FIELD_TYPE = new ShapeFieldType();
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static class Builder extends AbstractGeometryFieldMapper.Builder<AbstractGeometryFieldMapper.Builder, ShapeFieldMapper> {
public static class Builder extends AbstractShapeGeometryFieldMapper.Builder<AbstractShapeGeometryFieldMapper.Builder,
ShapeFieldMapper> {
public Builder(String name) {
super(name, Defaults.FIELD_TYPE, Defaults.FIELD_TYPE);
@ -53,7 +54,7 @@ public class ShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geom
public ShapeFieldMapper build(BuilderContext context) {
setupFieldType(context);
return new ShapeFieldMapper(name, fieldType, defaultFieldType, ignoreMalformed(context), coerce(context),
ignoreZValue(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo);
ignoreZValue(), orientation(), context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo);
}
@Override
@ -66,7 +67,7 @@ public class ShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geom
protected void setupFieldType(BuilderContext context) {
super.setupFieldType(context);
GeometryParser geometryParser = new GeometryParser(orientation == ShapeBuilder.Orientation.RIGHT,
GeometryParser geometryParser = new GeometryParser(orientation == Orientation.RIGHT,
coerce(context).value(), ignoreZValue().value());
fieldType().setGeometryIndexer(new ShapeIndexer(fieldType().name()));
@ -75,7 +76,7 @@ public class ShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geom
}
}
public static class TypeParser extends AbstractGeometryFieldMapper.TypeParser {
public static class TypeParser extends AbstractShapeGeometryFieldMapper.TypeParser {
@Override
protected boolean parseXContentParameters(String name, Map.Entry<String, Object> entry,
Map<String, Object> params) throws MapperParsingException {
@ -89,9 +90,10 @@ public class ShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geom
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static final class ShapeFieldType extends AbstractGeometryFieldType {
public static final class ShapeFieldType extends AbstractShapeGeometryFieldType {
public ShapeFieldType() {
super();
setDimensions(7, 4, Integer.BYTES);
}
public ShapeFieldType(ShapeFieldType ref) {
@ -116,9 +118,9 @@ public class ShapeFieldMapper extends AbstractGeometryFieldMapper<Geometry, Geom
public ShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
Explicit<Boolean> ignoreZValue, Settings indexSettings,
MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, indexSettings,
Explicit<Boolean> ignoreZValue, Explicit<Orientation> orientation,
Settings indexSettings, MultiFields multiFields, CopyTo copyTo) {
super(simpleName, fieldType, defaultFieldType, ignoreMalformed, coerce, ignoreZValue, orientation, indexSettings,
multiFields, copyTo);
}

View File

@ -19,7 +19,7 @@ import org.elasticsearch.geometry.MultiPolygon;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.xpack.spatial.common.ShapeUtils;
@ -27,7 +27,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ShapeIndexer implements AbstractGeometryFieldMapper.Indexer<Geometry, Geometry> {
public class ShapeIndexer implements AbstractShapeGeometryFieldMapper.Indexer<Geometry, Geometry> {
private final String name;
public ShapeIndexer(String name) {

View File

@ -17,7 +17,7 @@ import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.query.AbstractGeometryQueryBuilder;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
@ -139,7 +139,7 @@ public class ShapeQueryBuilder extends AbstractGeometryQueryBuilder<ShapeQueryBu
+ "] but of type [" + fieldType.typeName() + "]");
}
final AbstractSearchableGeometryFieldType ft = (AbstractSearchableGeometryFieldType) fieldType;
final AbstractGeometryFieldType ft = (AbstractGeometryFieldType) fieldType;
return new ConstantScoreQuery(ft.geometryQueryBuilder().process(shape, ft.name(), relation, context));
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.geometry.ShapeType;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType.QueryProcessor;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
@ -34,7 +34,7 @@ import org.elasticsearch.xpack.spatial.index.mapper.PointFieldMapper;
import org.elasticsearch.xpack.spatial.common.ShapeUtils;
public class ShapeQueryPointProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
public class ShapeQueryPointProcessor implements QueryProcessor {
@Override
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {

View File

@ -23,7 +23,7 @@ import org.elasticsearch.geometry.MultiPolygon;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.mapper.AbstractSearchableGeometryFieldType;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper.AbstractGeometryFieldType.QueryProcessor;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
@ -34,7 +34,7 @@ import java.util.ArrayList;
import java.util.List;
public class ShapeQueryProcessor implements AbstractSearchableGeometryFieldType.QueryProcessor {
public class ShapeQueryProcessor implements QueryProcessor {
@Override
public Query process(Geometry shape, String fieldName, ShapeRelation relation, QueryShardContext context) {

View File

@ -32,7 +32,7 @@ import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.Mapper;
@ -361,7 +361,7 @@ public class GeoShapeWithDocValuesFieldMapperTests extends ESSingleNodeTestCase
DocumentMapper defaultMapper = parser.parse("type1", new CompressedXContent(mapping));
String serialized = toXContentString((GeoShapeWithDocValuesFieldMapper) defaultMapper.mappers().getMapper("location"));
assertTrue(serialized, serialized.contains("\"orientation\":\"" +
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
AbstractShapeGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
assertTrue(serialized, serialized.contains("\"doc_values\":true"));
}
}
@ -378,7 +378,7 @@ public class GeoShapeWithDocValuesFieldMapperTests extends ESSingleNodeTestCase
DocumentMapper mapper = parser.parse("type1", new CompressedXContent(mapping));
String serialized = toXContentString((GeoShapeWithDocValuesFieldMapper) mapper.mappers().getMapper("location"));
assertTrue(serialized, serialized.contains("\"orientation\":\"" +
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
AbstractShapeGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
assertTrue(serialized, serialized.contains("\"doc_values\":" + docValues));
}

View File

@ -12,7 +12,7 @@ import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.Mapper;
@ -273,7 +273,7 @@ public class ShapeFieldMapperTests extends CartesianFieldMapperTests {
DocumentMapper defaultMapper = parser.parse("type1", new CompressedXContent(mapping));
String serialized = toXContentString((ShapeFieldMapper) defaultMapper.mappers().getMapper("location"));
assertTrue(serialized, serialized.contains("\"orientation\":\"" +
AbstractGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
AbstractShapeGeometryFieldMapper.Defaults.ORIENTATION.value() + "\""));
}
}