Redisearch Geo sorting

138 views
Skip to first unread message

Davy Meybos

unread,
Sep 25, 2019, 7:23:38 AM9/25/19
to RediSearch Discussion Forum
Hello,

I've just discovered the support in RediSearch for Geo filters. This is looks like a nice feature, but I am wondering if it somehow also could be used for sorting?

Let say you want to build a store locator and allow the user to sort by nearest shops.

The difficulty I see here it that the sorting mechanism needs an input: the users location, so I don't see right now how this can be accomplished. Maybe someone knows a way to get this working.


Meir Shpilraien

unread,
Sep 25, 2019, 9:08:48 AM9/25/19
to RediSearch Discussion Forum
Theoretical aggregation (https://oss.redislabs.com/redisearch/Aggregations.html) should allow you to do this, but I do not think there is currently enough functionality to achieve it. You need to calculate for each results the distance from the user and then sort by the distance. One option is to get the results (locations) and sort them on the client side. Another option is to use RedisGears (https://oss.redislabs.com/redisgears/). Using RedisGears you can run a python script on the server side that perform the search query and calculate for each result, the distance from the user, then it sort the results by the distance and returns them.

If you do choose to use RedisGears, let me know and I can help you do it.

Meir Shpilraien

unread,
Sep 25, 2019, 10:10:17 AM9/25/19
to RediSearch Discussion Forum
Using Gears, the script will look something like this:

import math

USER_LON = 19
USER_LAT = 47

def CreateTouple(t):
lon = float(t[1].split(',')[0])
lat = float(t[1].split(',')[1])
docid = t[0]
return (docid, lon, lat)

'''
1. Perform the redisearch query
2. Remove the first results which is the number of results
3. Put the docid and the location inside a touple
4. Create a touple of (docid, lon, lat)
5. Create a touple of (distance, docid)
6. Sorting by distance
7. Run the exection
'''
GB().\
map(lambda x: execute('FT.SEARCH', 'idx', '@test:[19,47,100,km]')).\
map(lambda x: x[1:]).\
flatmap(lambda x: [(x[i - 1], x[i][1]) for i  in range(len(x)) if i % 2 == 1]).\
map(CreateTouple).\
map(lambda x: (math.sqrt((x[1] - USER_LON)**2 + (x[2] - USER_LAT)**2), x[0])).\
sort().\
run('idx:idx')

And when running it on this data:
127.0.0.1:6379> FT.CREATE idx SCHEMA test GEO
OK
127.0.0.1:6379> FT.ADD idx doc1 1.0 FIELDS test "19.05,47.497"
OK
127.0.0.1:6379> FT.ADD idx doc2 1.0 FIELDS test "19.06,47.498"
OK
127.0.0.1:6379> FT.ADD idx doc3 1.0 FIELDS test "19.07,47.499"
OK
127.0.0.1:6379> FT.ADD idx doc4 1.0 FIELDS test "19.02,47.492"
OK

You will get something like this:
python gears.py ClientExample.py 
[["(0.4924063362711708, 'doc4')", "(0.4995087586819674, 'doc1')", "(0.5016014354046422, 'doc2')", "(0.5038858997828798, 'doc3')"], []]

You can see that inside the Geas script I use RediSearch query to extract the data, then I calculating the distance from the "user" and then I sorting the results.

Don Irwin

unread,
Sep 25, 2019, 2:28:18 PM9/25/19
to RediSearch Discussion Forum
Hi Meir!  I've been looking for the same functionality.  We are doing a POC and this feature is crucial for us.  I was hoping to be able to run a query similar to GEORADIUS WITHDIST:

GEORADIUS vendor-geo -111 33 50 km WITHDIST

to get back the full records and a sortable distance with a search query like:

FT.SEARCH vendors "@geolocation:[-111.9729275 33.4322451 50 km] WITHDIST" SORTBY distance ASC LIMIT 0 5

Michael Masouras

unread,
Sep 25, 2019, 3:28:29 PM9/25/19
to Don Irwin, RediSearch Discussion Forum
+1 - we would also love to have this functionality for the same use case (sort results by distance for the user). 

--
You received this message because you are subscribed to the Google Groups "RediSearch Discussion Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to redisearch+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/redisearch/8ba299de-c204-41eb-b666-e0740b5996e7%40googlegroups.com.

Meir Shpilraien

unread,
Sep 26, 2019, 2:49:24 AM9/26/19
to RediSearch Discussion Forum
Ok we got the message :), created an issue for this and we will try to push it (https://github.com/RediSearch/RediSearch/issues/916).

Until then I came up with another way to do it but it will require to put the LON and the LAT as NUMERIC fields inside the index (there is not need to actually index them), something like this:

127.0.0.1:6379> FT.CREATE idx SCHEMA geo GEO lon NUMERIC NOINDEX lat NUMERIC NOINDEX
OK
127.0.0.1:6379> FT.ADD idx doc1 1.0 FIELDS geo "19.05,47.497" lon 19.05 lat 47.497
OK
127.0.0.1:6379> FT.ADD idx doc2 1.0 FIELDS geo "19.06,47.498" lon 19.06 lat 47.498
OK
127.0.0.1:6379> FT.ADD idx doc3 1.0 FIELDS geo "19.07,47.499" lon 19.07 lat 47.499
OK
127.0.0.1:6379> FT.ADD idx doc4 1.0 FIELDS geo "19.02,47.492" lon 19.02 lat 47.492
OK

Then the query will look like this:

127.0.0.1:6379> FT.AGGREGATE idx @geo:[19,47,100,km] LOAD 2 @lon @lat APPLY "sqrt((@lon - 19)^2 + (@lat - 47)^2)" as dist sortby 1 @dist
1) (integer) 4
2) 1) lon
   2) "19.02"
   3) lat
   4) "47.492"
   5) dist
   6) "0.492406336271"
3) 1) lon
   2) "19.05"
   3) lat
   4) "47.497"
   5) dist
   6) "0.499508758682"
4) 1) lon
   2) "19.06"
   3) lat
   4) "47.498"
   5) dist
   6) "0.501601435405"
5) 1) lon
   2) "19.07"
   3) lat
   4) "47.499"
   5) dist
   6) "0.503885899783"
To unsubscribe from this group and stop receiving emails from it, send an email to redisearch+unsubscribe@googlegroups.com.

Pieter Cailliau

unread,
Sep 26, 2019, 9:02:05 AM9/26/19
to RediSearch Discussion Forum
What's your timeline on this PoC?

We added it to 2.0 scope for now and will try to tackle this once 1.6 is out

Don Irwin

unread,
Sep 26, 2019, 11:51:23 AM9/26/19
to RediSearch Discussion Forum
+1 - thanks @Meir - that's a brilliant and easy solution for now,

@Pieter - I'm running the POC now with our reps.  The workaround @Meir provided will get me through the POC.  This feature will be a nice competitive advantage since I haven't found a means using Elastic or other search platforms to provide this in a single query at the speed of Redis.  Thanks for taking it on and looking at it!
Reply all
Reply to author
Forward
0 new messages