Question

In my ElasticSearch index, location is a MultiValueField. When I write a custom scoring formula for my documents involving location, I want the script to pick up on whichever location is the closest to the point in my query.

So, I have this part of my scoring formula:

...
if (!doc['location'].empty && doc['location'].values.length > 1) { 
    least_distance = 10000; 
    foreach (loc_index: doc['location'].values) {
        temp_distance = loc_index.distance(lat, lng); 
        if (temp_distance < least_distance) {
            least_distance = temp_distance;
        }
...

It's not the most elegant (I'm new to mvel and ES), but conceptually I'm first checking to see if doc['location'] indeed has more than one location in it, and if so, go through each of the locations to calculate distance, and keep track of the minimum distance found so far.

When I do this, ElasticSearch is returning an error:

Query Failed [Failed to execute main query]]; nested: PropertyAccessException[[Error: unable to resolve method: org.elasticsearch.common.geo.GeoPoint.distance(java.lang.Double, java.lang.Double)

which I think means that it doesn't want to do .distance() on a GeoPoint, which for some reason is different than a field that I might get by doing doc['location'].

Am I interpreting this situation correctly, and does anybody know of a workaround? Is there a way to just calculate distance (ideally without actually putting all the arithmetic for the distance between two coordinates) using ElasticSearch?

Was it helpful?

Solution

The issue here is that calling .values gives a list of GeoPoint() objects. There is a work around, although we need to do a bit of extra work to pull in the appropriate Java classes. We need to have the latitude and longitude of both points.

import org.elasticsearch.common.geo.GeoDistance;   
import org.elasticsearch.common.unit.DistanceUnit; 
base_point = doc['base_location'].value;

if (!doc['location'].empty && doc['location'].values.length > 1) { 
    foreach (loc_index: doc['location'].values) {
        distance = GeoDistance.PLANE.calculate(loc_index.lat, loc_index.lon, base_point.lat, base_point.lon, DistanceUnit.MILES);         
    }
}

We can get the result in different units described by the enumerable here. We can also use different calculation methodologies (like ARC), described here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top