diff --git a/docs/reference/search/suggesters/context-suggest.asciidoc b/docs/reference/search/suggesters/context-suggest.asciidoc
index 60427cbb7c7..1830118af47 100644
--- a/docs/reference/search/suggesters/context-suggest.asciidoc
+++ b/docs/reference/search/suggesters/context-suggest.asciidoc
@@ -174,13 +174,12 @@ geohash of a certain precision, which provides the context.
[float]
==== Geo location Mapping
-The mapping for a geo context accepts four settings:
+The mapping for a geo context accepts four settings, only of which `precision` is required:
[horizontal]
`precision`:: This defines the precision of the geohash and can be specified as `5m`, `10km`,
or as a raw geohash precision: `1`..`12`. It's also possible to setup multiple
precisions by defining a list of precisions: `["5m", "10km"]`
- (default is a geohash level of 12)
`neighbors`:: Geohashes are rectangles, so a geolocation, which in reality is only 1 metre
away from the specified point, may fall into the neighbouring rectangle. Set
`neighbours` to `true` to include the neighbouring geohashes in the context.
diff --git a/rest-api-spec/test/suggest/20_context.yaml b/rest-api-spec/test/suggest/20_context.yaml
index 8577bd50cd2..cabd8a39552 100644
--- a/rest-api-spec/test/suggest/20_context.yaml
+++ b/rest-api-spec/test/suggest/20_context.yaml
@@ -33,6 +33,7 @@ setup:
"context":
"location":
"type" : "geo"
+ "precision" : "5km"
---
"Simple context suggestion should work":
@@ -201,8 +202,12 @@ setup:
- do:
indices.refresh: {}
+ - do:
+ indices.get_mapping: {}
+
- do:
suggest:
+ index: test
body:
result:
text: "hote"
diff --git a/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java b/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java
index d757e82ad0a..4631aaabcb5 100644
--- a/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java
+++ b/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java
@@ -18,8 +18,6 @@
*/
package org.elasticsearch.search.suggest.completion;
-import org.apache.lucene.search.suggest.analyzing.XFuzzySuggester;
-import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.suggest.SuggestBuilder;
diff --git a/src/main/java/org/elasticsearch/search/suggest/context/GeolocationContextMapping.java b/src/main/java/org/elasticsearch/search/suggest/context/GeolocationContextMapping.java
index 7ddbef0f2b2..1016d7aa6a2 100644
--- a/src/main/java/org/elasticsearch/search/suggest/context/GeolocationContextMapping.java
+++ b/src/main/java/org/elasticsearch/search/suggest/context/GeolocationContextMapping.java
@@ -114,6 +114,10 @@ public class GeolocationContextMapping extends ContextMapping {
* config
*/
protected static GeolocationContextMapping load(String name, Map config) {
+ if (!config.containsKey(FIELD_PRECISION)) {
+ throw new ElasticsearchParseException("field [precision] is missing");
+ }
+
final GeolocationContextMapping.Builder builder = new GeolocationContextMapping.Builder(name);
if (config != null) {
@@ -381,6 +385,10 @@ public class GeolocationContextMapping extends ContextMapping {
}
}
+ if (precision == null || precision.length == 0) {
+ precision = this.precision;
+ }
+
return new GeoQuery(name, point.geohash(), precision);
} else {
return new GeoQuery(name, GeoUtils.parseGeoPoint(parser).getGeohash(), precision);
diff --git a/src/test/java/org/elasticsearch/search/suggest/ContextSuggestSearchTests.java b/src/test/java/org/elasticsearch/search/suggest/ContextSuggestSearchTests.java
index 021a9d8cb8d..66bc4568ede 100644
--- a/src/test/java/org/elasticsearch/search/suggest/ContextSuggestSearchTests.java
+++ b/src/test/java/org/elasticsearch/search/suggest/ContextSuggestSearchTests.java
@@ -27,7 +27,9 @@ import org.elasticsearch.action.suggest.SuggestResponse;
import org.elasticsearch.common.geo.GeoHashUtils;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.Fuzziness;
-import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.*;
+import org.elasticsearch.index.mapper.MapperParsingException;
+import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.suggest.Suggest.Suggestion;
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry;
import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
@@ -479,6 +481,7 @@ public class ContextSuggestSearchTests extends ElasticsearchIntegrationTest {
.field("type", "completion")
.startObject("context").startObject("location")
.field("type", "geo")
+ .field("precision", "500m")
.startObject("default").field("lat", berlinAlexanderplatz.lat()).field("lon", berlinAlexanderplatz.lon()).endObject()
.endObject().endObject()
.endObject().endObject().endObject()
@@ -529,6 +532,7 @@ public class ContextSuggestSearchTests extends ElasticsearchIntegrationTest {
.field("type", "completion")
.startObject("context").startObject("location")
.field("type", "geo")
+ .field("precision", "1m")
.endObject().endObject()
.endObject().endObject().endObject()
.endObject();
@@ -670,6 +674,7 @@ public class ContextSuggestSearchTests extends ElasticsearchIntegrationTest {
.field("type", "completion")
.startObject("context").startObject("location")
.field("type", "geo")
+ .field("precision", "5m")
.field("path", "loc")
.endObject().endObject()
.endObject().endObject().endObject()
@@ -687,6 +692,57 @@ public class ContextSuggestSearchTests extends ElasticsearchIntegrationTest {
assertSuggestion(suggestResponse.getSuggest(), 0, "suggestion", "Berlin Alexanderplatz");
}
+ @Test(expected = MapperParsingException.class)
+ public void testThatPrecisionIsRequired() throws Exception {
+ XContentBuilder xContentBuilder = jsonBuilder().startObject()
+ .startObject("item").startObject("properties").startObject("suggest")
+ .field("type", "completion")
+ .startObject("context").startObject("location")
+ .field("type", "geo")
+ .field("path", "loc")
+ .endObject().endObject()
+ .endObject().endObject().endObject()
+ .endObject();
+
+ assertAcked(prepareCreate(INDEX).addMapping("item", xContentBuilder));
+ }
+
+ @Test
+ public void testThatLatLonParsingFromSourceWorks() throws Exception {
+ XContentBuilder xContentBuilder = jsonBuilder().startObject()
+ .startObject("mappings").startObject("test").startObject("properties").startObject("suggest_geo")
+ .field("type", "completion")
+ .startObject("context").startObject("location")
+ .field("type", "geo")
+ .field("precision", "1km")
+ .endObject().endObject()
+ .endObject().endObject().endObject()
+ .endObject().endObject();
+
+ assertAcked(prepareCreate("test").setSource(xContentBuilder.bytes()));
+
+ double latitude = 52.22;
+ double longitude = 4.53;
+ String geohash = GeoHashUtils.encode(latitude, longitude);
+
+ XContentBuilder doc1 = jsonBuilder().startObject().startObject("suggest_geo").field("input", "Hotel Marriot in Amsterdam").startObject("context").startObject("location").field("lat", latitude).field("lon", longitude).endObject().endObject().endObject().endObject();
+ index("test", "test", "1", doc1);
+ XContentBuilder doc2 = jsonBuilder().startObject().startObject("suggest_geo").field("input", "Hotel Marriot in Berlin").startObject("context").startObject("location").field("lat", 53.31).field("lon", 13.24).endObject().endObject().endObject().endObject();
+ index("test", "test", "2", doc2);
+ refresh();
+
+ XContentBuilder source = jsonBuilder().startObject().startObject("suggestion").field("text", "h").startObject("completion").field("field", "suggest_geo").startObject("context").field("location", geohash).endObject().endObject().endObject().endObject();
+ SuggestRequest suggestRequest = new SuggestRequest(INDEX).suggest(source.bytes());
+ SuggestResponse suggestResponse = client().suggest(suggestRequest).get();
+ assertSuggestion(suggestResponse.getSuggest(), 0, "suggestion", "Hotel Marriot in Amsterdam");
+
+ // this is exact the same request, but using lat/lon instead of geohash
+ source = jsonBuilder().startObject().startObject("suggestion").field("text", "h").startObject("completion").field("field", "suggest_geo").startObject("context").startObject("location").field("lat", latitude).field("lon", longitude).endObject().endObject().endObject().endObject().endObject();
+ suggestRequest = new SuggestRequest(INDEX).suggest(source.bytes());
+ suggestResponse = client().suggest(suggestRequest).get();
+ assertSuggestion(suggestResponse.getSuggest(), 0, "suggestion", "Hotel Marriot in Amsterdam");
+ }
+
public void assertGeoSuggestionsInRange(String location, String suggest, double precision) throws IOException {
String suggestionName = randomAsciiOfLength(10);
CompletionSuggestionBuilder context = new CompletionSuggestionBuilder(suggestionName).field(FIELD).text(suggest).size(10)
diff --git a/src/test/java/org/elasticsearch/search/suggest/context/GeoLocationContextMappingTest.java b/src/test/java/org/elasticsearch/search/suggest/context/GeoLocationContextMappingTest.java
index b15865ad639..b95722ffac9 100644
--- a/src/test/java/org/elasticsearch/search/suggest/context/GeoLocationContextMappingTest.java
+++ b/src/test/java/org/elasticsearch/search/suggest/context/GeoLocationContextMappingTest.java
@@ -18,13 +18,14 @@
*/
package org.elasticsearch.search.suggest.context;
-import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.Maps;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Test;
+import java.util.HashMap;
+
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
/**
@@ -38,7 +39,9 @@ public class GeoLocationContextMappingTest extends ElasticsearchTestCase {
XContentParser parser = XContentHelper.createParser(builder.bytes());
parser.nextToken();
- GeolocationContextMapping mapping = GeolocationContextMapping.load("foo", Maps.newHashMap());
+ HashMap config = new HashMap<>();
+ config.put("precision", 12);
+ GeolocationContextMapping mapping = GeolocationContextMapping.load("foo", config);
mapping.parseQuery("foo", parser);
}