From the Viewport to the Query

From the Viewport to the Query

🏡 Home 📖 Chapter Home 👉 Next

Use Case

I want to retrieve locations
  • that are within the NYC area, defined by a rectangular viewport
  • and boost those that are in Brooklyn, described by a GeoJSON polygon:
Randomly generated points of interest in the NYC area. Base map courtesy of http://geojson.io/
Randomly generated points of interest in the NYC area. Base map courtesy of http://geojson.io/

Approach

Data

Let's create an index:
PUT locations
{
  "mappings": {
    "properties": {
      "geometry": {
        "type": "object",
        "properties": {
          "coordinates": {
            "type": "geo_point"
          }
        }
      }
    }
  }
}
⚠️
Notice how the geometry.coordinates field is explicitly declared as a geo_point. It's tempting to use the geo_shape field type on the whole geometry field because a Point is a valid GeoJSON type (which a geo_shape would accept) but the geo_bounding_box query we'll be using only allows filtering on explicitly declared geo_point fields!
Next, let's add some locations into our index:
POST _bulk
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-73.78964,40.70269]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.14181,40.76044]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.18276,40.85367]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.12306,40.62101]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.0113,40.83436]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.27228,40.72379]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-73.7888,40.59183]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-73.87138,40.86417]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-73.89522,40.71144]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.12918,40.72388]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.04345,40.86526]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.27225,40.84098]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.19762,40.69674]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-73.78374,40.89914]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.23609,40.86037]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-73.94215,40.67004]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.12929,40.60387]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.08588,40.68269]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-74.27447,40.89801]}}
{"index":{"_index":"locations"}}
{"geometry":{"type":"Point","coordinates":[-77.17435,38.98741]}, "meta": "not in nyc"}

Bounding Box Recap

In order to describe an area of a map (that uses the Mercator projection) with minimum points, we'll need a rectangle's opposing corners — typically the south west and the north east:
  • South West → Bottom Left → [ min(x), min(y) ]
  • North East → Top Right → [ max(x), max(y) ]
💡
Many frontend mapping libraries implement a getBounds() method which returns the viewport's NE & SW corners — most notably Mapbox, Google Maps, and Leaflet.
As soon as we've obtained the two points, we can plug them into the geo_bounding_box query:
POST locations/_search
{
  "query": {
    "geo_bounding_box": {
      "geometry.coordinates": {
        "bottom_left": [-74.32457, 40.51119],
        "top_right": [-73.72444, 40.93012]
      }
    }
  }
}
A bounding box encompassing the NYC area
 
Alternatively, the opposing points' coordinates can be deconstructed into a bounding box:

Already purchased? Sign in here.