diff --git a/core/src/test/java/org/elasticsearch/search/sort/GeoDistanceIT.java b/core/src/test/java/org/elasticsearch/search/sort/GeoDistanceIT.java new file mode 100644 index 00000000000..158a0bb812b --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/sort/GeoDistanceIT.java @@ -0,0 +1,630 @@ +/* + * 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.sort; + +import org.apache.lucene.util.GeoHashUtils; +import org.elasticsearch.Version; +import org.elasticsearch.action.index.IndexRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.geo.GeoDistance; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.index.query.GeoDistanceQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.sort.SortBuilders; +import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.InternalSettingsPlugin; +import org.elasticsearch.test.VersionUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.index.query.QueryBuilders.geoDistanceQuery; +import static org.elasticsearch.index.query.QueryBuilders.geoDistanceRangeQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.index.query.QueryBuilders.termQuery; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFirstHit; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertOrderedSearchHits; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; + + +public class GeoDistanceIT extends ESIntegTestCase { + @Override + protected Collection> nodePlugins() { + return pluginList(InternalSettingsPlugin.class); + } + + public void testSimpleDistance() throws Exception { + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") + .startObject("location").field("type", "geo_point"); + if (version.before(Version.V_2_2_0)) { + xContentBuilder.field("lat_lon", true); + } + xContentBuilder.endObject().endObject().endObject().endObject(); + assertAcked(prepareCreate("test").setSettings(settings).addMapping("type1", xContentBuilder)); + ensureGreen(); + + indexRandom(true, + client().prepareIndex("test", "type1", "1") + .setSource(jsonBuilder().startObject().field("name", "New York").startObject("location").field("lat", 40.7143528) + .field("lon", -74.0059731).endObject().endObject()), + // to NY: 5.286 km + client().prepareIndex("test", "type1", "2") + .setSource(jsonBuilder().startObject().field("name", "Times Square").startObject("location").field("lat", 40.759011) + .field("lon", -73.9844722).endObject().endObject()), + // to NY: 0.4621 km + client().prepareIndex("test", "type1", "3") + .setSource(jsonBuilder().startObject().field("name", "Tribeca").startObject("location").field("lat", 40.718266) + .field("lon", -74.007819).endObject().endObject()), + // to NY: 1.055 km + client().prepareIndex("test", "type1", "4") + .setSource(jsonBuilder().startObject().field("name", "Wall Street").startObject("location").field("lat", 40.7051157) + .field("lon", -74.0088305).endObject().endObject()), + // to NY: 1.258 km + client().prepareIndex("test", "type1", "5") + .setSource(jsonBuilder().startObject().field("name", "Soho").startObject("location").field("lat", 40.7247222) + .field("lon", -74).endObject().endObject()), + // to NY: 2.029 km + client().prepareIndex("test", "type1", "6") + .setSource(jsonBuilder().startObject().field("name", "Greenwich Village").startObject("location") + .field("lat", 40.731033).field("lon", -73.9962255).endObject().endObject()), + // to NY: 8.572 km + client().prepareIndex("test", "type1", "7").setSource(jsonBuilder().startObject().field("name", "Brooklyn") + .startObject("location").field("lat", 40.65).field("lon", -73.95).endObject().endObject())); + + SearchResponse searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("3km").point(40.7143528, -74.0059731)).execute().actionGet(); + assertHitCount(searchResponse, 5); + assertThat(searchResponse.getHits().hits().length, equalTo(5)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6"))); + } + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("3km").point(40.7143528, -74.0059731).optimizeBbox("indexed")).execute() + .actionGet(); + assertHitCount(searchResponse, 5); + assertThat(searchResponse.getHits().hits().length, equalTo(5)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6"))); + } + + // now with a PLANE type + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("3km").geoDistance(GeoDistance.PLANE).point(40.7143528, -74.0059731)) + .execute().actionGet(); + assertHitCount(searchResponse, 5); + assertThat(searchResponse.getHits().hits().length, equalTo(5)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6"))); + } + + // factor type is really too small for this resolution + + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("2km").point(40.7143528, -74.0059731)).execute().actionGet(); + assertHitCount(searchResponse, 4); + assertThat(searchResponse.getHits().hits().length, equalTo(4)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); + } + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("2km").point(40.7143528, -74.0059731).optimizeBbox("indexed")).execute() + .actionGet(); + assertHitCount(searchResponse, 4); + assertThat(searchResponse.getHits().hits().length, equalTo(4)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); + } + + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("1.242mi").point(40.7143528, -74.0059731)).execute().actionGet(); + assertHitCount(searchResponse, 4); + assertThat(searchResponse.getHits().hits().length, equalTo(4)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); + } + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceQuery("location").distance("1.242mi").point(40.7143528, -74.0059731).optimizeBbox("indexed")).execute() + .actionGet(); + assertHitCount(searchResponse, 4); + assertThat(searchResponse.getHits().hits().length, equalTo(4)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); + } + + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).from("1.0km").to("2.0km")).execute().actionGet(); + assertHitCount(searchResponse, 2); + assertThat(searchResponse.getHits().hits().length, equalTo(2)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("4"), equalTo("5"))); + } + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).from("1.0km").to("2.0km").optimizeBbox("indexed")) + .execute().actionGet(); + assertHitCount(searchResponse, 2); + assertThat(searchResponse.getHits().hits().length, equalTo(2)); + for (SearchHit hit : searchResponse.getHits()) { + assertThat(hit.id(), anyOf(equalTo("4"), equalTo("5"))); + } + + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).to("2.0km")).execute().actionGet(); + assertHitCount(searchResponse, 4); + assertThat(searchResponse.getHits().hits().length, equalTo(4)); + + searchResponse = client().prepareSearch() // from NY + .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).from("2.0km")).execute().actionGet(); + assertHitCount(searchResponse, 3); + assertThat(searchResponse.getHits().hits().length, equalTo(3)); + + // SORTING + + searchResponse = client().prepareSearch().setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("location").point(40.7143528, -74.0059731).order(SortOrder.ASC)).execute() + .actionGet(); + + assertHitCount(searchResponse, 7); + assertOrderedSearchHits(searchResponse, "1", "3", "4", "5", "6", "2", "7"); + + searchResponse = client().prepareSearch().setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("location").point(40.7143528, -74.0059731).order(SortOrder.DESC)).execute() + .actionGet(); + + assertHitCount(searchResponse, 7); + assertOrderedSearchHits(searchResponse, "7", "2", "6", "5", "4", "3", "1"); + } + + public void testDistanceSortingMVFields() throws Exception { + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") + .startObject("locations").field("type", "geo_point"); + if (version.before(Version.V_2_2_0)) { + xContentBuilder.field("lat_lon", true).field("coerce", true); + } + xContentBuilder.field("ignore_malformed", true).endObject().endObject().endObject().endObject(); + assertAcked(prepareCreate("test").setSettings(settings).addMapping("type1", xContentBuilder)); + ensureGreen(); + + client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject().field("names", "New York") + .startObject("locations").field("lat", 40.7143528).field("lon", -74.0059731).endObject().endObject()).execute().actionGet(); + + client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject().field("names", "New York 2") + .startObject("locations").field("lat", 400.7143528).field("lon", 285.9990269).endObject().endObject()).execute() + .actionGet(); + + client().prepareIndex("test", "type1", "3") + .setSource(jsonBuilder().startObject().field("names", "Times Square", "Tribeca").startArray("locations") + // to NY: 5.286 km + .startObject().field("lat", 40.759011).field("lon", -73.9844722).endObject() + // to NY: 0.4621 km + .startObject().field("lat", 40.718266).field("lon", -74.007819).endObject().endArray().endObject()) + .execute().actionGet(); + + client().prepareIndex("test", "type1", "4") + .setSource(jsonBuilder().startObject().field("names", "Wall Street", "Soho").startArray("locations") + // to NY: 1.055 km + .startObject().field("lat", 40.7051157).field("lon", -74.0088305).endObject() + // to NY: 1.258 km + .startObject().field("lat", 40.7247222).field("lon", -74).endObject().endArray().endObject()) + .execute().actionGet(); + + client().prepareIndex("test", "type1", "5") + .setSource(jsonBuilder().startObject().field("names", "Greenwich Village", "Brooklyn").startArray("locations") + // to NY: 2.029 km + .startObject().field("lat", 40.731033).field("lon", -73.9962255).endObject() + // to NY: 8.572 km + .startObject().field("lat", 40.65).field("lon", -73.95).endObject().endArray().endObject()) + .execute().actionGet(); + + client().admin().indices().prepareRefresh().execute().actionGet(); + + // Order: Asc + SearchResponse searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.ASC)).execute() + .actionGet(); + + assertHitCount(searchResponse, 5); + assertOrderedSearchHits(searchResponse, "1", "2", "3", "4", "5"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); + + // Order: Asc, Mode: max + searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.ASC).sortMode("max")) + .execute().actionGet(); + + assertHitCount(searchResponse, 5); + assertOrderedSearchHits(searchResponse, "1", "2", "4", "3", "5"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); + + // Order: Desc + searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.DESC)).execute() + .actionGet(); + + assertHitCount(searchResponse, 5); + assertOrderedSearchHits(searchResponse, "5", "3", "4", "2", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + + // Order: Desc, Mode: min + searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.DESC).sortMode("min")) + .execute().actionGet(); + + assertHitCount(searchResponse, 5); + assertOrderedSearchHits(searchResponse, "5", "4", "3", "2", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + + searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC)) + .execute().actionGet(); + + assertHitCount(searchResponse, 5); + assertOrderedSearchHits(searchResponse, "1", "2", "4", "3", "5"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1157d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(2874d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(5301d, 10d)); + + searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.DESC)) + .execute().actionGet(); + + assertHitCount(searchResponse, 5); + assertOrderedSearchHits(searchResponse, "5", "3", "4", "2", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(5301.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(2874.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1157.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + + assertFailures( + client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).sortMode("sum")), + RestStatus.BAD_REQUEST, containsString("sort_mode [sum] isn't supported for sorting by geo distance")); + } + + // Regression bug: + // https://github.com/elasticsearch/elasticsearch/issues/2851 + public void testDistanceSortingWithMissingGeoPoint() throws Exception { + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") + .startObject("locations").field("type", "geo_point"); + if (version.before(Version.V_2_2_0)) { + xContentBuilder.field("lat_lon", true); + } + xContentBuilder.endObject().endObject().endObject().endObject(); + assertAcked(prepareCreate("test").setSettings(settings).addMapping("type1", xContentBuilder)); + ensureGreen(); + + client().prepareIndex("test", "type1", "1") + .setSource(jsonBuilder().startObject().field("names", "Times Square", "Tribeca").startArray("locations") + // to NY: 5.286 km + .startObject().field("lat", 40.759011).field("lon", -73.9844722).endObject() + // to NY: 0.4621 km + .startObject().field("lat", 40.718266).field("lon", -74.007819).endObject().endArray().endObject()) + .execute().actionGet(); + + client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject().field("names", "Wall Street", "Soho").endObject()) + .execute().actionGet(); + + refresh(); + + // Order: Asc + SearchResponse searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.ASC)).execute() + .actionGet(); + + assertHitCount(searchResponse, 2); + assertOrderedSearchHits(searchResponse, "1", "2"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); + + // Order: Desc + searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.DESC)).execute() + .actionGet(); + + // Doc with missing geo point is first, is consistent with 0.20.x + assertHitCount(searchResponse, 2); + assertOrderedSearchHits(searchResponse, "2", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(5286d, 10d)); + } + + public void testDistanceSortingNestedFields() throws Exception { + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("company").startObject("properties") + .startObject("name").field("type", "string").endObject().startObject("branches").field("type", "nested") + .startObject("properties").startObject("name").field("type", "string").endObject().startObject("location") + .field("type", "geo_point"); + if (version.before(Version.V_2_2_0)) { + xContentBuilder.field("lat_lon", true); + } + xContentBuilder.endObject().endObject().endObject().endObject().endObject().endObject(); + + assertAcked(prepareCreate("companies").setSettings(settings).addMapping("company", xContentBuilder)); + ensureGreen(); + + indexRandom(true, + client().prepareIndex("companies", "company", "1") + .setSource( + jsonBuilder().startObject().field("name", "company 1").startArray("branches").startObject() + .field("name", "New York").startObject("location").field("lat", 40.7143528) + .field("lon", + -74.0059731) + .endObject().endObject().endArray().endObject()), + client().prepareIndex("companies", "company", "2") + .setSource(jsonBuilder().startObject().field("name", "company 2").startArray("branches").startObject() + .field("name", "Times Square").startObject("location").field("lat", 40.759011).field("lon", -73.9844722) + .endObject() // to NY: 5.286 km + .endObject().startObject().field("name", "Tribeca").startObject("location").field("lat", 40.718266) + .field("lon", -74.007819).endObject() // to NY: + // 0.4621 + // km + .endObject().endArray().endObject()), + client().prepareIndex("companies", "company", "3") + .setSource(jsonBuilder().startObject().field("name", "company 3").startArray("branches").startObject() + .field("name", "Wall Street").startObject("location").field("lat", 40.7051157).field("lon", -74.0088305) + .endObject() // to NY: 1.055 km + .endObject().startObject().field("name", "Soho").startObject("location").field("lat", 40.7247222) + .field("lon", -74).endObject() // to NY: 1.258 + // km + .endObject().endArray().endObject()), + client().prepareIndex("companies", "company", "4") + .setSource(jsonBuilder().startObject().field("name", "company 4").startArray("branches").startObject() + .field("name", "Greenwich Village").startObject("location").field("lat", 40.731033) + .field("lon", -73.9962255).endObject() // to NY: + // 2.029 + // km + .endObject().startObject().field("name", "Brooklyn").startObject("location").field("lat", 40.65) + .field("lon", -73.95).endObject() // to NY: + // 8.572 km + .endObject().endArray().endObject())); + + // Order: Asc + SearchResponse searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()).addSort(SortBuilders + .geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC).setNestedPath("branches")) + .execute().actionGet(); + + assertHitCount(searchResponse, 4); + assertOrderedSearchHits(searchResponse, "1", "2", "3", "4"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); + + // Order: Asc, Mode: max + searchResponse = client() + .prepareSearch("companies").setQuery(matchAllQuery()).addSort(SortBuilders.geoDistanceSort("branches.location") + .point(40.7143528, -74.0059731).order(SortOrder.ASC).sortMode("max").setNestedPath("branches")) + .execute().actionGet(); + + assertHitCount(searchResponse, 4); + assertOrderedSearchHits(searchResponse, "1", "3", "2", "4"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); + + // Order: Desc + searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()).addSort(SortBuilders + .geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC).setNestedPath("branches")) + .execute().actionGet(); + + assertHitCount(searchResponse, 4); + assertOrderedSearchHits(searchResponse, "4", "2", "3", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + + // Order: Desc, Mode: min + searchResponse = client() + .prepareSearch("companies").setQuery(matchAllQuery()).addSort(SortBuilders.geoDistanceSort("branches.location") + .point(40.7143528, -74.0059731).order(SortOrder.DESC).sortMode("min").setNestedPath("branches")) + .execute().actionGet(); + + assertHitCount(searchResponse, 4); + assertOrderedSearchHits(searchResponse, "4", "3", "2", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + + searchResponse = client() + .prepareSearch("companies").setQuery(matchAllQuery()).addSort(SortBuilders.geoDistanceSort("branches.location") + .point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC).setNestedPath("branches")) + .execute().actionGet(); + + assertHitCount(searchResponse, 4); + assertOrderedSearchHits(searchResponse, "1", "3", "2", "4"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1157.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(2874.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(5301.0d, 10d)); + + searchResponse = client().prepareSearch("companies") + .setQuery(matchAllQuery()).addSort(SortBuilders.geoDistanceSort("branches.location").setNestedPath("branches") + .point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.DESC).setNestedPath("branches")) + .execute().actionGet(); + + assertHitCount(searchResponse, 4); + assertOrderedSearchHits(searchResponse, "4", "2", "3", "1"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(5301.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(2874.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1157.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); + + searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("branches.location").setNestedFilter(termQuery("branches.name", "brooklyn")) + .point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC).setNestedPath("branches")) + .execute().actionGet(); + assertHitCount(searchResponse, 4); + assertFirstHit(searchResponse, hasId("4")); + assertSearchHits(searchResponse, "1", "2", "3", "4"); + assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); + assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); + assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); + assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); + + assertFailures( + client().prepareSearch("companies").setQuery(matchAllQuery()) + .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("sum") + .setNestedPath("branches")), + RestStatus.BAD_REQUEST, containsString("sort_mode [sum] isn't supported for sorting by geo distance")); + } + + /** + * Issue 3073 + */ + public void testGeoDistanceFilter() throws IOException { + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + double lat = 40.720611; + double lon = -73.998776; + + XContentBuilder mapping = JsonXContent.contentBuilder().startObject().startObject("location").startObject("properties") + .startObject("pin").field("type", "geo_point"); + if (version.before(Version.V_2_2_0)) { + mapping.field("lat_lon", true); + } + mapping.endObject().endObject().endObject().endObject(); + + XContentBuilder source = JsonXContent.contentBuilder().startObject().field("pin", GeoHashUtils.stringEncode(lon, lat)).endObject(); + + assertAcked(prepareCreate("locations").setSettings(settings).addMapping("location", mapping)); + client().prepareIndex("locations", "location", "1").setCreate(true).setSource(source).execute().actionGet(); + refresh(); + client().prepareGet("locations", "location", "1").execute().actionGet(); + + SearchResponse result = client().prepareSearch("locations").setQuery(QueryBuilders.matchAllQuery()) + .setPostFilter(QueryBuilders.geoDistanceQuery("pin").geoDistance(GeoDistance.ARC).point(lat, lon).distance("1m")).execute() + .actionGet(); + + assertHitCount(result, 1); + } + + private double randomLon() { + return randomDouble() * 360 - 180; + } + + private double randomLat() { + return randomDouble() * 180 - 90; + } + + public void testDuelOptimizations() throws Exception { + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + if (version.before(Version.V_2_2_0)) { + assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point,lat_lon=true")); + } else { + assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point")); + } + final int numDocs = scaledRandomIntBetween(3000, 10000); + List docs = new ArrayList<>(); + for (int i = 0; i < numDocs; ++i) { + docs.add(client().prepareIndex("index", "type").setSource(jsonBuilder().startObject().startObject("location") + .field("lat", randomLat()).field("lon", randomLon()).endObject().endObject())); + } + indexRandom(true, docs); + ensureSearchable(); + + for (int i = 0; i < 10; ++i) { + final double originLat = randomLat(); + final double originLon = randomLon(); + final String distance = DistanceUnit.KILOMETERS.toString(randomIntBetween(1, 10000)); + for (GeoDistance geoDistance : Arrays.asList(GeoDistance.ARC, GeoDistance.SLOPPY_ARC)) { + logger.info("Now testing GeoDistance={}, distance={}, origin=({}, {})", geoDistance, distance, originLat, originLon); + GeoDistanceQueryBuilder qb = QueryBuilders.geoDistanceQuery("location").point(originLat, originLon).distance(distance) + .geoDistance(geoDistance); + long matches; + if (version.before(Version.V_2_2_0)) { + for (String optimizeBbox : Arrays.asList("none", "memory", "indexed")) { + qb.optimizeBbox(optimizeBbox); + SearchResponse resp = client().prepareSearch("index").setSize(0).setQuery(QueryBuilders.constantScoreQuery(qb)) + .execute().actionGet(); + matches = assertDuelOptimization(resp); + logger.info("{} -> {} hits", optimizeBbox, matches); + } + } else { + SearchResponse resp = client().prepareSearch("index").setSize(0).setQuery(QueryBuilders.constantScoreQuery(qb)) + .execute().actionGet(); + matches = assertDuelOptimization(resp); + logger.info("{} hits", matches); + } + } + } + } + + private long assertDuelOptimization(SearchResponse resp) { + long matches = -1; + assertSearchResponse(resp); + if (matches < 0) { + matches = resp.getHits().totalHits(); + } else { + assertEquals(matches, matches = resp.getHits().totalHits()); + } + return matches; + } +} diff --git a/core/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderIT.java b/core/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderIT.java new file mode 100644 index 00000000000..10053c40406 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/sort/GeoDistanceSortBuilderIT.java @@ -0,0 +1,310 @@ +/* + * 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.sort; + +import org.elasticsearch.Version; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.geo.GeoDistance; +import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.text.Text; +import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.InternalSettingsPlugin; +import org.elasticsearch.test.VersionUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.search.sort.SortBuilders.fieldSort; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertOrderedSearchHits; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSortValues; +import static org.hamcrest.Matchers.closeTo; + +public class GeoDistanceSortBuilderIT extends ESIntegTestCase { + @Override + protected Collection> nodePlugins() { + return pluginList(InternalSettingsPlugin.class); + } + + public void testManyToManyGeoPoints() throws ExecutionException, InterruptedException, IOException { + /** + * | q | d1 | d2 + * | | | + * | | | + * | | | + * |2 o| x | x + * | | | + * |1 o| x | x + * |___________________________ + * 1 2 3 4 5 6 7 + */ + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point")); + XContentBuilder d1Builder = jsonBuilder(); + GeoPoint[] d1Points = {new GeoPoint(3, 2), new GeoPoint(4, 1)}; + createShuffeldJSONArray(d1Builder, d1Points); + + XContentBuilder d2Builder = jsonBuilder(); + GeoPoint[] d2Points = {new GeoPoint(5, 1), new GeoPoint(6, 2)}; + createShuffeldJSONArray(d2Builder, d2Points); + + logger.info(d1Builder.string()); + logger.info(d2Builder.string()); + indexRandom(true, + client().prepareIndex("index", "type", "d1").setSource(d1Builder), + client().prepareIndex("index", "type", "d2").setSource(d2Builder)); + ensureYellow(); + GeoPoint[] q = new GeoPoint[2]; + if (randomBoolean()) { + q[0] = new GeoPoint(2, 1); + q[1] = new GeoPoint(2, 2); + } else { + q[1] = new GeoPoint(2, 2); + q[0] = new GeoPoint(2, 1); + } + + SearchResponse searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + assertOrderedSearchHits(searchResponse, "d1", "d2"); + assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 3, 2, DistanceUnit.KILOMETERS), 0.01d)); + assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 5, 1, DistanceUnit.KILOMETERS), 0.01d)); + + searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("min").order(SortOrder.DESC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + assertOrderedSearchHits(searchResponse, "d2", "d1"); + assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 5, 1, DistanceUnit.KILOMETERS), 0.01d)); + assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 3, 2, DistanceUnit.KILOMETERS), 0.01d)); + + searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("max").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + assertOrderedSearchHits(searchResponse, "d1", "d2"); + assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 4, 1, DistanceUnit.KILOMETERS), 0.01d)); + assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 6, 2, DistanceUnit.KILOMETERS), 0.01d)); + + searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("max").order(SortOrder.DESC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + assertOrderedSearchHits(searchResponse, "d2", "d1"); + assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 6, 2, DistanceUnit.KILOMETERS), 0.01d)); + assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 4, 1, DistanceUnit.KILOMETERS), 0.01d)); + } + + protected void createShuffeldJSONArray(XContentBuilder builder, GeoPoint[] pointsArray) throws IOException { + List points = new ArrayList<>(); + points.addAll(Arrays.asList(pointsArray)); + builder.startObject(); + builder.startArray("location"); + int numPoints = points.size(); + for (int i = 0; i < numPoints; i++) { + builder.value(points.remove(randomInt(points.size() - 1))); + } + builder.endArray(); + builder.endObject(); + } + + public void testManyToManyGeoPointsWithDifferentFormats() throws ExecutionException, InterruptedException, IOException { + /** q d1 d2 + * |4 o| x | x + * | | | + * |3 o| x | x + * | | | + * |2 o| x | x + * | | | + * |1 o|x |x + * |______________________ + * 1 2 3 4 5 6 + */ + Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); + Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); + assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point")); + XContentBuilder d1Builder = jsonBuilder(); + GeoPoint[] d1Points = {new GeoPoint(2.5, 1), new GeoPoint(2.75, 2), new GeoPoint(3, 3), new GeoPoint(3.25, 4)}; + createShuffeldJSONArray(d1Builder, d1Points); + + XContentBuilder d2Builder = jsonBuilder(); + GeoPoint[] d2Points = {new GeoPoint(4.5, 1), new GeoPoint(4.75, 2), new GeoPoint(5, 3), new GeoPoint(5.25, 4)}; + createShuffeldJSONArray(d2Builder, d2Points); + + indexRandom(true, + client().prepareIndex("index", "type", "d1").setSource(d1Builder), + client().prepareIndex("index", "type", "d2").setSource(d2Builder)); + ensureYellow(); + + List qHashes = new ArrayList<>(); + List qPoints = new ArrayList<>(); + createQPoints(qHashes, qPoints); + + GeoDistanceSortBuilder geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); + for (int i = 0; i < 4; i++) { + int at = randomInt(3 - i); + if (randomBoolean()) { + geoDistanceSortBuilder.geohashes(qHashes.get(at)); + } else { + geoDistanceSortBuilder.points(qPoints.get(at)); + } + qHashes.remove(at); + qPoints.remove(at); + } + + SearchResponse searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + assertOrderedSearchHits(searchResponse, "d1", "d2"); + assertThat((Double) searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2.5, 1, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); + assertThat((Double) searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(4.5, 1, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); + + searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(geoDistanceSortBuilder.sortMode("max").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + assertOrderedSearchHits(searchResponse, "d1", "d2"); + assertThat((Double) searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(3.25, 4, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); + assertThat((Double) searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(5.25, 4, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); + + } + + public void testSinglePointGeoDistanceSort() throws ExecutionException, InterruptedException, IOException { + assertAcked(prepareCreate("index").addMapping("type", "location", "type=geo_point")); + indexRandom(true, + client().prepareIndex("index", "type", "d1").setSource(jsonBuilder().startObject().startObject("location").field("lat", 1).field("lon", 1).endObject().endObject()), + client().prepareIndex("index", "type", "d2").setSource(jsonBuilder().startObject().startObject("location").field("lat", 1).field("lon", 2).endObject().endObject())); + ensureYellow(); + + String hashPoint = "s037ms06g7h0"; + + GeoDistanceSortBuilder geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); + geoDistanceSortBuilder.geohashes(hashPoint); + + SearchResponse searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + checkCorrectSortOrderForGeoSort(searchResponse); + + geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); + geoDistanceSortBuilder.points(new GeoPoint(2, 2)); + + searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + checkCorrectSortOrderForGeoSort(searchResponse); + + geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); + geoDistanceSortBuilder.point(2, 2); + + searchResponse = client().prepareSearch() + .setQuery(matchAllQuery()) + .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) + .execute().actionGet(); + checkCorrectSortOrderForGeoSort(searchResponse); + + searchResponse = client() + .prepareSearch() + .setSource( + new SearchSourceBuilder().sort(SortBuilders.geoDistanceSort("location").point(2.0, 2.0) + .unit(DistanceUnit.KILOMETERS).geoDistance(GeoDistance.PLANE))).execute().actionGet(); + checkCorrectSortOrderForGeoSort(searchResponse); + + searchResponse = client() + .prepareSearch() + .setSource( + new SearchSourceBuilder().sort(SortBuilders.geoDistanceSort("location").geohashes("s037ms06g7h0") + .unit(DistanceUnit.KILOMETERS).geoDistance(GeoDistance.PLANE))).execute().actionGet(); + checkCorrectSortOrderForGeoSort(searchResponse); + + searchResponse = client() + .prepareSearch() + .setSource( + new SearchSourceBuilder().sort(SortBuilders.geoDistanceSort("location").point(2.0, 2.0) + .unit(DistanceUnit.KILOMETERS).geoDistance(GeoDistance.PLANE))).execute().actionGet(); + checkCorrectSortOrderForGeoSort(searchResponse); + } + + private void checkCorrectSortOrderForGeoSort(SearchResponse searchResponse) { + assertOrderedSearchHits(searchResponse, "d2", "d1"); + assertThat((Double) searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 1, 2, DistanceUnit.KILOMETERS), 1.e-4)); + assertThat((Double) searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 1, 1, DistanceUnit.KILOMETERS), 1.e-4)); + } + + protected void createQPoints(List qHashes, List qPoints) { + GeoPoint[] qp = {new GeoPoint(2, 1), new GeoPoint(2, 2), new GeoPoint(2, 3), new GeoPoint(2, 4)}; + qPoints.addAll(Arrays.asList(qp)); + String[] qh = {"s02equ04ven0", "s037ms06g7h0", "s065kk0dc540", "s06g7h0dyg00"}; + qHashes.addAll(Arrays.asList(qh)); + } + + public void testCrossIndexIgnoreUnmapped() throws Exception { + assertAcked(prepareCreate("test1").addMapping( + "type", "str_field1", "type=string", + "long_field", "type=long", + "double_field", "type=double").get()); + assertAcked(prepareCreate("test2").get()); + + indexRandom(true, + client().prepareIndex("test1", "type").setSource("str_field", "bcd", "long_field", 3, "double_field", 0.65), + client().prepareIndex("test2", "type").setSource()); + + ensureYellow("test1", "test2"); + + SearchResponse resp = client().prepareSearch("test1", "test2") + .addSort(fieldSort("str_field").order(SortOrder.ASC).unmappedType("string")) + .addSort(fieldSort("str_field2").order(SortOrder.DESC).unmappedType("string")).get(); + + assertSortValues(resp, + new Object[] {new Text("bcd"), null}, + new Object[] {null, null}); + + resp = client().prepareSearch("test1", "test2") + .addSort(fieldSort("long_field").order(SortOrder.ASC).unmappedType("long")) + .addSort(fieldSort("long_field2").order(SortOrder.DESC).unmappedType("long")).get(); + assertSortValues(resp, + new Object[] {3L, Long.MIN_VALUE}, + new Object[] {Long.MAX_VALUE, Long.MIN_VALUE}); + + resp = client().prepareSearch("test1", "test2") + .addSort(fieldSort("double_field").order(SortOrder.ASC).unmappedType("double")) + .addSort(fieldSort("double_field2").order(SortOrder.DESC).unmappedType("double")).get(); + assertSortValues(resp, + new Object[] {0.65, Double.NEGATIVE_INFINITY}, + new Object[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}); + } +} diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoDistanceTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoDistanceTests.java index f101303ee82..a748c3cfd33 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoDistanceTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/GeoDistanceTests.java @@ -19,9 +19,7 @@ package org.elasticsearch.messy.tests; -import org.apache.lucene.util.GeoHashUtils; import org.elasticsearch.Version; -import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.geo.GeoDistance; @@ -29,43 +27,18 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.common.xcontent.json.JsonXContent; -import org.elasticsearch.index.query.GeoDistanceQueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.rest.RestStatus; import org.elasticsearch.script.Script; import org.elasticsearch.script.groovy.GroovyPlugin; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.search.sort.SortBuilders; -import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.InternalSettingsPlugin; import org.elasticsearch.test.VersionUtils; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.List; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; -import static org.elasticsearch.index.query.QueryBuilders.geoDistanceQuery; -import static org.elasticsearch.index.query.QueryBuilders.geoDistanceRangeQuery; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; -import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFirstHit; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertOrderedSearchHits; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; -import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.closeTo; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; /** */ @@ -75,350 +48,6 @@ public class GeoDistanceTests extends ESIntegTestCase { return pluginList(GroovyPlugin.class, InternalSettingsPlugin.class); } - public void testSimpleDistance() throws Exception { - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1") - .startObject("properties").startObject("location").field("type", "geo_point"); - if (version.before(Version.V_2_2_0)) { - xContentBuilder.field("lat_lon", true); - } - xContentBuilder.endObject().endObject().endObject().endObject(); - assertAcked(prepareCreate("test").setSettings(settings).addMapping("type1", xContentBuilder)); - ensureGreen(); - - indexRandom(true, client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() - .field("name", "New York") - .startObject("location").field("lat", 40.7143528).field("lon", -74.0059731).endObject() - .endObject()), - // to NY: 5.286 km - client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject() - .field("name", "Times Square") - .startObject("location").field("lat", 40.759011).field("lon", -73.9844722).endObject() - .endObject()), - // to NY: 0.4621 km - client().prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject() - .field("name", "Tribeca") - .startObject("location").field("lat", 40.718266).field("lon", -74.007819).endObject() - .endObject()), - // to NY: 1.055 km - client().prepareIndex("test", "type1", "4").setSource(jsonBuilder().startObject() - .field("name", "Wall Street") - .startObject("location").field("lat", 40.7051157).field("lon", -74.0088305).endObject() - .endObject()), - // to NY: 1.258 km - client().prepareIndex("test", "type1", "5").setSource(jsonBuilder().startObject() - .field("name", "Soho") - .startObject("location").field("lat", 40.7247222).field("lon", -74).endObject() - .endObject()), - // to NY: 2.029 km - client().prepareIndex("test", "type1", "6").setSource(jsonBuilder().startObject() - .field("name", "Greenwich Village") - .startObject("location").field("lat", 40.731033).field("lon", -73.9962255).endObject() - .endObject()), - // to NY: 8.572 km - client().prepareIndex("test", "type1", "7").setSource(jsonBuilder().startObject() - .field("name", "Brooklyn") - .startObject("location").field("lat", 40.65).field("lon", -73.95).endObject() - .endObject())); - - SearchResponse searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("3km").point(40.7143528, -74.0059731)) - .execute().actionGet(); - assertHitCount(searchResponse, 5); - assertThat(searchResponse.getHits().hits().length, equalTo(5)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6"))); - } - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("3km").point(40.7143528, -74.0059731).optimizeBbox("indexed")) - .execute().actionGet(); - assertHitCount(searchResponse, 5); - assertThat(searchResponse.getHits().hits().length, equalTo(5)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6"))); - } - - // now with a PLANE type - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("3km").geoDistance(GeoDistance.PLANE).point(40.7143528, -74.0059731)) - .execute().actionGet(); - assertHitCount(searchResponse, 5); - assertThat(searchResponse.getHits().hits().length, equalTo(5)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"), equalTo("6"))); - } - - // factor type is really too small for this resolution - - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("2km").point(40.7143528, -74.0059731)) - .execute().actionGet(); - assertHitCount(searchResponse, 4); - assertThat(searchResponse.getHits().hits().length, equalTo(4)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); - } - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("2km").point(40.7143528, -74.0059731).optimizeBbox("indexed")) - .execute().actionGet(); - assertHitCount(searchResponse, 4); - assertThat(searchResponse.getHits().hits().length, equalTo(4)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); - } - - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("1.242mi").point(40.7143528, -74.0059731)) - .execute().actionGet(); - assertHitCount(searchResponse, 4); - assertThat(searchResponse.getHits().hits().length, equalTo(4)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); - } - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceQuery("location").distance("1.242mi").point(40.7143528, -74.0059731).optimizeBbox("indexed")) - .execute().actionGet(); - assertHitCount(searchResponse, 4); - assertThat(searchResponse.getHits().hits().length, equalTo(4)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5"))); - } - - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).from("1.0km").to("2.0km")) - .execute().actionGet(); - assertHitCount(searchResponse, 2); - assertThat(searchResponse.getHits().hits().length, equalTo(2)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("4"), equalTo("5"))); - } - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).from("1.0km").to("2.0km").optimizeBbox("indexed")) - .execute().actionGet(); - assertHitCount(searchResponse, 2); - assertThat(searchResponse.getHits().hits().length, equalTo(2)); - for (SearchHit hit : searchResponse.getHits()) { - assertThat(hit.id(), anyOf(equalTo("4"), equalTo("5"))); - } - - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).to("2.0km")) - .execute().actionGet(); - assertHitCount(searchResponse, 4); - assertThat(searchResponse.getHits().hits().length, equalTo(4)); - - searchResponse = client().prepareSearch() // from NY - .setQuery(geoDistanceRangeQuery("location", 40.7143528, -74.0059731).from("2.0km")) - .execute().actionGet(); - assertHitCount(searchResponse, 3); - assertThat(searchResponse.getHits().hits().length, equalTo(3)); - - // SORTING - - searchResponse = client().prepareSearch().setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("location").point(40.7143528, -74.0059731).order(SortOrder.ASC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 7); - assertOrderedSearchHits(searchResponse, "1", "3", "4", "5", "6", "2", "7"); - - searchResponse = client().prepareSearch().setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("location").point(40.7143528, -74.0059731).order(SortOrder.DESC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 7); - assertOrderedSearchHits(searchResponse, "7", "2", "6", "5", "4", "3", "1"); - } - - public void testDistanceSortingMVFields() throws Exception { - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1") - .startObject("properties").startObject("locations").field("type", "geo_point"); - if (version.before(Version.V_2_2_0)) { - xContentBuilder.field("lat_lon", true).field("coerce", true); - } - xContentBuilder.field("ignore_malformed", true).endObject().endObject().endObject().endObject(); - assertAcked(prepareCreate("test").setSettings(settings).addMapping("type1", xContentBuilder)); - ensureGreen(); - - client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() - .field("names", "New York") - .startObject("locations").field("lat", 40.7143528).field("lon", -74.0059731).endObject() - .endObject()).execute().actionGet(); - - client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject() - .field("names", "New York 2") - .startObject("locations").field("lat", 400.7143528).field("lon", 285.9990269).endObject() - .endObject()).execute().actionGet(); - - client().prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject() - .field("names", "Times Square", "Tribeca") - .startArray("locations") - // to NY: 5.286 km - .startObject().field("lat", 40.759011).field("lon", -73.9844722).endObject() - // to NY: 0.4621 km - .startObject().field("lat", 40.718266).field("lon", -74.007819).endObject() - .endArray() - .endObject()).execute().actionGet(); - - client().prepareIndex("test", "type1", "4").setSource(jsonBuilder().startObject() - .field("names", "Wall Street", "Soho") - .startArray("locations") - // to NY: 1.055 km - .startObject().field("lat", 40.7051157).field("lon", -74.0088305).endObject() - // to NY: 1.258 km - .startObject().field("lat", 40.7247222).field("lon", -74).endObject() - .endArray() - .endObject()).execute().actionGet(); - - - client().prepareIndex("test", "type1", "5").setSource(jsonBuilder().startObject() - .field("names", "Greenwich Village", "Brooklyn") - .startArray("locations") - // to NY: 2.029 km - .startObject().field("lat", 40.731033).field("lon", -73.9962255).endObject() - // to NY: 8.572 km - .startObject().field("lat", 40.65).field("lon", -73.95).endObject() - .endArray() - .endObject()).execute().actionGet(); - - client().admin().indices().prepareRefresh().execute().actionGet(); - - // Order: Asc - SearchResponse searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.ASC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 5); - assertOrderedSearchHits(searchResponse, "1", "2", "3", "4", "5"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); - - // Order: Asc, Mode: max - searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.ASC).sortMode("max")) - .execute().actionGet(); - - assertHitCount(searchResponse, 5); - assertOrderedSearchHits(searchResponse, "1", "2", "4", "3", "5"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); - - // Order: Desc - searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.DESC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 5); - assertOrderedSearchHits(searchResponse, "5", "3", "4", "2", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - - // Order: Desc, Mode: min - searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.DESC).sortMode("min")) - .execute().actionGet(); - - assertHitCount(searchResponse, 5); - assertOrderedSearchHits(searchResponse, "5", "4", "3", "2", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - - searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 5); - assertOrderedSearchHits(searchResponse, "1", "2", "4", "3", "5"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1157d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(2874d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(5301d, 10d)); - - searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.DESC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 5); - assertOrderedSearchHits(searchResponse, "5", "3", "4", "2", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(5301.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(2874.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1157.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(421.2d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(4).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - - assertFailures(client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).sortMode("sum")), - RestStatus.BAD_REQUEST, - containsString("sort_mode [sum] isn't supported for sorting by geo distance")); - } - - // Regression bug: https://github.com/elasticsearch/elasticsearch/issues/2851 - public void testDistanceSortingWithMissingGeoPoint() throws Exception { - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("type1") - .startObject("properties").startObject("locations").field("type", "geo_point"); - if (version.before(Version.V_2_2_0)) { - xContentBuilder.field("lat_lon", true); - } - xContentBuilder.endObject().endObject().endObject().endObject(); - assertAcked(prepareCreate("test").setSettings(settings).addMapping("type1", xContentBuilder)); - ensureGreen(); - - client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject() - .field("names", "Times Square", "Tribeca") - .startArray("locations") - // to NY: 5.286 km - .startObject().field("lat", 40.759011).field("lon", -73.9844722).endObject() - // to NY: 0.4621 km - .startObject().field("lat", 40.718266).field("lon", -74.007819).endObject() - .endArray() - .endObject()).execute().actionGet(); - - client().prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject() - .field("names", "Wall Street", "Soho") - .endObject()).execute().actionGet(); - - refresh(); - - // Order: Asc - SearchResponse searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.ASC)) - .execute().actionGet(); - - assertHitCount(searchResponse, 2); - assertOrderedSearchHits(searchResponse, "1", "2"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); - - // Order: Desc - searchResponse = client().prepareSearch("test").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("locations").point(40.7143528, -74.0059731).order(SortOrder.DESC)) - .execute().actionGet(); - - // Doc with missing geo point is first, is consistent with 0.20.x - assertHitCount(searchResponse, 2); - assertOrderedSearchHits(searchResponse, "2", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(5286d, 10d)); - } - public void testDistanceScript() throws Exception { double source_lat = 32.798; double source_long = -117.151; @@ -503,273 +132,4 @@ public class GeoDistanceTests extends ESIntegTestCase { assertThat(resultDistance8, closeTo(GeoDistance.PLANE.calculate(source_lat, source_long, target_lat, target_long, DistanceUnit.MILES), 0.01d)); } - - public void testDistanceSortingNestedFields() throws Exception { - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("company") - .startObject("properties") - .startObject("name").field("type", "string").endObject() - .startObject("branches") - .field("type", "nested") - .startObject("properties") - .startObject("name").field("type", "string").endObject() - .startObject("location").field("type", "geo_point"); - if (version.before(Version.V_2_2_0)) { - xContentBuilder.field("lat_lon", true); - } - xContentBuilder.endObject() - .endObject() - .endObject() - .endObject() - .endObject().endObject(); - - assertAcked(prepareCreate("companies").setSettings(settings).addMapping("company", xContentBuilder)); - ensureGreen(); - - indexRandom(true, client().prepareIndex("companies", "company", "1").setSource(jsonBuilder().startObject() - .field("name", "company 1") - .startArray("branches") - .startObject() - .field("name", "New York") - .startObject("location").field("lat", 40.7143528).field("lon", -74.0059731).endObject() - .endObject() - .endArray() - .endObject()), - client().prepareIndex("companies", "company", "2").setSource(jsonBuilder().startObject() - .field("name", "company 2") - .startArray("branches") - .startObject() - .field("name", "Times Square") - .startObject("location").field("lat", 40.759011).field("lon", -73.9844722).endObject() // to NY: 5.286 km - .endObject() - .startObject() - .field("name", "Tribeca") - .startObject("location").field("lat", 40.718266).field("lon", -74.007819).endObject() // to NY: 0.4621 km - .endObject() - .endArray() - .endObject()), - client().prepareIndex("companies", "company", "3").setSource(jsonBuilder().startObject() - .field("name", "company 3") - .startArray("branches") - .startObject() - .field("name", "Wall Street") - .startObject("location").field("lat", 40.7051157).field("lon", -74.0088305).endObject() // to NY: 1.055 km - .endObject() - .startObject() - .field("name", "Soho") - .startObject("location").field("lat", 40.7247222).field("lon", -74).endObject() // to NY: 1.258 km - .endObject() - .endArray() - .endObject()), - client().prepareIndex("companies", "company", "4").setSource(jsonBuilder().startObject() - .field("name", "company 4") - .startArray("branches") - .startObject() - .field("name", "Greenwich Village") - .startObject("location").field("lat", 40.731033).field("lon", -73.9962255).endObject() // to NY: 2.029 km - .endObject() - .startObject() - .field("name", "Brooklyn") - .startObject("location").field("lat", 40.65).field("lon", -73.95).endObject() // to NY: 8.572 km - .endObject() - .endArray() - .endObject())); - - // Order: Asc - SearchResponse searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC).setNestedPath("branches")) - .execute().actionGet(); - - assertHitCount(searchResponse, 4); - assertOrderedSearchHits(searchResponse, "1", "2", "3", "4"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); - - // Order: Asc, Mode: max - searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC).sortMode("max").setNestedPath("branches")) - .execute().actionGet(); - - assertHitCount(searchResponse, 4); - assertOrderedSearchHits(searchResponse, "1", "3", "2", "4"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); - - // Order: Desc - searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC).setNestedPath("branches")) - .execute().actionGet(); - - assertHitCount(searchResponse, 4); - assertOrderedSearchHits(searchResponse, "4", "2", "3", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(5286.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1258.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - - // Order: Desc, Mode: min - searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC).sortMode("min").setNestedPath("branches")) - .execute().actionGet(); - - assertHitCount(searchResponse, 4); - assertOrderedSearchHits(searchResponse, "4", "3", "2", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(2029.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1055.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(462.1d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - - searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC).setNestedPath("branches")) - .execute().actionGet(); - - assertHitCount(searchResponse, 4); - assertOrderedSearchHits(searchResponse, "1", "3", "2", "4"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(1157.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(2874.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(5301.0d, 10d)); - - searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort( - SortBuilders.geoDistanceSort("branches.location").setNestedPath("branches") - .point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.DESC).setNestedPath("branches") - ) - .execute().actionGet(); - - assertHitCount(searchResponse, 4); - assertOrderedSearchHits(searchResponse, "4", "2", "3", "1"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(5301.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), closeTo(2874.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), closeTo(1157.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d)); - - searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort( - SortBuilders.geoDistanceSort("branches.location").setNestedFilter(termQuery("branches.name", "brooklyn")) - .point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC).setNestedPath("branches") - ) - .execute().actionGet(); - assertHitCount(searchResponse, 4); - assertFirstHit(searchResponse, hasId("4")); - assertSearchHits(searchResponse, "1", "2", "3", "4"); - assertThat(((Number) searchResponse.getHits().getAt(0).sortValues()[0]).doubleValue(), closeTo(8572.0d, 10d)); - assertThat(((Number) searchResponse.getHits().getAt(1).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); - assertThat(((Number) searchResponse.getHits().getAt(2).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); - assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE)); - - assertFailures(client().prepareSearch("companies").setQuery(matchAllQuery()) - .addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("sum").setNestedPath("branches")), - RestStatus.BAD_REQUEST, - containsString("sort_mode [sum] isn't supported for sorting by geo distance")); - } - - /** - * Issue 3073 - */ - public void testGeoDistanceFilter() throws IOException { - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - double lat = 40.720611; - double lon = -73.998776; - - XContentBuilder mapping = JsonXContent.contentBuilder() - .startObject() - .startObject("location") - .startObject("properties") - .startObject("pin") - .field("type", "geo_point"); - if (version.before(Version.V_2_2_0)) { - mapping.field("lat_lon", true); - } - mapping.endObject().endObject().endObject().endObject(); - - XContentBuilder source = JsonXContent.contentBuilder() - .startObject() - .field("pin", GeoHashUtils.stringEncode(lon, lat)) - .endObject(); - - assertAcked(prepareCreate("locations").setSettings(settings).addMapping("location", mapping)); - client().prepareIndex("locations", "location", "1").setCreate(true).setSource(source).execute().actionGet(); - refresh(); - client().prepareGet("locations", "location", "1").execute().actionGet(); - - SearchResponse result = client().prepareSearch("locations") - .setQuery(QueryBuilders.matchAllQuery()) - .setPostFilter(QueryBuilders.geoDistanceQuery("pin") - .geoDistance(GeoDistance.ARC) - .point(lat, lon) - .distance("1m")) - .execute().actionGet(); - - assertHitCount(result, 1); - } - - private double randomLon() { - return randomDouble() * 360 - 180; - } - - private double randomLat() { - return randomDouble() * 180 - 90; - } - - public void testDuelOptimizations() throws Exception { - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - if (version.before(Version.V_2_2_0)) { - assertAcked(prepareCreate("index").setSettings(settings) - .addMapping("type", "location", "type=geo_point,lat_lon=true")); - } else { - assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point")); - } - final int numDocs = scaledRandomIntBetween(3000, 10000); - List docs = new ArrayList<>(); - for (int i = 0; i < numDocs; ++i) { - docs.add(client().prepareIndex("index", "type").setSource(jsonBuilder().startObject().startObject("location") - .field("lat", randomLat()).field("lon", randomLon()).endObject().endObject())); - } - indexRandom(true, docs); - ensureSearchable(); - - for (int i = 0; i < 10; ++i) { - final double originLat = randomLat(); - final double originLon = randomLon(); - final String distance = DistanceUnit.KILOMETERS.toString(randomIntBetween(1, 10000)); - for (GeoDistance geoDistance : Arrays.asList(GeoDistance.ARC, GeoDistance.SLOPPY_ARC)) { - logger.info("Now testing GeoDistance={}, distance={}, origin=({}, {})", geoDistance, distance, originLat, originLon); - GeoDistanceQueryBuilder qb = QueryBuilders.geoDistanceQuery("location").point(originLat, originLon).distance(distance).geoDistance(geoDistance); - long matches; - if (version.before(Version.V_2_2_0)) { - for (String optimizeBbox : Arrays.asList("none", "memory", "indexed")) { - qb.optimizeBbox(optimizeBbox); - SearchResponse resp = client().prepareSearch("index").setSize(0) - .setQuery(QueryBuilders.constantScoreQuery(qb)).execute().actionGet(); - matches = assertDuelOptimization(resp); - logger.info("{} -> {} hits", optimizeBbox, matches); - } - } else { - SearchResponse resp = client().prepareSearch("index").setSize(0) - .setQuery(QueryBuilders.constantScoreQuery(qb)).execute().actionGet(); - matches = assertDuelOptimization(resp); - logger.info("{} hits", matches); - } - } - } - } - - private long assertDuelOptimization(SearchResponse resp) { - long matches = -1; - assertSearchResponse(resp); - if (matches < 0) { - matches = resp.getHits().totalHits(); - } else { - assertEquals(matches, matches = resp.getHits().totalHits()); - } - return matches; - } } diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/SimpleSortTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/SimpleSortTests.java index b0c77f54197..bae2eb552d1 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/SimpleSortTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/SimpleSortTests.java @@ -24,18 +24,13 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.UnicodeUtil; -import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchPhaseExecutionException; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.geo.GeoDistance; -import org.elasticsearch.common.geo.GeoPoint; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.text.Text; -import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.mapper.Uid; @@ -46,15 +41,12 @@ import org.elasticsearch.script.Script; import org.elasticsearch.script.groovy.GroovyPlugin; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHitField; -import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.search.sort.GeoDistanceSortBuilder; import org.elasticsearch.search.sort.ScriptSortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.InternalSettingsPlugin; -import org.elasticsearch.test.VersionUtils; import org.hamcrest.Matchers; import java.io.IOException; @@ -77,7 +69,6 @@ import static org.elasticsearch.index.query.QueryBuilders.functionScoreQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.fieldValueFactorFunction; -import static org.elasticsearch.search.sort.SortBuilders.fieldSort; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFirstHit; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; @@ -85,7 +76,6 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFa import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertOrderedSearchHits; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSecondHit; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSortValues; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.containsString; @@ -1718,258 +1708,4 @@ public class SimpleSortTests extends ESIntegTestCase { assertThat(multiShardResponse.getHits().getAt(i).id(), equalTo(singleShardResponse.getHits().getAt(i).id())); } } - - public void testManyToManyGeoPoints() throws ExecutionException, InterruptedException, IOException { - /** - * | q | d1 | d2 - * | | | - * | | | - * | | | - * |2 o| x | x - * | | | - * |1 o| x | x - * |___________________________ - * 1 2 3 4 5 6 7 - */ - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point")); - XContentBuilder d1Builder = jsonBuilder(); - GeoPoint[] d1Points = {new GeoPoint(3, 2), new GeoPoint(4, 1)}; - createShuffeldJSONArray(d1Builder, d1Points); - - XContentBuilder d2Builder = jsonBuilder(); - GeoPoint[] d2Points = {new GeoPoint(5, 1), new GeoPoint(6, 2)}; - createShuffeldJSONArray(d2Builder, d2Points); - - logger.info(d1Builder.string()); - logger.info(d2Builder.string()); - indexRandom(true, - client().prepareIndex("index", "type", "d1").setSource(d1Builder), - client().prepareIndex("index", "type", "d2").setSource(d2Builder)); - ensureYellow(); - GeoPoint[] q = new GeoPoint[2]; - if (randomBoolean()) { - q[0] = new GeoPoint(2, 1); - q[1] = new GeoPoint(2, 2); - } else { - q[1] = new GeoPoint(2, 2); - q[0] = new GeoPoint(2, 1); - } - - SearchResponse searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - assertOrderedSearchHits(searchResponse, "d1", "d2"); - assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 3, 2, DistanceUnit.KILOMETERS), 0.01d)); - assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 5, 1, DistanceUnit.KILOMETERS), 0.01d)); - - searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("min").order(SortOrder.DESC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - assertOrderedSearchHits(searchResponse, "d2", "d1"); - assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 5, 1, DistanceUnit.KILOMETERS), 0.01d)); - assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 3, 2, DistanceUnit.KILOMETERS), 0.01d)); - - searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("max").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - assertOrderedSearchHits(searchResponse, "d1", "d2"); - assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 4, 1, DistanceUnit.KILOMETERS), 0.01d)); - assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 6, 2, DistanceUnit.KILOMETERS), 0.01d)); - - searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(new GeoDistanceSortBuilder("location").points(q).sortMode("max").order(SortOrder.DESC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - assertOrderedSearchHits(searchResponse, "d2", "d1"); - assertThat((Double)searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 1, 6, 2, DistanceUnit.KILOMETERS), 0.01d)); - assertThat((Double)searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 4, 1, DistanceUnit.KILOMETERS), 0.01d)); - } - - protected void createShuffeldJSONArray(XContentBuilder builder, GeoPoint[] pointsArray) throws IOException { - List points = new ArrayList<>(); - points.addAll(Arrays.asList(pointsArray)); - builder.startObject(); - builder.startArray("location"); - int numPoints = points.size(); - for (int i = 0; i < numPoints; i++) { - builder.value(points.remove(randomInt(points.size() - 1))); - } - builder.endArray(); - builder.endObject(); - } - - public void testManyToManyGeoPointsWithDifferentFormats() throws ExecutionException, InterruptedException, IOException { - /** q d1 d2 - * |4 o| x | x - * | | | - * |3 o| x | x - * | | | - * |2 o| x | x - * | | | - * |1 o|x |x - * |______________________ - * 1 2 3 4 5 6 - */ - Version version = VersionUtils.randomVersionBetween(random(), Version.V_2_0_0, Version.CURRENT); - Settings settings = Settings.settingsBuilder().put(IndexMetaData.SETTING_VERSION_CREATED, version).build(); - assertAcked(prepareCreate("index").setSettings(settings).addMapping("type", "location", "type=geo_point")); - XContentBuilder d1Builder = jsonBuilder(); - GeoPoint[] d1Points = {new GeoPoint(2.5, 1), new GeoPoint(2.75, 2), new GeoPoint(3, 3), new GeoPoint(3.25, 4)}; - createShuffeldJSONArray(d1Builder, d1Points); - - XContentBuilder d2Builder = jsonBuilder(); - GeoPoint[] d2Points = {new GeoPoint(4.5, 1), new GeoPoint(4.75, 2), new GeoPoint(5, 3), new GeoPoint(5.25, 4)}; - createShuffeldJSONArray(d2Builder, d2Points); - - indexRandom(true, - client().prepareIndex("index", "type", "d1").setSource(d1Builder), - client().prepareIndex("index", "type", "d2").setSource(d2Builder)); - ensureYellow(); - - List qHashes = new ArrayList<>(); - List qPoints = new ArrayList<>(); - createQPoints(qHashes, qPoints); - - GeoDistanceSortBuilder geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); - for (int i = 0; i < 4; i++) { - int at = randomInt(3 - i); - if (randomBoolean()) { - geoDistanceSortBuilder.geohashes(qHashes.get(at)); - } else { - geoDistanceSortBuilder.points(qPoints.get(at)); - } - qHashes.remove(at); - qPoints.remove(at); - } - - SearchResponse searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - assertOrderedSearchHits(searchResponse, "d1", "d2"); - assertThat((Double) searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2.5, 1, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); - assertThat((Double) searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(4.5, 1, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); - - searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(geoDistanceSortBuilder.sortMode("max").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - assertOrderedSearchHits(searchResponse, "d1", "d2"); - assertThat((Double) searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(3.25, 4, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); - assertThat((Double) searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(5.25, 4, 2, 1, DistanceUnit.KILOMETERS), 1.e-4)); - - } - - public void testSinglePointGeoDistanceSort() throws ExecutionException, InterruptedException, IOException { - assertAcked(prepareCreate("index").addMapping("type", "location", "type=geo_point")); - indexRandom(true, - client().prepareIndex("index", "type", "d1").setSource(jsonBuilder().startObject().startObject("location").field("lat", 1).field("lon", 1).endObject().endObject()), - client().prepareIndex("index", "type", "d2").setSource(jsonBuilder().startObject().startObject("location").field("lat", 1).field("lon", 2).endObject().endObject())); - ensureYellow(); - - String hashPoint = "s037ms06g7h0"; - - GeoDistanceSortBuilder geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); - geoDistanceSortBuilder.geohashes(hashPoint); - - SearchResponse searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - checkCorrectSortOrderForGeoSort(searchResponse); - - geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); - geoDistanceSortBuilder.points(new GeoPoint(2, 2)); - - searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - checkCorrectSortOrderForGeoSort(searchResponse); - - geoDistanceSortBuilder = new GeoDistanceSortBuilder("location"); - geoDistanceSortBuilder.point(2, 2); - - searchResponse = client().prepareSearch() - .setQuery(matchAllQuery()) - .addSort(geoDistanceSortBuilder.sortMode("min").order(SortOrder.ASC).geoDistance(GeoDistance.PLANE).unit(DistanceUnit.KILOMETERS)) - .execute().actionGet(); - checkCorrectSortOrderForGeoSort(searchResponse); - - searchResponse = client() - .prepareSearch() - .setSource( - new SearchSourceBuilder().sort(SortBuilders.geoDistanceSort("location").point(2.0, 2.0) - .unit(DistanceUnit.KILOMETERS).geoDistance(GeoDistance.PLANE))).execute().actionGet(); - checkCorrectSortOrderForGeoSort(searchResponse); - - searchResponse = client() - .prepareSearch() - .setSource( - new SearchSourceBuilder().sort(SortBuilders.geoDistanceSort("location").geohashes("s037ms06g7h0") - .unit(DistanceUnit.KILOMETERS).geoDistance(GeoDistance.PLANE))).execute().actionGet(); - checkCorrectSortOrderForGeoSort(searchResponse); - - searchResponse = client() - .prepareSearch() - .setSource( - new SearchSourceBuilder().sort(SortBuilders.geoDistanceSort("location").point(2.0, 2.0) - .unit(DistanceUnit.KILOMETERS).geoDistance(GeoDistance.PLANE))).execute().actionGet(); - checkCorrectSortOrderForGeoSort(searchResponse); - } - - private void checkCorrectSortOrderForGeoSort(SearchResponse searchResponse) { - assertOrderedSearchHits(searchResponse, "d2", "d1"); - assertThat((Double) searchResponse.getHits().getAt(0).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 1, 2, DistanceUnit.KILOMETERS), 1.e-4)); - assertThat((Double) searchResponse.getHits().getAt(1).getSortValues()[0], closeTo(GeoDistance.PLANE.calculate(2, 2, 1, 1, DistanceUnit.KILOMETERS), 1.e-4)); - } - - protected void createQPoints(List qHashes, List qPoints) { - GeoPoint[] qp = {new GeoPoint(2, 1), new GeoPoint(2, 2), new GeoPoint(2, 3), new GeoPoint(2, 4)}; - qPoints.addAll(Arrays.asList(qp)); - String[] qh = {"s02equ04ven0", "s037ms06g7h0", "s065kk0dc540", "s06g7h0dyg00"}; - qHashes.addAll(Arrays.asList(qh)); - } - - public void testCrossIndexIgnoreUnmapped() throws Exception { - assertAcked(prepareCreate("test1").addMapping( - "type", "str_field1", "type=string", - "long_field", "type=long", - "double_field", "type=double").get()); - assertAcked(prepareCreate("test2").get()); - - indexRandom(true, - client().prepareIndex("test1", "type").setSource("str_field", "bcd", "long_field", 3, "double_field", 0.65), - client().prepareIndex("test2", "type").setSource()); - - ensureYellow("test1", "test2"); - - SearchResponse resp = client().prepareSearch("test1", "test2") - .addSort(fieldSort("str_field").order(SortOrder.ASC).unmappedType("string")) - .addSort(fieldSort("str_field2").order(SortOrder.DESC).unmappedType("string")).get(); - - assertSortValues(resp, - new Object[] {new Text("bcd"), null}, - new Object[] {null, null}); - - resp = client().prepareSearch("test1", "test2") - .addSort(fieldSort("long_field").order(SortOrder.ASC).unmappedType("long")) - .addSort(fieldSort("long_field2").order(SortOrder.DESC).unmappedType("long")).get(); - assertSortValues(resp, - new Object[] {3L, Long.MIN_VALUE}, - new Object[] {Long.MAX_VALUE, Long.MIN_VALUE}); - - resp = client().prepareSearch("test1", "test2") - .addSort(fieldSort("double_field").order(SortOrder.ASC).unmappedType("double")) - .addSort(fieldSort("double_field2").order(SortOrder.DESC).unmappedType("double")).get(); - assertSortValues(resp, - new Object[] {0.65, Double.NEGATIVE_INFINITY}, - new Object[] {Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}); - } - }