2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.solr.schema;
20
import org.apache.lucene.document.Fieldable;
21
import org.apache.lucene.search.Query;
22
import org.apache.lucene.search.SortField;
23
import org.apache.lucene.spatial.DistanceUtils;
24
import org.apache.lucene.spatial.geohash.GeoHashUtils;
25
import org.apache.lucene.spatial.tier.InvalidGeoException;
26
import org.apache.solr.common.SolrException;
27
import org.apache.solr.response.TextResponseWriter;
28
import org.apache.solr.response.XMLWriter;
29
import org.apache.solr.search.QParser;
30
import org.apache.solr.search.SolrConstantScoreQuery;
31
import org.apache.solr.search.SpatialOptions;
32
import org.apache.solr.search.function.LiteralValueSource;
33
import org.apache.solr.search.function.ValueSource;
34
import org.apache.solr.search.function.ValueSourceRangeFilter;
35
import org.apache.solr.search.function.distance.GeohashHaversineFunction;
38
import java.io.IOException;
41
* This is a class that represents a <a
42
* href="http://en.wikipedia.org/wiki/Geohash">Geohash</a> field. The field is
43
* provided as a lat/lon pair and is internally represented as a string.
45
* @see org.apache.lucene.spatial.DistanceUtils#parseLatitudeLongitude(double[], String)
47
public class GeoHashField extends FieldType implements SpatialQueryable {
51
public SortField getSortField(SchemaField field, boolean top) {
52
return getStringSort(field, top);
55
//QUESTION: Should we do a fast and crude one? Or actually check distances
56
//Fast and crude could use EdgeNGrams, but that would require a different
57
//encoding. Plus there are issues around the Equator/Prime Meridian
58
public Query createSpatialQuery(QParser parser, SpatialOptions options) {
59
double [] point = new double[0];
61
point = DistanceUtils.parsePointDouble(null, options.pointStr, 2);
62
} catch (InvalidGeoException e) {
63
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
65
String geohash = GeoHashUtils.encode(point[0], point[1]);
67
return new SolrConstantScoreQuery(new ValueSourceRangeFilter(new GeohashHaversineFunction(getValueSource(options.field, parser),
68
new LiteralValueSource(geohash), options.radius), "0", String.valueOf(options.distance), true, true));
72
public void write(XMLWriter xmlWriter, String name, Fieldable f)
74
xmlWriter.writeStr(name, toExternal(f));
78
public void write(TextResponseWriter writer, String name, Fieldable f)
80
writer.writeStr(name, toExternal(f), false);
85
public String toExternal(Fieldable f) {
86
double[] latLon = GeoHashUtils.decode(f.stringValue());
87
return latLon[0] + "," + latLon[1];
92
public String toInternal(String val) {
93
// validate that the string is of the form
94
// latitude, longitude
95
double[] latLon = new double[0];
97
latLon = DistanceUtils.parseLatitudeLongitude(null, val);
98
} catch (InvalidGeoException e) {
99
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
101
return GeoHashUtils.encode(latLon[0], latLon[1]);
106
public ValueSource getValueSource(SchemaField field, QParser parser) {
107
field.checkFieldCacheSource(parser);
108
return new StrFieldSource(field.name);