Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Elastic Search - Sort Geo Locations by distance

Given a Geo location point I am trying to find some sites within 10 Km and sort it by the nearest to the location given.

I managed to return the list of locations within 10km but when I try to sort it I get exceptions:

I am using the following versions of:

<properties>
        <commonscollections>3.2.1</commonscollections>
        <commonslang>2.6</commonslang>
        <spring.data.elasticsearch>1.0.0.BUILD-SNAPSHOT</spring.data.elasticsearch>
        <springversion>3.2.5.RELEASE</springversion>
</properties>

The java code as follow:

public List<SiteResource> findByGeoLocation(Double longitude, Double latitude, String channelKey, String distance) {

        if(StringUtils.isEmpty(distance)){
            distance = defaultRadius;           
        }       
        GeoPoint location = new GeoPoint(latitude, longitude);
        CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("location").within(location, distance+"km"));

        criteriaQuery.addIndices(channelKey);
        criteriaQuery.addTypes("site");

        criteriaQuery.addSort(new Sort(Sort.Direction.ASC, "location"));
        List<SiteResource> sites = esTemplate.queryForList(criteriaQuery, com.company.domain.site.SiteResource.class);
        return sites;
    }

If I remove the line:

criteriaQuery.addSort(new Sort(Sort.Direction.ASC, "location"));

then the code will returns all the locations, the problem is with the sorting

The error I am getting from elasticsearch log:

[2014-03-20 13:37:02,720][DEBUG][action.search.type       ] [Smuggler II] [210a9696a28545f2bbeecf88d64fbad8_20140318_153743][4], node[dB9dCIXMRZGmdUExquMWlQ], [P], s[STARTED]: Failed to execute [org.elasticsearch.action.search.SearchRequest@71b978fe] lastShard [true]
org.elasticsearch.search.SearchParseException: [210a9696a28545f2bbeecf88d64fbad8_20140318_153743][4]: query[ConstantScore(*:*)],from[0],size[-1]: Parse Failure [Failed to parse source [{"from":0,"query":{"match_all":{}},"post_filter":{"geo_distance":{"location":[-2.217753,53.432703],"distance":"10km"}},"sort":[{"location":{"order":"asc"}}]}]]
    at org.elasticsearch.search.SearchService.parseSource(SearchService.java:595)
    at org.elasticsearch.search.SearchService.createContext(SearchService.java:498)
    at org.elasticsearch.search.SearchService.createAndPutContext(SearchService.java:472)
    at org.elasticsearch.search.SearchService.executeDfsPhase(SearchService.java:178)
    at org.elasticsearch.search.action.SearchServiceTransportAction.sendExecuteDfs(SearchServiceTransportAction.java:168)
    at org.elasticsearch.action.search.type.TransportSearchDfsQueryThenFetchAction$AsyncAction.sendExecuteFirstPhase(TransportSearchDfsQueryThenFetchAction.java:85)
    at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction.performFirstPhase(TransportSearchTypeAction.java:216)
    at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction.performFirstPhase(TransportSearchTypeAction.java:203)
    at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction$2.run(TransportSearchTypeAction.java:186)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:701)
Caused by: org.elasticsearch.ElasticsearchIllegalArgumentException: can't sort on geo_point field without using specific sorting feature, like geo_distance
    at org.elasticsearch.index.fielddata.plain.AbstractGeoPointIndexFieldData.comparatorSource(AbstractGeoPointIndexFieldData.java:142)
    at org.elasticsearch.search.sort.SortParseElement.addSortField(SortParseElement.java:222)
    at org.elasticsearch.search.sort.SortParseElement.addCompoundSortField(SortParseElement.java:172)
    at org.elasticsearch.search.sort.SortParseElement.parse(SortParseElement.java:80)
    at org.elasticsearch.search.SearchService.parseSource(SearchService.java:583)
    ... 11 more
[2014-03-20 13:37:02,722][DEBUG][action.search.type       ] [Smuggler II] All shards failed for phase: [dfs]

If someone tell me if it is possible to sort the locations by nearest to me I very much appreciate it.

Many Thanks in advance

like image 634
justMe Avatar asked Mar 20 '14 14:03

justMe


People also ask

Does Elasticsearch support geolocation API?

This is becoming even more relevant with new browsers supporting Geolocation API. Already in master (and in the upcoming 0.9.1 release), elasticsearch comes with rich support for geo location. Lets take a drive down the geo support path:

How does Elasticsearch calculate Geo_distances?

The code is passing along a lat/lon point to Elasticsearch, and a geo_distance is being calculated between that point and every other point in all the documents in the index. If there are a large number of documents, then the time to compute geo_distances on all of them becomes non-trivial.

How to sort based on distance from a specific location?

There is now a new _geo_distance sort type allowing to sort based on a distance from a specific location: On top of that, elasticsearch will now return all the values per hit of fields sorted on, allowing to easily display this important information.

What is Elasticsearch and how does it work?

Elasticsearch is much more than just a search engine: it’s also a powerful analytics tool. One of the awesome things that Elasticsearch provides out of the box is the ability to calculate the distance between geographic points, and order the results by proximity.


1 Answers

Just in case someone else having the same problem we have solved our sorting problem in the following way:

public List<SiteResource> findByGeoLocation(Double longitude, Double latitude, String channelKey, Double distance) {

        if(StringUtils.isEmpty(distance)){
            distance = defaultRadius;           
        }

        GeoDistanceFilterBuilder filter = FilterBuilders.geoDistanceFilter("location").point(latitude, longitude).distance(distance, DistanceUnit.KILOMETERS);

        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withFilter(filter)
                .withSort(SortBuilders.geoDistanceSort("site.location").point(latitude, longitude).order(SortOrder.ASC)).build();

        searchQuery.addIndices(channelKey);
        searchQuery.addTypes("site");

        List<SiteResource> sites = esTemplate.queryForList(searchQuery, com.company.domain.site.SiteResource.class);
        return sites;
    }

Hope it help someone ;)

like image 134
justMe Avatar answered Oct 03 '22 11:10

justMe