Thursday, February 9, 2017

Ignore Results Outside of Distance Range

Leave a Comment

I am working with ElasticSearch for an application which deals with "posts". I currently have it working with a geo_point so that it will return all posts ordered by distance from the end-user. While this is working I also need to work in one more aspect for the system.

Posts can be paid for and for instance if I were to pay for my post and choose "Local" as the area range then this post should only show to end-users which are less than or equal to 20 miles away.

I have a column on my index named spotlight_range, is there a way I can create a query to say ignore all records if the spotlight_range = 'Local' and the distance is > 20 miles? I need to do this for several different spotlight ranges. For instance Regional may be 100 miles or less, etc.

My current query looks like this

$params = [     'index' => 'my_index',     'type' => 'posts',     'size' => 25,     'from' => 0,     'body' => [         'sort' => [             '_geo_distance' => [                 'post_location' => [                     'lat' => '44.4759',                     'lon' => '-73.2121'                 ],                 'order' => 'asc',                 'unit' => 'mi'             ]         ],         'query' => [             'filtered' => [                 'query' => [                     'match_all' => []                 ],                 'filter' => [                     'geo_distance' => [                         'distance' => '100mi',                         'post_location' => [                             'lat' => '44.4759',                             'lon' => '-73.2121'                         ]                     ]                 ]             ]         ]     ] ]; 

My index is setup with the following fields.

'id' => ['type' => 'integer'], 'title' => ['type' => 'string'], 'description' => ['type' => 'string'], 'price' => ['type' => 'integer'], 'shippable' => ['type' => 'boolean'], 'username' => ['type' => 'string'], 'post_location' => ['type' => 'geo_point'], 'post_location_string' => ['type' => 'string'], 'is_spotlight' => ['type' => 'boolean'], 'spotlight_range' => ['type' => 'string'], 'created_at' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss'], 'updated_at' => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss'] 

My end goal for this is not specifically to search for distance < X and range = Y but rather to have it filter them out for all types based on distances I specify. The search should return ALL types of ranges but also filter out anything past my specified distance for each range type based on the users lat/lon passed into the query.

I have been looking for a solution to this online without much luck.

1 Answers

Answers 1

I would add a circle geo_shape to the document, centered on post_location and with a radius corresponding to the spotlight_range since you know both information at indexing time. That way you can encode into each post its corresponding "reach".

... 'post_location' => ['type' => 'geo_point'], 'spotlight_range' => ['type' => 'string'], 'reach' => ['type' => 'geo_shape'],            <---- add this 

So a "local" document would look something like this once indexed

{     "spotlight_range": "local",     "post_location": {           "lat": 42.1526,          "lon": -71.7378     },      "reach" : {         "type" : "circle",         "coordinates" : [-71.7378, 42.1526],         "radius" : "20mi"     } } 

Then the query would feature another geo_shape centered on the user's location with the chosen radius and would only retrieve documents whose reach intersects the circle shape in the query.

$params = [     'index' => 'my_index',     'type' => 'posts',     'size' => 25,     'from' => 0,     'body' => [         'sort' => [             '_geo_distance' => [                 'post_location' => [                     'lat' => '44.4759',                     'lon' => '-73.2121'                 ],                 'order' => 'asc',                 'unit' => 'mi'             ]         ],         'query' => [             'filtered' => [                 'query' => [                     'match_all' => []                 ],                 'filter' => [                     'geo_shape' => [                         'reach' => [                            'relation' => 'INTERSECTS',                            'shape' => [                                'type' => 'circle',                                'coordinates' => [-73.2121, 44.4759],                                'radius' => '20mi'                            ]                         ]                     ]                 ]             ]         ]     ] ]; 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment