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' ] ] ] ] ] ] ] ];
0 comments:
Post a Comment