Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add geo_shape mapper supporting doc-values in Spatial Plugin #55037

Merged
merged 13 commits into from
Apr 16, 2020
Merged
6 changes: 6 additions & 0 deletions distribution/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ configure(subprojects.findAll { ['archives', 'packages'].contains(it.name) }) {
excludePlatforms = []
}
from(buildModules) {
// geo registers the geo_shape mapper that is overridden by
// the geo_shape mapper registered in the x-pack-spatial plugin
if (oss == false) {
exclude "**/geo/**"
}

for (String excludePlatform : excludePlatforms) {
exclude "**/platform/${excludePlatform}/**"
}
Expand Down
4 changes: 4 additions & 0 deletions modules/geo/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ esplugin {
description 'Placeholder plugin for geospatial features in ES. only registers geo_shape field mapper for now'
classname 'org.elasticsearch.geo.GeoPlugin'
}

artifacts {
restTests(new File(projectDir, "src/test/resources/rest-api-spec/test"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

package org.elasticsearch.geo;

import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.plugins.MapperPlugin;
Expand All @@ -32,6 +31,6 @@ public class GeoPlugin extends Plugin implements MapperPlugin {

@Override
public Map<String, Mapper.TypeParser> getMappers() {
return Collections.singletonMap(GeoShapeFieldMapper.CONTENT_TYPE, new AbstractGeometryFieldMapper.TypeParser());
return Collections.singletonMap(GeoShapeFieldMapper.CONTENT_TYPE, new GeoShapeFieldMapper.TypeParser());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ public long readLong() throws IOException {
}
}

public void position(int newPosition) throws IOException {
buffer.position(newPosition);
}

public int position() throws IOException {
return buffer.position();
}

@Override
public void reset() throws IOException {
buffer.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ protected void setupFieldType(BuilderContext context) {

protected static final String DEPRECATED_PARAMETERS_KEY = "deprecated_parameters";

public static class TypeParser implements Mapper.TypeParser {
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(),
Expand All @@ -195,13 +197,6 @@ protected boolean parseXContentParameters(String name, Map.Entry<String, Object>
return false;
}

protected Builder newBuilder(String name, Map<String, Object> params) {
if (params.containsKey(DEPRECATED_PARAMETERS_KEY)) {
return new LegacyGeoShapeFieldMapper.Builder(name, (DeprecatedParameters)params.get(DEPRECATED_PARAMETERS_KEY));
}
return new GeoShapeFieldMapper.Builder(name);
}

@Override
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
Map<String, Object> params = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.query.VectorGeoShapeQueryProcessor;

import java.util.Map;

/**
* FieldMapper for indexing {@link LatLonShape}s.
* <p>
Expand Down Expand Up @@ -76,7 +78,7 @@ protected void setupFieldType(BuilderContext context) {
}
}

public static final class GeoShapeFieldType extends AbstractGeometryFieldType<Geometry, Geometry> {
public static class GeoShapeFieldType extends AbstractGeometryFieldType<Geometry, Geometry> {
public GeoShapeFieldType() {
super();
}
Expand All @@ -96,6 +98,18 @@ public String typeName() {
}
}

public static final class TypeParser extends AbstractGeometryFieldMapper.TypeParser {

@Override
protected AbstractGeometryFieldMapper.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));
}
return new GeoShapeFieldMapper.Builder(name);
}
}

public GeoShapeFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType,
Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
Explicit<Boolean> ignoreZValue, Settings indexSettings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
/**
* Utility class that converts geometries into Lucene-compatible form for indexing in a geo_shape field.
*/
public final class GeoShapeIndexer implements AbstractGeometryFieldMapper.Indexer<Geometry, Geometry> {
public class GeoShapeIndexer implements AbstractGeometryFieldMapper.Indexer<Geometry, Geometry> {

private final boolean orientation;
private final String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public String toString() {
};
}

static SortedBinaryDocValues replaceMissing(final SortedBinaryDocValues values, final BytesRef missing) {
public static SortedBinaryDocValues replaceMissing(final SortedBinaryDocValues values, final BytesRef missing) {
return new SortedBinaryDocValues() {

private int count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package org.elasticsearch.test;

import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.plugins.MapperPlugin;
Expand All @@ -40,7 +39,7 @@ public class TestGeoShapeFieldMapperPlugin extends Plugin implements MapperPlugi
@Override
public Map<String, Mapper.TypeParser> getMappers() {
Map<String, Mapper.TypeParser> mappers = new LinkedHashMap<>();
mappers.put(GeoShapeFieldMapper.CONTENT_TYPE, new AbstractGeometryFieldMapper.TypeParser());
mappers.put(GeoShapeFieldMapper.CONTENT_TYPE, new GeoShapeFieldMapper.TypeParser());
return Collections.unmodifiableMap(mappers);
}
}
21 changes: 15 additions & 6 deletions x-pack/plugin/spatial/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@ esplugin {
dependencies {
compileOnly project(path: xpackModule('core'), configuration: 'default')
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
testCompile project(path: ':modules:geo', configuration: 'runtime')
compile project(path: ':modules:geo', configuration: 'default')
restTestConfig project(path: ':modules:geo', configuration: 'restTests')
}

restResources {
restApi {
includeCore '_common', 'indices', 'index', 'search'
}
restTests {
includeCore 'geo_shape'
}
}

testClusters.integTest {
testDistribution = 'DEFAULT'
}

licenseHeaders {
// This class was sourced from apache lucene's sandbox module tests
excludes << 'org/apache/lucene/geo/XShapeTestUtil.java'
}

// xpack modules are installed in real clusters as the meta plugin, so
// installing them as individual plugins for integ tests doesn't make sense,
// so we disable integ tests
integTest.enabled = false
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,30 @@

import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.geo.GeoPlugin;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.ingest.Processor;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.IngestPlugin;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction;
import org.elasticsearch.xpack.spatial.index.mapper.GeoShapeWithDocValuesFieldMapper;
import org.elasticsearch.xpack.spatial.index.mapper.PointFieldMapper;
import org.elasticsearch.xpack.spatial.index.mapper.ShapeFieldMapper;
import org.elasticsearch.xpack.spatial.index.query.ShapeQueryBuilder;
import org.elasticsearch.xpack.spatial.ingest.CircleProcessor;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;

public class SpatialPlugin extends Plugin implements ActionPlugin, MapperPlugin, SearchPlugin, IngestPlugin {

public SpatialPlugin(Settings settings) {
}
public class SpatialPlugin extends GeoPlugin implements ActionPlugin, MapperPlugin, SearchPlugin, IngestPlugin {

@Override
public List<ActionPlugin.ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
Expand All @@ -44,9 +41,10 @@ public SpatialPlugin(Settings settings) {

@Override
public Map<String, Mapper.TypeParser> getMappers() {
Map<String, Mapper.TypeParser> mappers = new LinkedHashMap<>();
Map<String, Mapper.TypeParser> mappers = new HashMap<>(super.getMappers());
mappers.put(ShapeFieldMapper.CONTENT_TYPE, new ShapeFieldMapper.TypeParser());
mappers.put(PointFieldMapper.CONTENT_TYPE, new PointFieldMapper.TypeParser());
mappers.put(GeoShapeWithDocValuesFieldMapper.CONTENT_TYPE, new GeoShapeWithDocValuesFieldMapper.TypeParser());
return Collections.unmodifiableMap(mappers);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

package org.elasticsearch.xpack.spatial.index.mapper;

import org.apache.lucene.util.Accountable;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;

import java.util.Collection;
import java.util.Collections;

public abstract class AbstractAtomicGeoShapeShapeFieldData implements LeafGeoShapeFieldData {

@Override
public final SortedBinaryDocValues getBytesValues() {
throw new UnsupportedOperationException("scripts and term aggs are not supported by geo_shape doc values");
}

@Override
public final ScriptDocValues.BytesRefs getScriptValues() {
throw new UnsupportedOperationException("scripts are not supported by geo_shape doc values");
}

public static LeafGeoShapeFieldData empty(final int maxDoc) {
return new AbstractAtomicGeoShapeShapeFieldData() {

@Override
public long ramBytesUsed() {
return 0;
}

@Override
public Collection<Accountable> getChildResources() {
return Collections.emptyList();
}

@Override
public void close() {
}

@Override
public MultiGeoShapeValues getGeoShapeValues() {
return MultiGeoShapeValues.EMPTY;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

package org.elasticsearch.xpack.spatial.index.mapper;

import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.SortField;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
import org.elasticsearch.index.fielddata.plain.DocValuesIndexFieldData;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.MultiValueMode;
import org.elasticsearch.search.sort.BucketedSort;
import org.elasticsearch.search.sort.SortOrder;

public abstract class AbstractLatLonShapeDVIndexFieldData extends DocValuesIndexFieldData implements IndexGeoShapeFieldData {
AbstractLatLonShapeDVIndexFieldData(Index index, String fieldName) {
super(index, fieldName);
}

@Override
public SortField sortField(@Nullable Object missingValue, MultiValueMode sortMode, XFieldComparatorSource.Nested nested,
boolean reverse) {
throw new IllegalArgumentException("can't sort on geo_shape field without using specific sorting feature, like geo_distance");
}

public static class LatLonShapeDVIndexFieldData extends AbstractLatLonShapeDVIndexFieldData {
public LatLonShapeDVIndexFieldData(Index index, String fieldName) {
super(index, fieldName);
}

@Override
public LeafGeoShapeFieldData load(LeafReaderContext context) {
LeafReader reader = context.reader();
FieldInfo info = reader.getFieldInfos().fieldInfo(fieldName);
if (info != null) {
checkCompatible(info);
}
return new LatLonShapeDVAtomicShapeFieldData(reader, fieldName);
}

@Override
public LeafGeoShapeFieldData loadDirect(LeafReaderContext context) throws Exception {
return load(context);
}

@Override
public BucketedSort newBucketedSort(BigArrays bigArrays, Object missingValue, MultiValueMode sortMode,
IndexFieldData.XFieldComparatorSource.Nested nested, SortOrder sortOrder, DocValueFormat format,
int bucketSize, BucketedSort.ExtraData extra) {
throw new IllegalArgumentException("can't sort on geo_shape field without using specific sorting feature, like geo_distance");
}

/** helper: checks a fieldinfo and throws exception if its definitely not a LatLonDocValuesField */
static void checkCompatible(FieldInfo fieldInfo) {
// dv properties could be "unset", if you e.g. used only StoredField with this same name in the segment.
if (fieldInfo.getDocValuesType() != DocValuesType.NONE
&& fieldInfo.getDocValuesType() != DocValuesType.BINARY) {
throw new IllegalArgumentException("field=\"" + fieldInfo.name + "\" was indexed with docValuesType="
+ fieldInfo.getDocValuesType() + " but this type has docValuesType="
+ DocValuesType.BINARY + ", is the field really a geo-shape field?");
}
}
}

public static class Builder implements IndexFieldData.Builder {
@Override
public IndexFieldData<?> build(IndexSettings indexSettings, MappedFieldType fieldType, IndexFieldDataCache cache,
CircuitBreakerService breakerService, MapperService mapperService) {
// ignore breaker
return new LatLonShapeDVIndexFieldData(indexSettings.getIndex(), fieldType.name());
}
}
}
Loading