Gravatar for wvuong@captechconsulting.com

Question by wvuong, Aug 18, 2016 9:30 AM

Sorting Results Based on Distance

I know the Coveo JS framework currently supports sorting results based on the distance, but i have a scenario where one item can have multiple locations and I want Coveo to sort my results using the item's closest location to me. Does Coveo support this functionality?

I was also thinking I could duplicate the item for each location and then have Coveo filter out duplicates only based on the item's name for instance. I know Coveo supports filtering duplicates but can we specify which fields it uses to figure out if an item is a duplicate?

Gravatar for ssartell@rightpoint.com

Comment by ssartell, Sep 29, 2016 12:24 PM

Did you ever get this working? I'm running into the same scenario and would love not to have to reinvent the wheel.

Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Sep 29, 2016 1:21 PM

You'll want to use folding. https://developers.coveo.com/display/public/SearchREST/Query+Parameters#QueryParameters-filterField

This will combine results that have the same value for the designated field, while still giving you access to all the children results. You can then do your normal sort by distance as documented by Coveo.

Gravatar for ssartell@rightpoint.com

Comment by ssartell, Oct 3, 2016 10:00 AM

But really I want the min distance of all the child results and then sort by distance. Can that actually work with folding? Can a parent have a calculated field based on the children?

Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Oct 3, 2016 10:07 AM

Yes, it sounds like you have the same use case I did. Let's say we have a store with 3 locations. Coveo will fold them and the parent will be the closest one based on my testing.

Folding is fairly simple to implement so you could test this relatively quickly.

Gravatar for ssartell@rightpoint.com

Comment by ssartell, Oct 3, 2016 11:38 AM

Definitely the exact same case. I understand how the folding parameters work that would allow me to group all the locations under the same result and how to calculate distance using query function, but I just can't see how you got Coveo to sort by the minimum distance of all the child items. What am I missing?

Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Oct 3, 2016 11:43 AM

So you want the child results to be sorted as well? I'm not sure if Coveo does that, if it didn't then you could possibly sort that yourself client side after the query completes.

In my case, the sorting of the child results didn't matter.

Gravatar for ssartell@rightpoint.com

Comment by ssartell, Oct 3, 2016 4:53 PM

No, in my scenario I want to sort the parents based on the nearest child (i.e. the min distance of all the children). I don't care about sorting or even showing the children, just sorting the parents.

1 Reply
Gravatar for jflheureux@coveo.com

Answer by Jean-François L'Heureux, Aug 18, 2016 1:38 PM

Hi William,

Coveo distance sorting works with a Query Function (QF) that creates an additional field on search results calculated from their proximity from a fixed location. To work, the results location need to be stored in a latitude and longitude floating point fields.

In your case, having multiple locations per search result implies your latitudes and longitudes are probably stored in a single multi-value facet string field which isn't supported for distance calculation.

If you have a fixed maximum number of locations per search result, you could store each latitude and longitude in separate floating point fields and determine the shortest distance of a search result from a fixed location using the min() query function and use the resulting @shortestDistance field as your sort field. Example with only 2 possible locations:

$qf(function:'min(dist(@latitude1, @longitude1, 46.8167, -71.2167), dist(@latitude2, @longitude2, 46.8167, -71.2167))', fieldName: 'shortestDistance')

If you don't have a fixed number of locations per search result, I think you could craft a more complex query function that would iterate each latitude/longitude to calculate the distance and keep only the shortest. That would require string to float conversion, array iteration, variable definition… All the syntax of ExprTk is supported. I never tried it but it might be feasible.

As for the duplicate filtering, the logic to determine duplicates is fixed. The index is comparing the body, title and other properties of documents to determine if they are the same. I'm not sure if a single different field value would make all the results unique or duplicates.

I hope this helps,

Jeff

Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Aug 18, 2016 1:43 PM

When you say all the syntax of ExprTk is supported, where would I write this code?

I assume I would make some function like dist that takes in some parameters (array of distances) and then I could do my calculations to a return a value, but I'm not sure where to actually include that function

Gravatar for jflheureux@coveo.com

Comment by Jean-François L'Heureux, Aug 18, 2016 1:58 PM

You would do it directly in the Query Function like this:

$qf(function:'YOUR CUSTOM ExprTk CODE HERE', fieldName: 'shortestDistance')
Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Aug 18, 2016 2:41 PM

So for instance would the following:

$qf(function:'return 24;', fieldName: 'shortestDistance')

put the value 24 in shortestDistance?

Gravatar for jflheureux@coveo.com

Comment by Jean-François L'Heureux, Aug 18, 2016 2:46 PM

Exactly yes!

Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Aug 26, 2016 11:03 PM

So would I be writing all the ExprTk code inline?

Can you provide details on how/where the min/dist function is created?

I assume its created as documented here: https://developers.coveo.com/display/public/SearchREST/Implementing+Query+Extensions

Is this something I can do when using Coveo Cloud and not on premise?

Gravatar for sbelzile@coveo.com

Comment by Sébastien Belzile, Aug 29, 2016 8:17 AM

Jeff is on holiday, I will answer in his place.

"Can you provide details on how/where the min/dist function is created?": You know how to find the distance between two points: sqrt((y2-y1)^2 + (x2-x1)^2), do this for every points and always keep the minimum in a variable.

https://developers.coveo.com/display/public/SearchREST/Implementing+Query+Extensions : I think you could use this feature to simplify your code if you need to use your query function to many places. Otherwise the OOTB extension does the job: https://developers.coveo.com/display/public/SearchREST/Standard+Query+Extensions#StandardQueryExtensions-$qf

"Is this something I can do when using Coveo Cloud and not on premises?": This works with Coveo Cloud and CES 7, so yes.

Gravatar for wvuong@captechconsulting.com

Comment by wvuong, Aug 29, 2016 9:07 AM

This makes sense but I don't know how many locations an item will have ahead of time, so instead of having "min(dist(@latitude1, @longitude1, 46.8167, -71.2167), dist(@latitude2, @longitude2, 46.8167, -71.2167))" like Jeff suggested, I would need to use an array, parse it, and then create all the QF.

I would think that I need to create my function that does this in the same spot that dist exists, which I'm not sure where that is.

Ask a question