Points Closest to the Origin

Spatialized founder Jozef Sorocin
Jozef Soročin
Book a consultation ↗
4 min read  •  Updated 07/13/2025

As we've established in From the Viewport to the Query , any rectangle or bounding box can be targeted using the geo_bounding_box query.

Similarly, any polygon (incl. polygon circles) can be targeted through the geo_polygon query.

But what if we want all points that lie within a certain distance from an origin point? Think the nearest restaurants, the closest Uber driver, etc. That's what the geo_distance query is for.

I want to retrieve restaurants that serve pizza and lie within 0.5 miles of an origin geo point. I also want to give precedence to those that are closer to the origin:

Imaginary Restaurants in Midtown Manhattan. Map courtesy of http://geojson.io/

Imaginary Restaurants in Midtown Manhattan. Map courtesy of geojson.io

Imaginary Restaurants in Midtown Manhattan. Map courtesy of http://geojson.io/
PUT restaurants
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      },
      "menu": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
POST restaurants/_doc
{
  "name": "French Eatery",
  "location": [-74.00620, 40.73981],
  "menu": [
    "european",
    "french",
    "pizza"
  ]
}

POST restaurants/_doc
{
  "name": "Flatiron Streetfood",
  "location": [-73.99500, 40.74039],
  "menu": [
    "pizza",
    "kebab"
  ]
}

We'll first apply a simple match query to target pizza restaurants:

{
  "match": {
    "menu": "pizza"
  }
}

Next, we'll be utilizing a geo_distance query but will need to keep in mind that it's a purely boolean, constant-score query — meaning it'll assign a score of 1 to any docs it matches and filter out those that are too far away:

{
  "geo_distance": {
    "distance": "0.5mi",
    "location": [-73.9982, 40.7388]
  }
}

So on top of that, we'll apply a decay function_score query which is a fancy way of saying "the further one moves from the origin, the lower the location's score":

{
  "function_score": {
    "functions": [
      {
        "exp": {
          "location": {
            "origin": [-73.9982, 40.7388],
            "scale": "0.5mi"
          }
        }
      }
    ]
  }
}

Let's envelop them all in a must query:

POST restaurants/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "menu": "pizza"
          }
        },
        {
          "geo_distance": {
            "distance": "0.5mi",
            "location": [-73.9982, 40.7388]
          }
        },
        {
          "function_score": {
            "functions": [
              {
                "exp": {
                  "location": {
                    "origin": [-73.9982, 40.7388],
                    "scale": "0.5mi"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

There's a whole bunch of decay functions to choose from but I went with the exponential exp which has the smoothest decay curve.

Join 200+ developers who've mastered this! Get Lifetime Access — $5
Already a member? Sign in here