Skip to content

Commit 5dc6860

Browse files
authored
DATAES-929 - Support geo_shape field type field type.
Original PR: spring-projects#520
1 parent b7b1718 commit 5dc6860

File tree

7 files changed

+234
-60
lines changed

7 files changed

+234
-60
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2017-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.annotations;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* @author Lukas Vorisek
26+
* @author Peter-Josef Meisch
27+
* @since 4.1
28+
*/
29+
@Retention(RetentionPolicy.RUNTIME)
30+
@Target(ElementType.FIELD)
31+
@Documented
32+
public @interface GeoShapeField {
33+
Orientation orientation() default Orientation.ccw;
34+
35+
boolean ignoreMalformed() default false;
36+
37+
boolean ignoreZValue() default true;
38+
39+
boolean coerce() default false;
40+
41+
enum Orientation {
42+
right, ccw, counterclockwise, left, cw, clockwise
43+
}
44+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.core.index;
17+
18+
import java.io.IOException;
19+
20+
import org.elasticsearch.common.xcontent.XContentBuilder;
21+
import org.springframework.data.elasticsearch.annotations.GeoShapeField;
22+
import org.springframework.lang.Nullable;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* @author Peter-Josef Meisch
27+
*/
28+
final class GeoShapeMappingParameters {
29+
private static final String FIELD_PARAM_TYPE = "type";
30+
private static final String FIELD_PARAM_COERCE = "coerce";
31+
private static final String FIELD_PARAM_IGNORE_MALFORMED = "ignore_malformed";
32+
private static final String FIELD_PARAM_IGNORE_Z_VALUE = "ignore_z_value";
33+
private static final String FIELD_PARAM_ORIENTATION = "orientation";
34+
35+
private static final String TYPE_VALUE_GEO_SHAPE = "geo_shape";
36+
37+
private final boolean coerce;
38+
private final boolean ignoreMalformed;
39+
private final boolean ignoreZValue;
40+
private final GeoShapeField.Orientation orientation;
41+
42+
/**
43+
* Creates a GeoShapeMappingParameters from the given annotation.
44+
*
45+
* @param annotation if null, default values are set in the returned object
46+
* @return a parameters object
47+
*/
48+
public static GeoShapeMappingParameters from(@Nullable GeoShapeField annotation) {
49+
50+
if (annotation == null) {
51+
return new GeoShapeMappingParameters(false, false, true, GeoShapeField.Orientation.ccw);
52+
} else {
53+
return new GeoShapeMappingParameters(annotation.coerce(), annotation.ignoreMalformed(), annotation.ignoreZValue(),
54+
annotation.orientation());
55+
}
56+
}
57+
58+
private GeoShapeMappingParameters(boolean coerce, boolean ignoreMalformed, boolean ignoreZValue,
59+
GeoShapeField.Orientation orientation) {
60+
this.coerce = coerce;
61+
this.ignoreMalformed = ignoreMalformed;
62+
this.ignoreZValue = ignoreZValue;
63+
this.orientation = orientation;
64+
}
65+
66+
public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException {
67+
68+
Assert.notNull(builder, "builder must ot be null");
69+
70+
if (coerce) {
71+
builder.field(FIELD_PARAM_COERCE, coerce);
72+
}
73+
74+
if (ignoreMalformed) {
75+
builder.field(FIELD_PARAM_IGNORE_MALFORMED, ignoreMalformed);
76+
}
77+
78+
if (!ignoreZValue) {
79+
builder.field(FIELD_PARAM_IGNORE_Z_VALUE, ignoreZValue);
80+
}
81+
82+
if (orientation != GeoShapeField.Orientation.ccw) {
83+
builder.field(FIELD_PARAM_ORIENTATION, orientation.name());
84+
}
85+
86+
builder.field(FIELD_PARAM_TYPE, TYPE_VALUE_GEO_SHAPE);
87+
88+
}
89+
}

src/main/java/org/springframework/data/elasticsearch/core/index/MappingBuilder.java

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@
3535
import org.springframework.data.elasticsearch.annotations.*;
3636
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
3737
import org.springframework.data.elasticsearch.core.ResourceUtil;
38-
import org.springframework.data.elasticsearch.core.completion.Completion;
3938
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
40-
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
41-
import org.springframework.data.elasticsearch.core.join.JoinField;
4239
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
4340
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
4441
import org.springframework.data.mapping.MappingException;
@@ -203,17 +200,21 @@ private void buildPropertyMapping(XContentBuilder builder, boolean isRootObject,
203200
}
204201
}
205202

206-
if (isGeoPointProperty(property)) {
203+
if (property.isGeoPointProperty()) {
207204
applyGeoPointFieldMapping(builder, property);
208205
return;
209206
}
210207

211-
if (isJoinFieldProperty(property)) {
208+
if (property.isGeoShapeProperty()) {
209+
applyGeoShapeMapping(builder, property);
210+
}
211+
212+
if (property.isJoinFieldProperty()) {
212213
addJoinFieldMapping(builder, property);
213214
}
214215

215216
Field fieldAnnotation = property.findAnnotation(Field.class);
216-
boolean isCompletionProperty = isCompletionProperty(property);
217+
boolean isCompletionProperty = property.isCompletionProperty();
217218
boolean isNestedOrObjectProperty = isNestedOrObjectProperty(property);
218219

219220
if (!isCompletionProperty && property.isEntity() && hasRelevantAnnotation(property)) {
@@ -228,8 +229,8 @@ private void buildPropertyMapping(XContentBuilder builder, boolean isRootObject,
228229
? elasticsearchConverter.getMappingContext().getPersistentEntity(iterator.next())
229230
: null;
230231

231-
mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty,
232-
fieldAnnotation.type(), fieldAnnotation, property.findAnnotation(DynamicMapping.class));
232+
mapEntity(builder, persistentEntity, false, property.getFieldName(), true, fieldAnnotation.type(),
233+
fieldAnnotation, property.findAnnotation(DynamicMapping.class));
233234
return;
234235
}
235236
}
@@ -259,10 +260,17 @@ private boolean hasRelevantAnnotation(ElasticsearchPersistentProperty property)
259260

260261
private void applyGeoPointFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
261262
throws IOException {
262-
263263
builder.startObject(property.getFieldName()).field(FIELD_PARAM_TYPE, TYPE_VALUE_GEO_POINT).endObject();
264264
}
265265

266+
private void applyGeoShapeMapping(XContentBuilder builder, ElasticsearchPersistentProperty property)
267+
throws IOException {
268+
269+
builder.startObject(property.getFieldName());
270+
GeoShapeMappingParameters.from(property.findAnnotation(GeoShapeField.class)).writeTypeAndParametersTo(builder);
271+
builder.endObject();
272+
}
273+
266274
private void applyCompletionFieldMapping(XContentBuilder builder, ElasticsearchPersistentProperty property,
267275
@Nullable CompletionField annotation) throws IOException {
268276

@@ -448,16 +456,4 @@ private boolean isNestedOrObjectProperty(ElasticsearchPersistentProperty propert
448456
return fieldAnnotation != null
449457
&& (FieldType.Nested == fieldAnnotation.type() || FieldType.Object == fieldAnnotation.type());
450458
}
451-
452-
private boolean isGeoPointProperty(ElasticsearchPersistentProperty property) {
453-
return property.getActualType() == GeoPoint.class || property.isAnnotationPresent(GeoPointField.class);
454-
}
455-
456-
private boolean isJoinFieldProperty(ElasticsearchPersistentProperty property) {
457-
return property.getActualType() == JoinField.class;
458-
}
459-
460-
private boolean isCompletionProperty(ElasticsearchPersistentProperty property) {
461-
return property.getActualType() == Completion.class;
462-
}
463459
}

src/main/java/org/springframework/data/elasticsearch/core/index/MappingParameters.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ public boolean isStore() {
195195
* @param builder must not be {@literal null}.
196196
*/
197197
public void writeTypeAndParametersTo(XContentBuilder builder) throws IOException {
198+
198199
Assert.notNull(builder, "builder must ot be null");
199200

200201
if (fielddata) {

src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentProperty.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,30 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
102102
*/
103103
boolean storeNullValue();
104104

105+
/**
106+
* @return {@literal true} if this is a GeoPoint property
107+
* @since 4.1
108+
*/
109+
boolean isGeoPointProperty();
110+
111+
/**
112+
* @return {@literal true} if this is a GeoShape property
113+
* @since 4.1
114+
*/
115+
boolean isGeoShapeProperty();
116+
117+
/**
118+
* @return {@literal true} if this is a JoinField property
119+
* @since 4.1
120+
*/
121+
boolean isJoinFieldProperty();
122+
123+
/**
124+
* @return {@literal true} if this is a Completion property
125+
* @since 4.1
126+
*/
127+
boolean isCompletionProperty();
128+
105129
enum PropertyToFieldNameConverter implements Converter<ElasticsearchPersistentProperty, String> {
106130

107131
INSTANCE;

src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@
2626
import org.springframework.data.elasticsearch.annotations.DateFormat;
2727
import org.springframework.data.elasticsearch.annotations.Field;
2828
import org.springframework.data.elasticsearch.annotations.FieldType;
29+
import org.springframework.data.elasticsearch.annotations.GeoPointField;
30+
import org.springframework.data.elasticsearch.annotations.GeoShapeField;
2931
import org.springframework.data.elasticsearch.annotations.MultiField;
3032
import org.springframework.data.elasticsearch.annotations.Parent;
3133
import org.springframework.data.elasticsearch.annotations.Score;
34+
import org.springframework.data.elasticsearch.core.completion.Completion;
3235
import org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter;
36+
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
37+
import org.springframework.data.elasticsearch.core.join.JoinField;
3338
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
3439
import org.springframework.data.mapping.Association;
3540
import org.springframework.data.mapping.MappingException;
@@ -215,66 +220,58 @@ private String getAnnotatedFieldName() {
215220
return StringUtils.hasText(name) ? name : null;
216221
}
217222

218-
/*
219-
* (non-Javadoc)
220-
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#getFieldName()
221-
*/
222223
@Override
223224
public String getFieldName() {
224225
return annotatedFieldName == null ? getProperty().getName() : annotatedFieldName;
225226
}
226227

227-
/*
228-
* (non-Javadoc)
229-
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#isIdProperty()
230-
*/
231228
@Override
232229
public boolean isIdProperty() {
233230
return isId;
234231
}
235232

236-
/*
237-
* (non-Javadoc)
238-
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
239-
*/
240233
@Override
241234
protected Association<ElasticsearchPersistentProperty> createAssociation() {
242235
throw new UnsupportedOperationException();
243236
}
244237

245-
/*
246-
* (non-Javadoc)
247-
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isScoreProperty()
248-
*/
249238
@Override
250239
public boolean isScoreProperty() {
251240
return isScore;
252241
}
253242

254-
/*
255-
* (non-Javadoc)
256-
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#isImmutable()
257-
*/
258243
@Override
259244
public boolean isImmutable() {
260245
return false;
261246
}
262247

263-
/*
264-
* (non-Javadoc)
265-
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isParentProperty()
266-
*/
267248
@Override
268249
public boolean isParentProperty() {
269250
return isParent;
270251
}
271252

272-
/*
273-
* (non-Javadoc)
274-
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isSeqNoPrimaryTermProperty()
275-
*/
276253
@Override
277254
public boolean isSeqNoPrimaryTermProperty() {
278255
return isSeqNoPrimaryTerm;
279256
}
257+
258+
@Override
259+
public boolean isGeoPointProperty() {
260+
return getActualType() == GeoPoint.class || isAnnotationPresent(GeoPointField.class);
261+
}
262+
263+
@Override
264+
public boolean isGeoShapeProperty() {
265+
return isAnnotationPresent(GeoShapeField.class);
266+
}
267+
268+
@Override
269+
public boolean isJoinFieldProperty() {
270+
return getActualType() == JoinField.class;
271+
}
272+
273+
@Override
274+
public boolean isCompletionProperty() {
275+
return getActualType() == Completion.class;
276+
}
280277
}

0 commit comments

Comments
 (0)