mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-05-30 16:52:11 +00:00
DATAES-929 - Support geo_shape field type field type.
Original PR: #520
This commit is contained in:
parent
b7b17180f6
commit
5dc68600f4
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2017-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Lukas Vorisek
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 4.1
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
public @interface GeoShapeField {
|
||||
Orientation orientation() default Orientation.ccw;
|
||||
|
||||
boolean ignoreMalformed() default false;
|
||||
|
||||
boolean ignoreZValue() default true;
|
||||
|
||||
boolean coerce() default false;
|
||||
|
||||
enum Orientation {
|
||||
right, ccw, counterclockwise, left, cw, clockwise
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.data.elasticsearch.core.index;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.springframework.data.elasticsearch.annotations.GeoShapeField;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
final class GeoShapeMappingParameters {
|
||||
private static final String FIELD_PARAM_TYPE = "type";
|
||||
private static final String FIELD_PARAM_COERCE = "coerce";
|
||||
private static final String FIELD_PARAM_IGNORE_MALFORMED = "ignore_malformed";
|
||||
private static final String FIELD_PARAM_IGNORE_Z_VALUE = "ignore_z_value";
|
||||
private static final String FIELD_PARAM_ORIENTATION = "orientation";
|
||||
|
||||
private static final String TYPE_VALUE_GEO_SHAPE = "geo_shape";
|
||||
|
||||
private final boolean coerce;
|
||||
private final boolean ignoreMalformed;
|
||||
private final boolean ignoreZValue;
|
||||
private final GeoShapeField.Orientation orientation;
|
||||
|
||||
/**
|
||||
* Creates a GeoShapeMappingParameters from the given annotation.
|
||||
*
|
||||
* @param annotation if null, default values are set in the returned object
|
||||
* @return a parameters object
|
||||
*/
|
||||
public static GeoShapeMappingParameters from(@Nullable GeoShapeField annotation) {
|
||||
|
||||
if (annotation == null) {
|
||||
return new GeoShapeMappingParameters(false, false, true, GeoShapeField.Orientation.ccw);
|
||||
} else {
|
||||
return new GeoShapeMappingParameters(annotation.coerce(), annotation.ignoreMalformed(), annotation.ignoreZValue(),
|
||||
annotation.orientation());
|
||||
}
|
||||
}
|
||||
|
||||
private GeoShapeMappingParameters(boolean coerce, boolean ignoreMalformed, boolean ignoreZValue,
|
||||
GeoShapeField.Orientation orientation) {
|
||||
this.coerce = coerce;
|
||||
this.ignoreMalformed = ignoreMalformed;
|
||||
this.ignoreZValue = ignoreZValue;
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException {
|
||||
|
||||
Assert.notNull(builder, "builder must ot be null");
|
||||
|
||||
if (coerce) {
|
||||
builder.field(FIELD_PARAM_COERCE, coerce);
|
||||
}
|
||||
|
||||
if (ignoreMalformed) {
|
||||
builder.field(FIELD_PARAM_IGNORE_MALFORMED, ignoreMalformed);
|
||||
}
|
||||
|
||||
if (!ignoreZValue) {
|
||||
builder.field(FIELD_PARAM_IGNORE_Z_VALUE, ignoreZValue);
|
||||
}
|
||||
|
||||
if (orientation != GeoShapeField.Orientation.ccw) {
|
||||
builder.field(FIELD_PARAM_ORIENTATION, orientation.name());
|
||||
}
|
||||
|
||||
builder.field(FIELD_PARAM_TYPE, TYPE_VALUE_GEO_SHAPE);
|
||||
|
||||
}
|
||||
}
|
@ -35,10 +35,7 @@ import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.annotations.*;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
|
||||
import org.springframework.data.elasticsearch.core.ResourceUtil;
|
||||
import org.springframework.data.elasticsearch.core.completion.Completion;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.join.JoinField;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
@ -203,17 +200,21 @@ public class MappingBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
if (isGeoPointProperty(property)) {
|
||||
if (property.isGeoPointProperty()) {
|
||||
applyGeoPointFieldMapping(builder, property);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJoinFieldProperty(property)) {
|
||||
if (property.isGeoShapeProperty()) {
|
||||
applyGeoShapeMapping(builder, property);
|
||||
}
|
||||
|
||||
if (property.isJoinFieldProperty()) {
|
||||
addJoinFieldMapping(builder, property);
|
||||
}
|
||||
|
||||
Field fieldAnnotation = property.findAnnotation(Field.class);
|
||||
boolean isCompletionProperty = isCompletionProperty(property);
|
||||
boolean isCompletionProperty = property.isCompletionProperty();
|
||||
boolean isNestedOrObjectProperty = isNestedOrObjectProperty(property);
|
||||
|
||||
if (!isCompletionProperty && property.isEntity() && hasRelevantAnnotation(property)) {
|
||||
@ -228,8 +229,8 @@ public class MappingBuilder {
|
||||
? elasticsearchConverter.getMappingContext().getPersistentEntity(iterator.next())
|
||||
: null;
|
||||
|
||||
mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty,
|
||||
fieldAnnotation.type(), fieldAnnotation, property.findAnnotation(DynamicMapping.class));
|
||||
mapEntity(builder, persistentEntity, false, property.getFieldName(), true, fieldAnnotation.type(),
|
||||
fieldAnnotation, property.findAnnotation(DynamicMapping.class));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -259,10 +260,17 @@ public class MappingBuilder {
|
||||
|
||||
private void applyGeoPointFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
|
||||
throws IOException {
|
||||
|
||||
builder.startObject(property.getFieldName()).field(FIELD_PARAM_TYPE, TYPE_VALUE_GEO_POINT).endObject();
|
||||
}
|
||||
|
||||
private void applyGeoShapeMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
|
||||
throws IOException {
|
||||
|
||||
builder.startObject(property.getFieldName());
|
||||
GeoShapeMappingParameters.from(property.findAnnotation(GeoShapeField.class)).writeTypeAndParametersTo(builder);
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
private void applyCompletionFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
|
||||
@Nullable CompletionField annotation) throws IOException {
|
||||
|
||||
@ -448,16 +456,4 @@ public class MappingBuilder {
|
||||
return fieldAnnotation != null
|
||||
&& (FieldType.Nested == fieldAnnotation.type() || FieldType.Object == fieldAnnotation.type());
|
||||
}
|
||||
|
||||
private boolean isGeoPointProperty(ElasticsearchPersistentProperty property) {
|
||||
return property.getActualType() == GeoPoint.class || property.isAnnotationPresent(GeoPointField.class);
|
||||
}
|
||||
|
||||
private boolean isJoinFieldProperty(ElasticsearchPersistentProperty property) {
|
||||
return property.getActualType() == JoinField.class;
|
||||
}
|
||||
|
||||
private boolean isCompletionProperty(ElasticsearchPersistentProperty property) {
|
||||
return property.getActualType() == Completion.class;
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +195,7 @@ public final class MappingParameters {
|
||||
* @param builder must not be {@literal null}.
|
||||
*/
|
||||
public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException {
|
||||
|
||||
Assert.notNull(builder, "builder must ot be null");
|
||||
|
||||
if (fielddata) {
|
||||
|
@ -102,6 +102,30 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
|
||||
*/
|
||||
boolean storeNullValue();
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this is a GeoPoint property
|
||||
* @since 4.1
|
||||
*/
|
||||
boolean isGeoPointProperty();
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this is a GeoShape property
|
||||
* @since 4.1
|
||||
*/
|
||||
boolean isGeoShapeProperty();
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this is a JoinField property
|
||||
* @since 4.1
|
||||
*/
|
||||
boolean isJoinFieldProperty();
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this is a Completion property
|
||||
* @since 4.1
|
||||
*/
|
||||
boolean isCompletionProperty();
|
||||
|
||||
enum PropertyToFieldNameConverter implements Converter<ElasticsearchPersistentProperty, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
@ -26,10 +26,15 @@ import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.GeoPointField;
|
||||
import org.springframework.data.elasticsearch.annotations.GeoShapeField;
|
||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||
import org.springframework.data.elasticsearch.annotations.Parent;
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.elasticsearch.core.completion.Completion;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.join.JoinField;
|
||||
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
@ -215,66 +220,58 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
return StringUtils.hasText(name) ? name : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#getFieldName()
|
||||
*/
|
||||
@Override
|
||||
public String getFieldName() {
|
||||
return annotatedFieldName == null ? getProperty().getName() : annotatedFieldName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#isIdProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
return isId;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
|
||||
*/
|
||||
@Override
|
||||
protected Association<ElasticsearchPersistentProperty> createAssociation() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isScoreProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isScoreProperty() {
|
||||
return isScore;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#isImmutable()
|
||||
*/
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isParentProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isParentProperty() {
|
||||
return isParent;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isSeqNoPrimaryTermProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isSeqNoPrimaryTermProperty() {
|
||||
return isSeqNoPrimaryTerm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGeoPointProperty() {
|
||||
return getActualType() == GeoPoint.class || isAnnotationPresent(GeoPointField.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGeoShapeProperty() {
|
||||
return isAnnotationPresent(GeoShapeField.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJoinFieldProperty() {
|
||||
return getActualType() == JoinField.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompletionProperty() {
|
||||
return getActualType() == Completion.class;
|
||||
}
|
||||
}
|
||||
|
@ -210,13 +210,37 @@ public class MappingBuilderTests extends MappingContextBaseTests {
|
||||
assertThat(entry.getMessage()).isEqualTo(message);
|
||||
}
|
||||
|
||||
@Test // DATAES-568
|
||||
public void shouldBuildMappingsForGeoPoint() throws JSONException {
|
||||
@Test // DATAES-568, DATAES-929
|
||||
@DisplayName("should build mappings for geo types")
|
||||
void shouldBuildMappingsForGeoTypes() throws JSONException {
|
||||
|
||||
// given
|
||||
String expected = "{\"properties\": {" + "\"pointA\":{\"type\":\"geo_point\"},"
|
||||
+ "\"pointB\":{\"type\":\"geo_point\"}," + "\"pointC\":{\"type\":\"geo_point\"},"
|
||||
+ "\"pointD\":{\"type\":\"geo_point\"}" + "}}";
|
||||
String expected = "{\n" + //
|
||||
" \"properties\": {\n" + //
|
||||
" \"pointA\": {\n" + //
|
||||
" \"type\": \"geo_point\"\n" + //
|
||||
" },\n" + //
|
||||
" \"pointB\": {\n" + //
|
||||
" \"type\": \"geo_point\"\n" + //
|
||||
" },\n" + //
|
||||
" \"pointC\": {\n" + //
|
||||
" \"type\": \"geo_point\"\n" + //
|
||||
" },\n" + //
|
||||
" \"pointD\": {\n" + //
|
||||
" \"type\": \"geo_point\"\n" + //
|
||||
" },\n" + //
|
||||
" \"shape1\": {\n" + //
|
||||
" \"type\": \"geo_shape\"\n" + //
|
||||
" },\n" + //
|
||||
" \"shape2\": {\n" + //
|
||||
" \"type\": \"geo_shape\",\n" + //
|
||||
" \"orientation\": \"clockwise\",\n" + //
|
||||
" \"ignore_malformed\": true,\n" + //
|
||||
" \"ignore_z_value\": false,\n" + //
|
||||
" \"coerce\": true\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}\n}"; //
|
||||
|
||||
// when
|
||||
String mapping;
|
||||
@ -961,9 +985,6 @@ public class MappingBuilderTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@ -981,12 +1002,14 @@ public class MappingBuilderTests extends MappingContextBaseTests {
|
||||
|
||||
// geo point - Custom implementation + Spring Data
|
||||
@GeoPointField private Point pointA;
|
||||
|
||||
private GeoPoint pointB;
|
||||
|
||||
@GeoPointField private String pointC;
|
||||
|
||||
@GeoPointField private double[] pointD;
|
||||
|
||||
// geo shape, until e have the classes for this, us a strng
|
||||
@GeoShapeField private String shape1;
|
||||
@GeoShapeField(coerce = true, ignoreMalformed = true, ignoreZValue = false,
|
||||
orientation = GeoShapeField.Orientation.clockwise) private String shape2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user