diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java index a46144bd1530a..d4a5ff6abf75b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java @@ -35,9 +35,9 @@ import org.elasticsearch.cluster.routing.ShardsIterator; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.CheckedBiFunction; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.xcontent.ParseField; import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.StreamInput; @@ -52,7 +52,6 @@ import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.geometry.Geometry; import org.elasticsearch.geometry.Point; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexService; @@ -602,12 +601,9 @@ static Response innerShardOperation(Request request, ScriptService scriptService List points = new ArrayList<>(); geoPointFieldScript.runGeoPointForDoc(0, gp -> points.add(new GeoPoint(gp))); // convert geo points to the standard format of the fields api - Function format = GeoFormatterFactory.getFormatter(GeoFormatterFactory.GEOJSON); - List objects = new ArrayList<>(); - for (GeoPoint gp : points) { - objects.add(format.apply(new Point(gp.getLon(), gp.getLat()))); - } - return new Response(objects); + Function, List> format = + GeometryFormatterFactory.getFormatter(GeometryFormatterFactory.GEOJSON, p -> new Point(p.lon(), p.lat())); + return new Response(format.apply(points)); }, indexService); } else if (scriptContext == IpFieldScript.CONTEXT) { return prepareRamIndex(request, (context, leafReaderContext) -> { diff --git a/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java b/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java deleted file mode 100644 index ab64b92859580..0000000000000 --- a/server/src/main/java/org/elasticsearch/common/geo/GeoFormatterFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -package org.elasticsearch.common.geo; - -import org.elasticsearch.geometry.Geometry; -import org.elasticsearch.geometry.utils.WellKnownText; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -/** - * Output formatters supported by geo fields. - */ -public class GeoFormatterFactory { - - public static final String GEOJSON = "geojson"; - public static final String WKT = "wkt"; - - private static final Map> FORMATTERS = new HashMap<>(); - static { - FORMATTERS.put(GEOJSON, GeoJson::toMap); - FORMATTERS.put(WKT, WellKnownText::toWKT); - } - - /** - * Returns a formatter by name - */ - public static Function getFormatter(String name) { - Function format = FORMATTERS.get(name); - if (format == null) { - throw new IllegalArgumentException("Unrecognized geometry format [" + name + "]."); - } - return format; - } -} diff --git a/server/src/main/java/org/elasticsearch/common/geo/GeometryFormatterFactory.java b/server/src/main/java/org/elasticsearch/common/geo/GeometryFormatterFactory.java new file mode 100644 index 0000000000000..21785bf549f0a --- /dev/null +++ b/server/src/main/java/org/elasticsearch/common/geo/GeometryFormatterFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.common.geo; + +import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.utils.WellKnownText; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +/** + * Output formatters supported by geometry fields. + */ +public class GeometryFormatterFactory { + + public static final String GEOJSON = "geojson"; + public static final String WKT = "wkt"; + + /** + * Returns a formatter by name + */ + public static Function, List> getFormatter(String name, Function toGeometry) { + switch (name) { + case GEOJSON: + return geometries -> { + final List objects = new ArrayList<>(geometries.size()); + geometries.forEach((shape) -> objects.add(GeoJson.toMap(toGeometry.apply(shape)))); + return objects; + }; + case WKT: + return geometries -> { + final List objects = new ArrayList<>(geometries.size()); + geometries.forEach((shape) -> objects.add(WellKnownText.toWKT(toGeometry.apply(shape)))); + return objects; + }; + default: throw new IllegalArgumentException("Unrecognized geometry format [" + name + "]."); + } + } +} diff --git a/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java index 0742c2a234082..0a6d70bf7536e 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/AbstractGeometryFieldMapper.java @@ -9,7 +9,7 @@ import org.apache.lucene.search.Query; import org.elasticsearch.common.Explicit; -import org.elasticsearch.common.geo.GeoFormatterFactory; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.support.MapXContentParser; import org.elasticsearch.core.CheckedConsumer; @@ -52,13 +52,14 @@ public abstract void parse( CheckedConsumer consumer, Consumer onMalformed) throws IOException; - private void fetchFromSource(Object sourceMap, Consumer consumer, Function formatter) { + private void fetchFromSource(Object sourceMap, Consumer consumer) { try (XContentParser parser = MapXContentParser.wrapObject(sourceMap)) { - parse(parser, v -> consumer.accept(formatter.apply(v)), e -> {}); /* ignore malformed */ + parse(parser, v -> consumer.accept(v), e -> {}); /* ignore malformed */ } catch (IOException e) { throw new UncheckedIOException(e); } } + } public abstract static class AbstractGeometryFieldType extends MappedFieldType { @@ -80,17 +81,17 @@ public final Query termQuery(Object value, SearchExecutionContext context) { /** * Gets the formatter by name. */ - protected abstract Function getFormatter(String format); + protected abstract Function, List> getFormatter(String format); @Override public ValueFetcher valueFetcher(SearchExecutionContext context, String format) { - Function formatter = getFormatter(format != null ? format : GeoFormatterFactory.GEOJSON); + Function, List> formatter = getFormatter(format != null ? format : GeometryFormatterFactory.GEOJSON); return new ArraySourceValueFetcher(name(), context) { @Override protected Object parseSourceValue(Object value) { - List values = new ArrayList<>(); - geometryParser.fetchFromSource(value, values::add, formatter); - return values; + final List values = new ArrayList<>(); + geometryParser.fetchFromSource(value, values::add); + return formatter.apply(values); } }; } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java index 121b0eb0da2b4..e53e738a6df4e 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java @@ -19,10 +19,10 @@ import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.CheckedBiFunction; import org.elasticsearch.common.Explicit; -import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoShapeUtils; import org.elasticsearch.common.geo.GeoUtils; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.xcontent.XContentParser; @@ -242,9 +242,8 @@ public String typeName() { } @Override - protected Function getFormatter(String format) { - Function formatter = GeoFormatterFactory.getFormatter(format); - return (point) -> formatter.apply(new Point(point.lon(), point.lat())); + protected Function, List> getFormatter(String format) { + return GeometryFormatterFactory.getFormatter(format, p -> new Point(p.lon(), p.lat())); } @Override @@ -252,8 +251,8 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format) if (scriptValues == null) { return super.valueFetcher(context, format); } - Function formatter = getFormatter(format != null ? format : GeoFormatterFactory.GEOJSON); - return FieldValues.valueFetcher(scriptValues, v -> formatter.apply((GeoPoint) v), context); + Function, List> formatter = getFormatter(format != null ? format : GeometryFormatterFactory.GEOJSON); + return FieldValues.valueListFetcher(scriptValues, formatter, context); } @Override diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java index 7b06383effeb5..82c698134399f 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java @@ -13,8 +13,8 @@ import org.apache.lucene.search.Query; import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; -import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoShapeUtils; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.GeometryParser; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.Orientation; @@ -140,8 +140,8 @@ public Query geoShapeQuery(Geometry shape, String fieldName, ShapeRelation relat } @Override - protected Function getFormatter(String format) { - return GeoFormatterFactory.getFormatter(format); + protected Function, List> getFormatter(String format) { + return GeometryFormatterFactory.getFormatter(format, Function.identity()); } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java index 961847aea2074..96a369305b27a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/LegacyGeoShapeFieldMapper.java @@ -18,8 +18,8 @@ import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; -import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoUtils; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.ShapesAvailability; import org.elasticsearch.common.geo.SpatialStrategy; @@ -441,9 +441,8 @@ public PrefixTreeStrategy resolvePrefixTreeStrategy(String strategyName) { } @Override - protected Function, Object> getFormatter(String format) { - Function formatter = GeoFormatterFactory.getFormatter(format); - return (g) -> formatter.apply(g.buildGeometry()); + protected Function>, List> getFormatter(String format) { + return GeometryFormatterFactory.getFormatter(format, ShapeBuilder::buildGeometry); } } diff --git a/server/src/main/java/org/elasticsearch/search/lookup/FieldValues.java b/server/src/main/java/org/elasticsearch/search/lookup/FieldValues.java index c0efd774d5bd6..638ae5706897d 100644 --- a/server/src/main/java/org/elasticsearch/search/lookup/FieldValues.java +++ b/server/src/main/java/org/elasticsearch/search/lookup/FieldValues.java @@ -70,4 +70,35 @@ public List fetchValues(SourceLookup lookup) { } }; } + + /** + * Creates a {@link ValueFetcher} that fetches values from a {@link FieldValues} instance + * @param fieldValues the source of the values + * @param formatter a function to format the list values + * @param context the search execution context + * @return the value fetcher + */ + static ValueFetcher valueListFetcher(FieldValues fieldValues, Function, List> formatter, + SearchExecutionContext context) { + return new ValueFetcher() { + LeafReaderContext ctx; + + @Override + public void setNextReader(LeafReaderContext context) { + this.ctx = context; + } + + @Override + public List fetchValues(SourceLookup lookup) { + List values = new ArrayList<>(); + try { + fieldValues.valuesForDoc(context.lookup(), ctx, lookup.docId(), v -> values.add(v)); + } catch (Exception e) { + // ignore errors - if they exist here then they existed at index time + // and so on_script_error must have been set to `ignore` + } + return formatter.apply(values); + } + }; + } } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/common/CartesianFormatterFactory.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/common/CartesianFormatterFactory.java deleted file mode 100644 index b941845b08f38..0000000000000 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/common/CartesianFormatterFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -package org.elasticsearch.xpack.spatial.common; - -import org.elasticsearch.common.geo.GeoJson; -import org.elasticsearch.geometry.Geometry; -import org.elasticsearch.geometry.utils.WellKnownText; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -/** - * Output formatters supported by cartesian fields. - */ -public class CartesianFormatterFactory { - - public static final String GEOJSON = "geojson"; - public static final String WKT = "wkt"; - - private static final Map> FORMATTERS = new HashMap<>(); - static { - FORMATTERS.put(GEOJSON, GeoJson::toMap); - FORMATTERS.put(WKT, WellKnownText::toWKT); - } - - /** - * Returns a formatter by name - */ - public static Function getFormatter(String name) { - Function format = FORMATTERS.get(name); - if (format == null) { - throw new IllegalArgumentException("Unrecognized geometry format [" + name + "]."); - } - return format; - } -} diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java index 93038f1140500..407785a4d22bd 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/GeoShapeWithDocValuesFieldMapper.java @@ -15,8 +15,8 @@ import org.apache.lucene.search.Query; import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; -import org.elasticsearch.common.geo.GeoFormatterFactory; import org.elasticsearch.common.geo.GeoShapeUtils; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.GeometryParser; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.Orientation; @@ -172,8 +172,8 @@ public Query geoShapeQuery(Geometry shape, String fieldName, ShapeRelation relat } @Override - protected Function getFormatter(String format) { - return GeoFormatterFactory.getFormatter(format); + protected Function, List> getFormatter(String format) { + return GeometryFormatterFactory.getFormatter(format, Function.identity()); } } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java index d34e20cfcfe88..ba945de5de1f4 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/PointFieldMapper.java @@ -12,6 +12,7 @@ import org.apache.lucene.search.Query; import org.elasticsearch.common.CheckedBiFunction; import org.elasticsearch.common.Explicit; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.logging.DeprecationCategory; import org.elasticsearch.common.logging.DeprecationLogger; @@ -25,7 +26,6 @@ import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.DocumentParserContext; import org.elasticsearch.index.query.SearchExecutionContext; -import org.elasticsearch.xpack.spatial.common.CartesianFormatterFactory; import org.elasticsearch.xpack.spatial.common.CartesianPoint; import org.elasticsearch.xpack.spatial.index.query.ShapeQueryPointProcessor; @@ -179,9 +179,8 @@ public Query shapeQuery(Geometry shape, String fieldName, ShapeRelation relation } @Override - protected Function getFormatter(String format) { - Function formatter = CartesianFormatterFactory.getFormatter(format); - return (point) -> formatter.apply(new Point(point.getX(), point.getY())); + protected Function, List> getFormatter(String format) { + return GeometryFormatterFactory.getFormatter(format, p -> new Point(p.getX(), p.getY())); } } diff --git a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java index 2f79ec4828fd6..5b5dc66aa00ad 100644 --- a/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java +++ b/x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/index/mapper/ShapeFieldMapper.java @@ -9,6 +9,7 @@ import org.apache.lucene.document.XYShape; import org.apache.lucene.search.Query; import org.elasticsearch.common.Explicit; +import org.elasticsearch.common.geo.GeometryFormatterFactory; import org.elasticsearch.common.geo.GeometryParser; import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.Orientation; @@ -23,7 +24,6 @@ import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.DocumentParserContext; import org.elasticsearch.index.query.SearchExecutionContext; -import org.elasticsearch.xpack.spatial.common.CartesianFormatterFactory; import org.elasticsearch.xpack.spatial.index.query.ShapeQueryProcessor; import java.io.IOException; @@ -124,8 +124,8 @@ public String typeName() { } @Override - protected Function getFormatter(String format) { - return CartesianFormatterFactory.getFormatter(format); + protected Function, List> getFormatter(String format) { + return GeometryFormatterFactory.getFormatter(format, Function.identity()); } }