public static class Defaults { public static final String TREE = Names.TREE_GEOHASH; public static final String STRATEGY = SpatialStrategy.RECURSIVE.getStrategyName(); public static final boolean POINTS_ONLY = false; public static final int GEOHASH_LEVELS = GeoUtils.geoHashLevelsForPrecision("50m"); public static final int QUADTREE_LEVELS = GeoUtils.quadTreeLevelsForPrecision("50m"); public static final double LEGACY_DISTANCE_ERROR_PCT = 0.025d; public static final Orientation ORIENTATION = Orientation.RIGHT; public static final Explicit<Boolean> COERCE = new Explicit<>(false, false); public static final MappedFieldType FIELD_TYPE = new GeoShapeFieldType(); static { // setting name here is a hack so freeze can be called...instead all these options should be // moved to the default ctor for GeoShapeFieldType, and defaultFieldType() should be removed // from mappers... FIELD_TYPE.setNames(new MappedFieldType.Names("DoesNotExist")); FIELD_TYPE.setIndexOptions(IndexOptions.DOCS); FIELD_TYPE.setTokenized(false); FIELD_TYPE.setStored(false); FIELD_TYPE.setStoreTermVectors(false); FIELD_TYPE.setOmitNorms(true); FIELD_TYPE.freeze(); } }
private static int getLevels( int treeLevels, double precisionInMeters, int defaultLevels, boolean geoHash) { if (treeLevels > 0 || precisionInMeters >= 0) { return Math.max( treeLevels, precisionInMeters >= 0 ? (geoHash ? GeoUtils.geoHashLevelsForPrecision(precisionInMeters) : GeoUtils.quadTreeLevelsForPrecision(precisionInMeters)) : 0); } return defaultLevels; }
@Override public Mapper parse(ParseContext context) throws IOException { ContentPath.Type origPathType = context.path().pathType(); context.path().pathType(pathType); context.path().add(simpleName()); GeoPoint sparse = context.parseExternalValue(GeoPoint.class); if (sparse != null) { parse(context, sparse, null); } else { sparse = new GeoPoint(); XContentParser.Token token = context.parser().currentToken(); if (token == XContentParser.Token.START_ARRAY) { token = context.parser().nextToken(); if (token == XContentParser.Token.START_ARRAY) { // its an array of array of lon/lat [ [1.2, 1.3], [1.4, 1.5] ] while (token != XContentParser.Token.END_ARRAY) { parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null); token = context.parser().nextToken(); } } else { // its an array of other possible values if (token == XContentParser.Token.VALUE_NUMBER) { double lon = context.parser().doubleValue(); token = context.parser().nextToken(); double lat = context.parser().doubleValue(); while ((token = context.parser().nextToken()) != XContentParser.Token.END_ARRAY) ; parse(context, sparse.reset(lat, lon), null); } else { while (token != XContentParser.Token.END_ARRAY) { if (token == XContentParser.Token.VALUE_STRING) { parsePointFromString(context, sparse, context.parser().text()); } else { parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null); } token = context.parser().nextToken(); } } } } else if (token == XContentParser.Token.VALUE_STRING) { parsePointFromString(context, sparse, context.parser().text()); } else if (token != XContentParser.Token.VALUE_NULL) { parse(context, GeoUtils.parseGeoPoint(context.parser(), sparse), null); } } context.path().remove(); context.path().pathType(origPathType); return null; }
private void assertGeoPointQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query) throws IOException { assertThat(query, instanceOf(XGeoPointDistanceRangeQuery.class)); XGeoPointDistanceRangeQuery geoQuery = (XGeoPointDistanceRangeQuery) query; assertThat(geoQuery.getField(), equalTo(queryBuilder.fieldName())); if (queryBuilder.point() != null) { GeoPoint expectedPoint = new GeoPoint(queryBuilder.point()); GeoUtils.normalizePoint(expectedPoint); assertThat(geoQuery.getCenterLat(), equalTo(expectedPoint.lat())); assertThat(geoQuery.getCenterLon(), equalTo(expectedPoint.lon())); } if (queryBuilder.from() != null && queryBuilder.from() instanceof Number) { double fromValue = ((Number) queryBuilder.from()).doubleValue(); if (queryBuilder.unit() != null) { fromValue = queryBuilder.unit().toMeters(fromValue); } assertThat(geoQuery.getMinRadiusMeters(), closeTo(fromValue, 1E-5)); } if (queryBuilder.to() != null && queryBuilder.to() instanceof Number) { double toValue = ((Number) queryBuilder.to()).doubleValue(); if (queryBuilder.unit() != null) { toValue = queryBuilder.unit().toMeters(toValue); } assertThat(geoQuery.getMaxRadiusMeters(), closeTo(toValue, 1E-5)); } }
private void parse(ParseContext context, GeoPoint point, String geohash) throws IOException { if (fieldType().ignoreMalformed == false) { if (point.lat() > 90.0 || point.lat() < -90.0) { throw new IllegalArgumentException( "illegal latitude value [" + point.lat() + "] for " + name()); } if (point.lon() > 180.0 || point.lon() < -180) { throw new IllegalArgumentException( "illegal longitude value [" + point.lon() + "] for " + name()); } } if (fieldType().coerce) { // by setting coerce to false we are assuming all geopoints are already in a valid coordinate // system // thus this extra step can be skipped // LUCENE WATCH: This will be folded back into Lucene's GeoPointField GeoUtils.normalizePoint(point, true, true); } if (fieldType().indexOptions() != IndexOptions.NONE || fieldType().stored()) { Field field = new Field( fieldType().names().indexName(), Double.toString(point.lat()) + ',' + Double.toString(point.lon()), fieldType()); context.doc().add(field); } if (fieldType().isGeohashEnabled()) { if (geohash == null) { geohash = GeoHashUtils.encode(point.lat(), point.lon()); } addGeohashField(context, geohash); } if (fieldType().isLatLonEnabled()) { latMapper.parse(context.createExternalValueContext(point.lat())); lonMapper.parse(context.createExternalValueContext(point.lon())); } if (fieldType().hasDocValues()) { CustomGeoPointDocValuesField field = (CustomGeoPointDocValuesField) context.doc().getByKey(fieldType().names().indexName()); if (field == null) { field = new CustomGeoPointDocValuesField( fieldType().names().indexName(), point.lat(), point.lon()); context.doc().addWithKey(fieldType().names().indexName(), field); } else { field.add(point.lat(), point.lon()); } } multiFields.parse(this, context); }
private void assertLegacyQuery(GeoDistanceRangeQueryBuilder queryBuilder, Query query) throws IOException { assertThat(query, instanceOf(GeoDistanceRangeQuery.class)); GeoDistanceRangeQuery geoQuery = (GeoDistanceRangeQuery) query; assertThat(geoQuery.fieldName(), equalTo(queryBuilder.fieldName())); if (queryBuilder.point() != null) { GeoPoint expectedPoint = new GeoPoint(queryBuilder.point()); if (GeoValidationMethod.isCoerce(queryBuilder.getValidationMethod())) { GeoUtils.normalizePoint(expectedPoint, true, true); } assertThat(geoQuery.lat(), equalTo(expectedPoint.lat())); assertThat(geoQuery.lon(), equalTo(expectedPoint.lon())); } assertThat(geoQuery.geoDistance(), equalTo(queryBuilder.geoDistance())); if (queryBuilder.from() != null && queryBuilder.from() instanceof Number) { double fromValue = ((Number) queryBuilder.from()).doubleValue(); if (queryBuilder.unit() != null) { fromValue = queryBuilder.unit().toMeters(fromValue); } if (queryBuilder.geoDistance() != null) { fromValue = queryBuilder.geoDistance().normalize(fromValue, DistanceUnit.DEFAULT); } double fromSlop = Math.abs(fromValue) / 1000; if (queryBuilder.includeLower() == false) { fromSlop = NumericUtils.sortableLongToDouble( (NumericUtils.doubleToSortableLong(Math.abs(fromValue)) + 1L)) / 1000.0; } assertThat(geoQuery.minInclusiveDistance(), closeTo(fromValue, fromSlop)); } if (queryBuilder.to() != null && queryBuilder.to() instanceof Number) { double toValue = ((Number) queryBuilder.to()).doubleValue(); if (queryBuilder.unit() != null) { toValue = queryBuilder.unit().toMeters(toValue); } if (queryBuilder.geoDistance() != null) { toValue = queryBuilder.geoDistance().normalize(toValue, DistanceUnit.DEFAULT); } double toSlop = Math.abs(toValue) / 1000; if (queryBuilder.includeUpper() == false) { toSlop = NumericUtils.sortableLongToDouble( (NumericUtils.doubleToSortableLong(Math.abs(toValue)) - 1L)) / 1000.0; } assertThat(geoQuery.maxInclusiveDistance(), closeTo(toValue, toSlop)); } }
private AbstractDistanceScoreFunction parseGeoVariable( XContentParser parser, QueryShardContext context, BaseGeoPointFieldMapper.GeoPointFieldType fieldType, MultiValueMode mode) throws IOException { XContentParser.Token token; String parameterName = null; GeoPoint origin = new GeoPoint(); String scaleString = null; String offsetString = "0km"; double decay = 0.5; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { parameterName = parser.currentName(); } else if (DecayFunctionBuilder.SCALE.equals(parameterName)) { scaleString = parser.text(); } else if (DecayFunctionBuilder.ORIGIN.equals(parameterName)) { origin = GeoUtils.parseGeoPoint(parser); } else if (DecayFunctionBuilder.DECAY.equals(parameterName)) { decay = parser.doubleValue(); } else if (DecayFunctionBuilder.OFFSET.equals(parameterName)) { offsetString = parser.text(); } else { throw new ElasticsearchParseException("parameter [{}] not supported!", parameterName); } } if (origin == null || scaleString == null) { throw new ElasticsearchParseException( "[{}] and [{}] must be set for geo fields.", DecayFunctionBuilder.ORIGIN, DecayFunctionBuilder.SCALE); } double scale = DistanceUnit.DEFAULT.parse(scaleString, DistanceUnit.DEFAULT); double offset = DistanceUnit.DEFAULT.parse(offsetString, DistanceUnit.DEFAULT); IndexGeoPointFieldData indexFieldData = context.getForField(fieldType); return new GeoFieldDataScoreFunction( origin, scale, decay, offset, getDecayFunction(), indexFieldData, mode); }
@Override protected GeoDistanceRangeQueryBuilder doCreateTestQueryBuilder() { GeoDistanceRangeQueryBuilder builder; GeoPoint randomPoint = RandomGeoGenerator.randomPointIn(random(), -180.0, -89.9, 180.0, 89.9); if (randomBoolean()) { builder = new GeoDistanceRangeQueryBuilder(GEO_POINT_FIELD_NAME, randomPoint.geohash()); } else { if (randomBoolean()) { builder = new GeoDistanceRangeQueryBuilder(GEO_POINT_FIELD_NAME, randomPoint); } else { builder = new GeoDistanceRangeQueryBuilder( GEO_POINT_FIELD_NAME, randomPoint.lat(), randomPoint.lon()); } } GeoPoint point = builder.point(); final double maxRadius = GeoUtils.maxRadialDistanceMeters(point.lat(), point.lon()); final int fromValueMeters = randomInt((int) (maxRadius * 0.5)); final int toValueMeters = randomIntBetween(fromValueMeters + 1, (int) maxRadius); DistanceUnit fromToUnits = randomFrom(DistanceUnit.values()); final String fromToUnitsStr = fromToUnits.toString(); final double fromValue = DistanceUnit.convert(fromValueMeters, DistanceUnit.DEFAULT, fromToUnits); final double toValue = DistanceUnit.convert(toValueMeters, DistanceUnit.DEFAULT, fromToUnits); if (randomBoolean()) { int branch = randomInt(2); fromToUnits = DistanceUnit.DEFAULT; switch (branch) { case 0: builder.from(fromValueMeters); break; case 1: builder.to(toValueMeters); break; case 2: builder.from(fromValueMeters); builder.to(toValueMeters); break; } } else { int branch = randomInt(2); switch (branch) { case 0: builder.from(fromValue + fromToUnitsStr); break; case 1: builder.to(toValue + fromToUnitsStr); break; case 2: builder.from(fromValue + fromToUnitsStr); builder.to(toValue + fromToUnitsStr); break; } } if (randomBoolean()) { builder.includeLower(randomBoolean()); } if (randomBoolean()) { builder.includeUpper(randomBoolean()); } if (randomBoolean()) { builder.geoDistance(randomFrom(GeoDistance.values())); } builder.unit(fromToUnits); if (randomBoolean()) { builder.setValidationMethod(randomFrom(GeoValidationMethod.values())); } if (randomBoolean()) { builder.ignoreUnmapped(randomBoolean()); } return builder; }
@Override public Builder fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; String geohash = null; Integer levels = null; Boolean neighbors = null; String queryName = null; Float boost = null; XContentParser.Token token; if ((token = parser.currentToken()) != Token.START_OBJECT) { throw new ElasticsearchParseException( "failed to parse [{}] query. expected an object but found [{}] instead", NAME, token); } while ((token = parser.nextToken()) != Token.END_OBJECT) { if (token == Token.FIELD_NAME) { String field = parser.currentName(); if (parseContext.isDeprecatedSetting(field)) { // skip } else if (parseContext.parseFieldMatcher().match(field, PRECISION_FIELD)) { token = parser.nextToken(); if (token == Token.VALUE_NUMBER) { levels = parser.intValue(); } else if (token == Token.VALUE_STRING) { double meters = DistanceUnit.parse(parser.text(), DistanceUnit.DEFAULT, DistanceUnit.METERS); levels = GeoUtils.geoHashLevelsForPrecision(meters); } } else if (parseContext.parseFieldMatcher().match(field, NEIGHBORS_FIELD)) { parser.nextToken(); neighbors = parser.booleanValue(); } else if (parseContext .parseFieldMatcher() .match(field, AbstractQueryBuilder.NAME_FIELD)) { parser.nextToken(); queryName = parser.text(); } else if (parseContext .parseFieldMatcher() .match(field, AbstractQueryBuilder.BOOST_FIELD)) { parser.nextToken(); boost = parser.floatValue(); } else { if (fieldName == null) { fieldName = field; token = parser.nextToken(); if (token == Token.VALUE_STRING) { // A string indicates either a geohash or a // lat/lon // string String location = parser.text(); if (location.indexOf(",") > 0) { geohash = GeoUtils.parseGeoPoint(parser).geohash(); } else { geohash = location; } } else { geohash = GeoUtils.parseGeoPoint(parser).geohash(); } } else { throw new ParsingException( parser.getTokenLocation(), "[" + NAME + "] field name already set to [" + fieldName + "] but found [" + field + "]"); } } } else { throw new ElasticsearchParseException( "failed to parse [{}] query. unexpected token [{}]", NAME, token); } } Builder builder = new Builder(fieldName, geohash); if (levels != null) { builder.precision(levels); } if (neighbors != null) { builder.neighbors(neighbors); } if (queryName != null) { builder.queryName(queryName); } if (boost != null) { builder.boost(boost); } return builder; }
public Builder precision(String precision) { double meters = DistanceUnit.parse(precision, DistanceUnit.DEFAULT, DistanceUnit.METERS); return precision(GeoUtils.geoHashLevelsForPrecision(meters)); }
@Override public Mapper.Builder<?, ?> parse( String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException { Builder builder = geoPointField(name); final boolean indexCreatedBeforeV2_0 = parserContext.indexVersionCreated().before(Version.V_2_0_0); parseField(builder, name, node, parserContext); for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator(); iterator.hasNext(); ) { Map.Entry<String, Object> entry = iterator.next(); String fieldName = Strings.toUnderscoreCase(entry.getKey()); Object fieldNode = entry.getValue(); if (fieldName.equals("path") && parserContext.indexVersionCreated().before(Version.V_2_0_0_beta1)) { builder.multiFieldPathType(parsePathType(name, fieldNode.toString())); iterator.remove(); } else if (fieldName.equals("lat_lon")) { builder.enableLatLon(XContentMapValues.nodeBooleanValue(fieldNode)); iterator.remove(); } else if (fieldName.equals("geohash")) { builder.enableGeoHash(XContentMapValues.nodeBooleanValue(fieldNode)); iterator.remove(); } else if (fieldName.equals("geohash_prefix")) { builder.geohashPrefix(XContentMapValues.nodeBooleanValue(fieldNode)); if (XContentMapValues.nodeBooleanValue(fieldNode)) { builder.enableGeoHash(true); } iterator.remove(); } else if (fieldName.equals("precision_step")) { builder.precisionStep(XContentMapValues.nodeIntegerValue(fieldNode)); iterator.remove(); } else if (fieldName.equals("geohash_precision")) { if (fieldNode instanceof Integer) { builder.geoHashPrecision(XContentMapValues.nodeIntegerValue(fieldNode)); } else { builder.geoHashPrecision(GeoUtils.geoHashLevelsForPrecision(fieldNode.toString())); } iterator.remove(); } else if (fieldName.equals(Names.IGNORE_MALFORMED)) { if (builder.fieldType().coerce == false) { builder.fieldType().ignoreMalformed = XContentMapValues.nodeBooleanValue(fieldNode); } iterator.remove(); } else if (indexCreatedBeforeV2_0 && fieldName.equals("validate")) { if (builder.fieldType().ignoreMalformed == false) { builder.fieldType().ignoreMalformed = !XContentMapValues.nodeBooleanValue(fieldNode); } iterator.remove(); } else if (indexCreatedBeforeV2_0 && fieldName.equals("validate_lon")) { if (builder.fieldType().ignoreMalformed() == false) { builder.fieldType().ignoreMalformed = !XContentMapValues.nodeBooleanValue(fieldNode); } iterator.remove(); } else if (indexCreatedBeforeV2_0 && fieldName.equals("validate_lat")) { if (builder.fieldType().ignoreMalformed == false) { builder.fieldType().ignoreMalformed = !XContentMapValues.nodeBooleanValue(fieldNode); } iterator.remove(); } else if (fieldName.equals(Names.COERCE)) { builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode); if (builder.fieldType().coerce == true) { builder.fieldType().ignoreMalformed = true; } iterator.remove(); } else if (indexCreatedBeforeV2_0 && fieldName.equals("normalize")) { builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode); iterator.remove(); } else if (indexCreatedBeforeV2_0 && fieldName.equals("normalize_lat")) { builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode); iterator.remove(); } else if (indexCreatedBeforeV2_0 && fieldName.equals("normalize_lon")) { if (builder.fieldType().coerce == false) { builder.fieldType().coerce = XContentMapValues.nodeBooleanValue(fieldNode); } iterator.remove(); } else if (parseMultiField(builder, name, parserContext, fieldName, fieldNode)) { iterator.remove(); } } return builder; }