For AI agents: this page is also available as Markdown at /docs/geo-distance-and-nearest.md. Every docs page is: add .md to its URL. llms.txt lists them all.

Distance sorting and nearest

A distance filter decides which places match. This page is about order: nearest first, relevance that fades with distance, or simply the k closest documents. The examples use the places collection from the Geo search quickstart and measure from Times Square (40.7580, -73.9855).

You want Use
Nearest first, within an area you choose A distance or box filter, plus a sort by distance
Relevance first, closer results higher A decay function in function_score
The distance of each hit Distances in hits
The k nearest, however far geo_nearest
A closeness bonus beside a text query distance_feature

Sort by distance

In the es language, put the Elasticsearch sort in the search body:

{
  "language": "es",
  "query": {
    "query": {"bool": {"filter": [
      {"term": {"category": "cafe"}},
      {"geo_distance": {"distance": "10km", "location": "40.7580,-73.9855"}}
    ]}},
    "sort": [{"_geo_distance": {"location": "40.7580,-73.9855", "order": "asc", "unit": "km"}}]
  },
  "fields": ["name"]
}

The hits come back as p1 (about 0.1 km), p5 (4.2 km) and p2 (6.1 km).

{
  "query": {"bool": {"filter": [
    {"term": {"category": "cafe"}},
    {"geo_distance": {"distance": "10km", "location": "40.7580,-73.9855"}}
  ]}},
  "sort": [{"_geo_distance": {"location": "40.7580,-73.9855", "order": "asc", "unit": "km"}}],
  "_source": ["name"]
}

geodist() is in kilometers. Name the field and point in the call, or set sfield and pt and call geodist() with no arguments:

q=category:cafe&fq={!geofilt sfield=location pt=40.7580,-73.9855 d=10}&sort=geodist(location,40.7580,-73.9855) asc
q=category:cafe&sfield=location&pt=40.7580,-73.9855&fq={!geofilt d=10}&sort=geodist() asc

Distances in hits

Each hit of a distance sort carries its sort values under sort, with the distance in the sort's unit. On the Elasticsearch endpoint this is the usual hits.hits[].sort. On /v1, a geo_distance sort object works with any query language:

{
  "language": "es",
  "query": {"term": {"category": "cafe"}},
  "filters": [{"geo_distance": {"distance": "10km", "location": "40.7580,-73.9855"}}],
  "sort": [{"geo_distance": {"field": "location", "origin": "40.7580,-73.9855", "unit": "km"}}, "name"],
  "fields": ["name"]
}
"hits": [
  {"id": "p1", "sort": [0.106], "fields": {"name": "Harbor Coffee"}},
  {"id": "p5", "sort": [4.246], "fields": {"name": "Hudson Espresso"}},
  {"id": "p2", "sort": [6.093], "fields": {"name": "Bridge Roasters"}}
]

(Distances rounded here.)

Key Meaning
geo_distance.field The geo_point field.
geo_distance.origin The point, in any query point form. Or give lat and lon as numbers.
geo_distance.unit m (default), km, mi, yd, ft, in, cm, mm or nmi, for the reported distance.
geo_distance.mode min or max, for multi-valued fields.
desc Beside geo_distance: true for farthest first.

The MCP search tool takes the same sort object.

Boost nearby results

A decay function scores a document by how far it is from an origin: the full score up to offset, decay (0.5 by default) at offset + scale, and less beyond. Multiply it into the text score and a relevant place a block away ranks above an equally relevant one across town:

{
  "language": "es",
  "query": {"function_score": {
    "query": {"match": {"description": "coffee"}},
    "functions": [
      {"gauss": {"location": {"origin": "40.7580,-73.9855", "scale": "2km", "offset": "500m", "decay": 0.5}}}
    ],
    "boost_mode": "multiply"
  }},
  "fields": ["name", "description"]
}
{
  "query": {"function_score": {
    "query": {"match": {"description": "coffee"}},
    "functions": [
      {"gauss": {"location": {"origin": "40.7580,-73.9855", "scale": "2km", "offset": "500m", "decay": 0.5}}}
    ],
    "boost_mode": "multiply"
  }},
  "_source": ["name", "description"]
}
Parameter Meaning
origin The point to measure from: "lat,lon", [lon, lat], {"lat", "lon"} or "POINT (lon lat)".
scale Required. The distance past offset at which the score falls to decay, such as "2km".
offset Default 0. Distances up to this score fully.
decay Default 0.5, strictly between 0 and 1.

Nearest k

geo_nearest matches the k documents nearest a point, however far they are, the way knn finds the nearest vectors. It is a WarpSearch extension to the Query DSL. On /v1, filters narrow the candidates first, so "the 3 nearest cafes" is the 3 nearest documents that pass the filter, not the 3 nearest places filtered afterwards:

{
  "language": "es",
  "query": {"geo_nearest": {"field": "location", "origin": "40.7580,-73.9855", "k": 3}},
  "filters": [{"term": {"category": "cafe"}}],
  "fields": ["name"]
}

This returns p1, p5 and p2, nearest first. On the Elasticsearch endpoint, send {"query": {"geo_nearest": {...}}}.

Parameter Meaning
field The geo_point field.
origin The point, in any query point form. Or give lat and lon as numbers.
k Required, positive, at most your plan's result window. How many documents to return at most.
max_distance Optional. Stop at this radius, such as "25km", so fewer than k may match.

Use geo_nearest when the answer must have k results even in sparse areas. When the area is what matters ("within 5 km"), a distance filter with a sort by distance is the better fit.

distance_feature scoring

distance_feature gives every document with a point a score of boost * pivot / (pivot + meters) from its nearest point: the full boost at the origin, half of it at pivot. Its usual place is a should clause beside a text query, so it reorders the text matches without adding or removing any:

{
  "language": "es",
  "query": {"bool": {
    "must": [{"match": {"description": "coffee"}}],
    "should": [{"distance_feature": {"field": "location", "origin": "40.7580,-73.9855", "pivot": "1km", "boost": 2}}]
  }},
  "fields": ["name"]
}

The same body, without "language", works on the Elasticsearch endpoint.

Parameter Meaning
field The geo_point field.
origin The point: "lat,lon", [lon, lat], {"lat", "lon"} or "POINT (lon lat)".
pivot Required. The distance at which the score halves, such as "1km".
boost Optional. The score at the origin, to weigh closeness against the text score.

Compared with a decay function, distance_feature adds to the text score rather than multiplying it, and needs only one parameter.

View this page as Markdown

Cookie settings

Optional tracking stays off until you choose it. Your choice applies to this browser for 180 days. Read the details.

Essential storage keeps you signed in, protects forms, and remembers this choice. It is always available.