Cesar Angiolucci
Cesar Angiolucci

Reputation: 184

Elasticsearch geo distance query prioritization for large radius

I have a simple elasticsearch 7.4 index, containing multiple establishments with geolocation coordinates assigned to then. As a user in my geolocation app, I'll be requesting all 50 nearby establishments, based on my current location.

The problem with this approach is when the user zooms out of the map (very large radius) it will keep receiving only the nearest establishments in a tiny portion of the map.

I would like to retrieve other results scattered throughout the map by some kind of prioritization, like more well-known companies and partners that demand a higher priority. Google maps do a similar thing, but I'm not sure what kind of prioritization is done there.

What is the best way to achieve this using ES?

My current query is somewhat like this:

GET /places/_search
{
   "size": 50,
   "query": {
      "bool": {
         "must": {
            "match_all": {}
         },
         "filter": {
            "geo_distance": {
               "distance": "10km",
               "coordinates": {
                  "lat": -2.000000,
                  "lon": -4.000000
               }
            }
         }
      }
   },
   "sort": [
      {
         "_geo_distance": {
            "coordinates": {
               "lat": -2.000000,
               "lon": -4.000000
            },
            "order": "asc",
            "unit": "m",
            "distance_type": "arc"
         }
      }
   ]
}

Upvotes: 0

Views: 1171

Answers (1)

Aditya Agarwal
Aditya Agarwal

Reputation: 503

I encountered a similar case in the past, I had 2 fields geo_coordinates and priority of a product, and I had to sort the products using both of these fields by taking some configurable weight of each field
With function score query u can redefine the elastic internal scoring formula, instead of just using text relevance sorting u can ask elastic to include the geo_distance also in the scoring mechanism, there are diff functions u can use for this case I used linear and field_value_factor https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-function-score-query.html

POST geotest/_search
{
  "query": {
    "bool": {
      "must": [
        {
           "match_all": {}
        },
        {
          "function_score": {
            "min_score": 0.1,
            "functions": [
              {
                "weight": 1,//weight of coordinates
                "linear": {
                  "coor": {
                    "offset": "500m",
                    "origin": [
                      106.82,
                      -6.22425
                    ],
                    "scale": "500m"
                  }
                }
              },
              {
                "field_value_factor": {
                  "factor": 1,//weight of priority
                  "field": "priority",
                  "modifier": "log2p"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

just take care of the factor in field_value_factor it's a logarithmic function so u need to adjust its value accordingly

[Edited]
To obtain same score for product at distance 100m and 10km, you have to define an area around the origin which can be done by offset https://www.elastic.co/guide/en/elasticsearch/reference/current/images/decay_2d.png
all the products which lie inside offset radius will have same score and products which lie in scale+offset radius will have decreasing score
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html

Upvotes: 1

Related Questions