/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.search.suggest.completion;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.suggest.completion.context.ContextBuilder;
import org.elasticsearch.search.suggest.completion.context.ContextMapping;
import org.elasticsearch.search.suggest.completion.context.GeoContextMapping;
import org.elasticsearch.test.ESSingleNodeTestCase;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.elasticsearch.common.geo.GeoHashUtils.addNeighbors;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.search.suggest.completion.CategoryContextMappingTests.assertContextSuggestFields;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isIn;
public class GeoContextMappingTests extends ESSingleNodeTestCase {
public void testIndexingWithNoContexts() throws Exception {
String mapping = jsonBuilder().startObject().startObject("type1")
.startObject("properties").startObject("completion")
.field("type", "completion")
.startArray("contexts")
.startObject()
.field("name", "ctx")
.field("type", "geo")
.endObject()
.endArray()
.endObject().endObject()
.endObject().endObject().string();
DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion");
MappedFieldType completionFieldType = fieldMapper.fieldType();
ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder()
.startObject()
.startArray("completion")
.startObject()
.array("input", "suggestion1", "suggestion2")
.field("weight", 3)
.endObject()
.startObject()
.array("input", "suggestion3", "suggestion4")
.field("weight", 4)
.endObject()
.startObject()
.array("input", "suggestion5", "suggestion6", "suggestion7")
.field("weight", 5)
.endObject()
.endArray()
.endObject()
.bytes(),
XContentType.JSON));
IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name());
assertContextSuggestFields(fields, 7);
}
public void testIndexingWithSimpleContexts() throws Exception {
String mapping = jsonBuilder().startObject().startObject("type1")
.startObject("properties").startObject("completion")
.field("type", "completion")
.startArray("contexts")
.startObject()
.field("name", "ctx")
.field("type", "geo")
.endObject()
.endArray()
.endObject()
.endObject()
.endObject().endObject().string();
DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion");
MappedFieldType completionFieldType = fieldMapper.fieldType();
ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder()
.startObject()
.startArray("completion")
.startObject()
.array("input", "suggestion5", "suggestion6", "suggestion7")
.startObject("contexts")
.startObject("ctx")
.field("lat", 43.6624803)
.field("lon", -79.3863353)
.endObject()
.endObject()
.field("weight", 5)
.endObject()
.endArray()
.endObject()
.bytes(),
XContentType.JSON));
IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name());
assertContextSuggestFields(fields, 3);
}
public void testIndexingWithContextList() throws Exception {
String mapping = jsonBuilder().startObject().startObject("type1")
.startObject("properties").startObject("completion")
.field("type", "completion")
.startArray("contexts")
.startObject()
.field("name", "ctx")
.field("type", "geo")
.endObject()
.endArray()
.endObject().endObject()
.endObject().endObject().string();
DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion");
MappedFieldType completionFieldType = fieldMapper.fieldType();
ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder()
.startObject()
.startObject("completion")
.array("input", "suggestion5", "suggestion6", "suggestion7")
.startObject("contexts")
.startArray("ctx")
.startObject()
.field("lat", 43.6624803)
.field("lon", -79.3863353)
.endObject()
.startObject()
.field("lat", 43.6624718)
.field("lon", -79.3873227)
.endObject()
.endArray()
.endObject()
.field("weight", 5)
.endObject()
.endObject()
.bytes(),
XContentType.JSON));
IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name());
assertContextSuggestFields(fields, 3);
}
public void testIndexingWithMultipleContexts() throws Exception {
String mapping = jsonBuilder().startObject().startObject("type1")
.startObject("properties").startObject("completion")
.field("type", "completion")
.startArray("contexts")
.startObject()
.field("name", "loc1")
.field("type", "geo")
.endObject()
.startObject()
.field("name", "loc2")
.field("type", "geo")
.endObject()
.endArray()
.endObject().endObject()
.endObject().endObject().string();
DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping));
FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion");
MappedFieldType completionFieldType = fieldMapper.fieldType();
XContentBuilder builder = jsonBuilder()
.startObject()
.startArray("completion")
.startObject()
.array("input", "suggestion5", "suggestion6", "suggestion7")
.field("weight", 5)
.startObject("contexts")
.array("loc1", "ezs42e44yx96")
.array("loc2", "wh0n9447fwrc")
.endObject()
.endObject()
.endArray()
.endObject();
ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", builder.bytes(),
XContentType.JSON));
IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name());
assertContextSuggestFields(fields, 3);
}
public void testParsingQueryContextBasic() throws Exception {
XContentBuilder builder = jsonBuilder().value("ezs42e44yx96");
XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes());
GeoContextMapping mapping = ContextBuilder.geo("geo").build();
List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser));
assertThat(internalQueryContexts.size(), equalTo(1 + 8));
Collection<String> locations = new ArrayList<>();
locations.add("ezs42e");
addNeighbors("ezs42e", GeoContextMapping.DEFAULT_PRECISION, locations);
for (ContextMapping.InternalQueryContext internalQueryContext : internalQueryContexts) {
assertThat(internalQueryContext.context, isIn(locations));
assertThat(internalQueryContext.boost, equalTo(1));
assertThat(internalQueryContext.isPrefix, equalTo(false));
}
}
public void testParsingQueryContextGeoPoint() throws Exception {
XContentBuilder builder = jsonBuilder().startObject()
.field("lat", 23.654242)
.field("lon", 90.047153)
.endObject();
XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes());
GeoContextMapping mapping = ContextBuilder.geo("geo").build();
List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser));
assertThat(internalQueryContexts.size(), equalTo(1 + 8));
Collection<String> locations = new ArrayList<>();
locations.add("wh0n94");
addNeighbors("wh0n94", GeoContextMapping.DEFAULT_PRECISION, locations);
for (ContextMapping.InternalQueryContext internalQueryContext : internalQueryContexts) {
assertThat(internalQueryContext.context, isIn(locations));
assertThat(internalQueryContext.boost, equalTo(1));
assertThat(internalQueryContext.isPrefix, equalTo(false));
}
}
public void testParsingQueryContextObject() throws Exception {
XContentBuilder builder = jsonBuilder().startObject()
.startObject("context")
.field("lat", 23.654242)
.field("lon", 90.047153)
.endObject()
.field("boost", 10)
.array("neighbours", 1, 2, 3)
.endObject();
XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes());
GeoContextMapping mapping = ContextBuilder.geo("geo").build();
List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser));
assertThat(internalQueryContexts.size(), equalTo(1 + 1 + 8 + 1 + 8 + 1 + 8));
Collection<String> locations = new ArrayList<>();
locations.add("wh0n94");
locations.add("w");
addNeighbors("w", 1, locations);
locations.add("wh");
addNeighbors("wh", 2, locations);
locations.add("wh0");
addNeighbors("wh0", 3, locations);
for (ContextMapping.InternalQueryContext internalQueryContext : internalQueryContexts) {
assertThat(internalQueryContext.context, isIn(locations));
assertThat(internalQueryContext.boost, equalTo(10));
assertThat(internalQueryContext.isPrefix, equalTo(internalQueryContext.context.length() < GeoContextMapping.DEFAULT_PRECISION));
}
}
public void testParsingQueryContextObjectArray() throws Exception {
XContentBuilder builder = jsonBuilder().startArray()
.startObject()
.startObject("context")
.field("lat", 23.654242)
.field("lon", 90.047153)
.endObject()
.field("boost", 10)
.array("neighbours", 1, 2, 3)
.endObject()
.startObject()
.startObject("context")
.field("lat", 22.337374)
.field("lon", 92.112583)
.endObject()
.field("boost", 2)
.array("neighbours", 5)
.endObject()
.endArray();
XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes());
GeoContextMapping mapping = ContextBuilder.geo("geo").build();
List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser));
assertThat(internalQueryContexts.size(), equalTo(1 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 1 + 8));
Collection<String> firstLocations = new ArrayList<>();
firstLocations.add("wh0n94");
firstLocations.add("w");
addNeighbors("w", 1, firstLocations);
firstLocations.add("wh");
addNeighbors("wh", 2, firstLocations);
firstLocations.add("wh0");
addNeighbors("wh0", 3, firstLocations);
Collection<String> secondLocations = new ArrayList<>();
secondLocations.add("w5cx04");
secondLocations.add("w5cx0");
addNeighbors("w5cx0", 5, secondLocations);
for (ContextMapping.InternalQueryContext internalQueryContext : internalQueryContexts) {
if (firstLocations.contains(internalQueryContext.context)) {
assertThat(internalQueryContext.boost, equalTo(10));
} else if (secondLocations.contains(internalQueryContext.context)) {
assertThat(internalQueryContext.boost, equalTo(2));
} else {
fail(internalQueryContext.context + " was not expected");
}
assertThat(internalQueryContext.isPrefix, equalTo(internalQueryContext.context.length() < GeoContextMapping.DEFAULT_PRECISION));
}
}
public void testParsingQueryContextMixed() throws Exception {
XContentBuilder builder = jsonBuilder().startArray()
.startObject()
.startObject("context")
.field("lat", 23.654242)
.field("lon", 90.047153)
.endObject()
.field("boost", 10)
.array("neighbours", 1, 2)
.endObject()
.startObject()
.field("lat", 22.337374)
.field("lon", 92.112583)
.endObject()
.endArray();
XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes());
GeoContextMapping mapping = ContextBuilder.geo("geo").build();
List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser));
assertThat(internalQueryContexts.size(), equalTo(1 + 1 + 8 + 1 + 8 + 1 + 8));
Collection<String> firstLocations = new ArrayList<>();
firstLocations.add("wh0n94");
firstLocations.add("w");
addNeighbors("w", 1, firstLocations);
firstLocations.add("wh");
addNeighbors("wh", 2, firstLocations);
Collection<String> secondLocations = new ArrayList<>();
secondLocations.add("w5cx04");
addNeighbors("w5cx04", 6, secondLocations);
for (ContextMapping.InternalQueryContext internalQueryContext : internalQueryContexts) {
if (firstLocations.contains(internalQueryContext.context)) {
assertThat(internalQueryContext.boost, equalTo(10));
} else if (secondLocations.contains(internalQueryContext.context)) {
assertThat(internalQueryContext.boost, equalTo(1));
} else {
fail(internalQueryContext.context + " was not expected");
}
assertThat(internalQueryContext.isPrefix, equalTo(internalQueryContext.context.length() < GeoContextMapping.DEFAULT_PRECISION));
}
}
private static QueryParseContext createParseContext(XContentParser parser) {
return new QueryParseContext(parser);
};
}