Mapper: `geo_point` to support passing array of [lat, lon], closes #361.
This commit is contained in:
parent
c045b4d0ef
commit
ad5945f141
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search 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.xcontent;
|
||||
|
||||
/**
|
||||
* A marker interface indicating that this mapper can handle array value, and the array
|
||||
* itself should be passed to it.
|
||||
*
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public interface XContentArrayValueMapperParser {
|
||||
}
|
|
@ -48,7 +48,7 @@ import static org.elasticsearch.index.mapper.xcontent.XContentTypeParsers.*;
|
|||
*
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class XContentGeoPointFieldMapper implements XContentMapper {
|
||||
public class XContentGeoPointFieldMapper implements XContentMapper, XContentArrayValueMapperParser {
|
||||
|
||||
public static final String CONTENT_TYPE = "geo_point";
|
||||
|
||||
|
@ -232,67 +232,91 @@ public class XContentGeoPointFieldMapper implements XContentMapper {
|
|||
context.path().pathType(pathType);
|
||||
context.path().add(name);
|
||||
|
||||
boolean added = false;
|
||||
XContentParser.Token token = context.parser().currentToken();
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
String value = context.parser().text();
|
||||
int comma = value.indexOf(',');
|
||||
if (comma != -1) {
|
||||
double lat = Double.parseDouble(value.substring(0, comma).trim());
|
||||
double lon = Double.parseDouble(value.substring(comma + 1).trim());
|
||||
added = true;
|
||||
parseLatLon(context, lat, lon);
|
||||
if (token == XContentParser.Token.START_ARRAY) {
|
||||
token = context.parser().nextToken();
|
||||
if (token == XContentParser.Token.START_ARRAY) {
|
||||
// its an array of array of lat/lon [ [1.2, 1.3], [1.4, 1.5] ]
|
||||
while (token != XContentParser.Token.END_ARRAY) {
|
||||
token = context.parser().nextToken();
|
||||
Double lat = context.parser().doubleValue();
|
||||
token = context.parser().nextToken();
|
||||
Double lon = context.parser().doubleValue();
|
||||
while ((token = context.parser().nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
|
||||
}
|
||||
parseLatLon(context, lat, lon);
|
||||
token = context.parser().nextToken();
|
||||
}
|
||||
} else {
|
||||
// geo hash
|
||||
added = true;
|
||||
parseGeohash(context, value);
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
String currentName = context.parser().currentName();
|
||||
Double lat = null;
|
||||
Double lon = null;
|
||||
String geohash = null;
|
||||
while ((token = context.parser().nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentName = context.parser().currentName();
|
||||
} else if (token.isValue()) {
|
||||
if (currentName.equals(Names.LAT)) {
|
||||
lat = context.parser().doubleValue();
|
||||
} else if (currentName.equals(Names.LON)) {
|
||||
lon = context.parser().doubleValue();
|
||||
} else if (currentName.equals(Names.GEOHASH)) {
|
||||
geohash = context.parser().text();
|
||||
// its an array of other possible values
|
||||
if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||
Double lat = context.parser().doubleValue();
|
||||
token = context.parser().nextToken();
|
||||
Double lon = context.parser().doubleValue();
|
||||
while ((token = context.parser().nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
|
||||
}
|
||||
parseLatLon(context, lat, lon);
|
||||
} else {
|
||||
while (token != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
parseObjectLatLon(context);
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
parseStringLatLon(context);
|
||||
}
|
||||
token = context.parser().nextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (geohash != null) {
|
||||
added = true;
|
||||
parseGeohash(context, geohash);
|
||||
} else if (lat != null && lon != null) {
|
||||
added = true;
|
||||
parseLatLon(context, lat, lon);
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
token = context.parser().nextToken();
|
||||
Double lat = context.parser().doubleValue();
|
||||
token = context.parser().nextToken();
|
||||
Double lon = context.parser().doubleValue();
|
||||
token = context.parser().nextToken();
|
||||
while ((token = context.parser().nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
|
||||
}
|
||||
added = true;
|
||||
parseLatLon(context, lat, lon);
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
throw new MapperParsingException("failed to find location values for [" + name + "]");
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
parseObjectLatLon(context);
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
parseStringLatLon(context);
|
||||
}
|
||||
|
||||
context.path().remove();
|
||||
context.path().pathType(origPathType);
|
||||
}
|
||||
|
||||
private void parseStringLatLon(ParseContext context) throws IOException {
|
||||
String value = context.parser().text();
|
||||
int comma = value.indexOf(',');
|
||||
if (comma != -1) {
|
||||
double lat = Double.parseDouble(value.substring(0, comma).trim());
|
||||
double lon = Double.parseDouble(value.substring(comma + 1).trim());
|
||||
parseLatLon(context, lat, lon);
|
||||
} else { // geo hash
|
||||
parseGeohash(context, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseObjectLatLon(ParseContext context) throws IOException {
|
||||
XContentParser.Token token;
|
||||
String currentName = context.parser().currentName();
|
||||
Double lat = null;
|
||||
Double lon = null;
|
||||
String geohash = null;
|
||||
while ((token = context.parser().nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentName = context.parser().currentName();
|
||||
} else if (token.isValue()) {
|
||||
if (currentName.equals(Names.LAT)) {
|
||||
lat = context.parser().doubleValue();
|
||||
} else if (currentName.equals(Names.LON)) {
|
||||
lon = context.parser().doubleValue();
|
||||
} else if (currentName.equals(Names.GEOHASH)) {
|
||||
geohash = context.parser().text();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (geohash != null) {
|
||||
parseGeohash(context, geohash);
|
||||
} else if (lat != null && lon != null) {
|
||||
parseLatLon(context, lat, lon);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLatLon(ParseContext context, Double lat, Double lon) throws IOException {
|
||||
if (enableLatLon) {
|
||||
context.externalValue(lat);
|
||||
|
|
|
@ -386,19 +386,24 @@ public class XContentObjectMapper implements XContentMapper, XContentIncludeInAl
|
|||
}
|
||||
|
||||
private void serializeArray(ParseContext context, String lastFieldName) throws IOException {
|
||||
XContentParser parser = context.parser();
|
||||
XContentParser.Token token;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
serializeObject(context, lastFieldName);
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
serializeArray(context, lastFieldName);
|
||||
} else if (token == XContentParser.Token.FIELD_NAME) {
|
||||
lastFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.VALUE_NULL) {
|
||||
serializeNullValue(context, lastFieldName);
|
||||
} else {
|
||||
serializeValue(context, lastFieldName, token);
|
||||
XContentMapper mapper = mappers.get(lastFieldName);
|
||||
if (mapper != null && mapper instanceof XContentArrayValueMapperParser) {
|
||||
mapper.parse(context);
|
||||
} else {
|
||||
XContentParser parser = context.parser();
|
||||
XContentParser.Token token;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
serializeObject(context, lastFieldName);
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
serializeArray(context, lastFieldName);
|
||||
} else if (token == XContentParser.Token.FIELD_NAME) {
|
||||
lastFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.VALUE_NULL) {
|
||||
serializeNullValue(context, lastFieldName);
|
||||
} else {
|
||||
serializeValue(context, lastFieldName, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,4 +183,70 @@ public class LatLonMappingGeoPointTests {
|
|||
assertThat(doc.doc().getField("point.lon"), notNullValue());
|
||||
assertThat(doc.doc().getField("point.geohash"), nullValue());
|
||||
}
|
||||
|
||||
@Test public void testLatLonArray() throws Exception {
|
||||
String mapping = XContentFactory.contentTextBuilder(XContentType.JSON).startObject().startObject("type")
|
||||
.startObject("properties").startObject("point").field("type", "geo_point").endObject().endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
XContentDocumentMapper defaultMapper = XContentMapperTests.newParser().parse(mapping);
|
||||
|
||||
ParsedDocument doc = defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startArray("point").value(1.2).value(1.3).endArray()
|
||||
.endObject()
|
||||
.copiedBytes());
|
||||
|
||||
assertThat(doc.doc().getField("point.lat"), notNullValue());
|
||||
assertThat(doc.doc().getField("point.lat").getBinaryValue(), nullValue());
|
||||
assertThat(doc.doc().getField("point.lon"), notNullValue());
|
||||
assertThat(doc.doc().getField("point.lon").getBinaryValue(), nullValue());
|
||||
assertThat(doc.doc().getField("point.geohash"), nullValue());
|
||||
}
|
||||
|
||||
@Test public void testLatLonArrayStored() throws Exception {
|
||||
String mapping = XContentFactory.contentTextBuilder(XContentType.JSON).startObject().startObject("type")
|
||||
.startObject("properties").startObject("point").field("type", "geo_point").field("store", "yes").endObject().endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
XContentDocumentMapper defaultMapper = XContentMapperTests.newParser().parse(mapping);
|
||||
|
||||
ParsedDocument doc = defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startArray("point").value(1.2).value(1.3).endArray()
|
||||
.endObject()
|
||||
.copiedBytes());
|
||||
|
||||
assertThat(doc.doc().getField("point.lat"), notNullValue());
|
||||
assertThat(doc.doc().getField("point.lat").getBinaryValue(), equalTo(Numbers.doubleToBytes(1.2)));
|
||||
assertThat(doc.doc().getField("point.lon"), notNullValue());
|
||||
assertThat(doc.doc().getField("point.lon").getBinaryValue(), equalTo(Numbers.doubleToBytes(1.3)));
|
||||
assertThat(doc.doc().getField("point.geohash"), nullValue());
|
||||
}
|
||||
|
||||
@Test public void testLatLonArrayArrayStored() throws Exception {
|
||||
String mapping = XContentFactory.contentTextBuilder(XContentType.JSON).startObject().startObject("type")
|
||||
.startObject("properties").startObject("point").field("type", "geo_point").field("store", "yes").endObject().endObject()
|
||||
.endObject().endObject().string();
|
||||
|
||||
XContentDocumentMapper defaultMapper = XContentMapperTests.newParser().parse(mapping);
|
||||
|
||||
ParsedDocument doc = defaultMapper.parse("type", "1", XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startArray("point")
|
||||
.startArray().value(1.2).value(1.3).endArray()
|
||||
.startArray().value(1.4).value(1.5).endArray()
|
||||
.endArray()
|
||||
.endObject()
|
||||
.copiedBytes());
|
||||
|
||||
assertThat(doc.doc().getFields("point.lat").length, equalTo(2));
|
||||
assertThat(doc.doc().getFields("point.lon").length, equalTo(2));
|
||||
assertThat(doc.doc().getFields("point.lat")[0].getBinaryValue(), equalTo(Numbers.doubleToBytes(1.2)));
|
||||
assertThat(doc.doc().getFields("point.lon")[0].getBinaryValue(), equalTo(Numbers.doubleToBytes(1.3)));
|
||||
assertThat(doc.doc().getFields("point.lat")[1].getBinaryValue(), equalTo(Numbers.doubleToBytes(1.4)));
|
||||
assertThat(doc.doc().getFields("point.lon")[1].getBinaryValue(), equalTo(Numbers.doubleToBytes(1.5)));
|
||||
|
||||
assertThat(doc.doc().getField("point.geohash"), nullValue());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue