The Short Answer
To filter vector-search or retriever results by geographic location, add an
attribute_filter stage with one of three geospatial operators over a location field: geo_radius (within N meters of a point), geo_bounding_box (inside a lat/lon box), or geo_polygon (inside an arbitrary shape). Radius is always in meters. Because it is a real filter stage, geo composes with the rest of a retriever — you can run a semantic vector query, keep only the results within 5km of a location, and apply a metadata filter, all in one request. A document with no location field is simply a non-match; malformed geometry is rejected at request time.The three operators
Each is a condition inside an
attribute_filter stage. The field (location here) holds a geographic point.// geo_radius — within 5,000 meters (5 km) of a center point (haversine)
{ "field": "location", "operator": "geo_radius",
"value": { "center": { "lat": 48.8584, "lon": 2.2945 }, "radius": 5000 } }
// geo_bounding_box — top_left (NW) and bottom_right (SE) corners
{ "field": "location", "operator": "geo_bounding_box",
"value": { "top_left": { "lat": 49.0, "lon": 2.0 },
"bottom_right": { "lat": 48.0, "lon": 3.0 } } }
// geo_polygon — an exterior ring of >= 3 points (auto-closed)
{ "field": "location", "operator": "geo_polygon",
"value": { "exterior": { "points": [
{ "lat": 48.0, "lon": 2.0 }, { "lat": 49.0, "lon": 2.0 },
{ "lat": 49.0, "lon": 3.0 }, { "lat": 48.0, "lon": 3.0 } ] } } }5000. Distances use the haversine formula on a spherical earth, which is accurate to a fraction of a percent at city and metro scale.lat/lon objects vs GeoJSON arrays — the one gotcha
A point can be written two ways, and one of them trips people up:
| Form | Example | Order |
| Object (recommended) | { "lat": 40.7128, "lon": -74.0060 } | named — unambiguous |
| GeoJSON array | [-74.0060, 40.7128] | lon first, then lat |
Which operator should I use — radius, bounding box, or polygon?
| Operator | Use when… | Shape it expresses |
geo_radius | "within X of here" — proximity, delivery range, "near me" | A circle around a point |
geo_bounding_box | a rectangular region, map viewport, or quick metro-area cut | An axis-aligned rectangle (antimeridian-safe) |
geo_polygon | real boundaries — a neighborhood, delivery zone, sales territory, school district | Any closed shape you can trace |
Combining geo with semantic search and metadata (location-aware RAG)
The reason geo lives in a retriever stage rather than a separate endpoint is composition. A single retriever can: run a semantic/vector query over your content, filter to a radius, and apply a metadata constraint — so "find listings that *look like* this photo, within 3km of downtown, under $2,000/month" is one request, not three round-trips and a manual intersection. This is the filtered vector search pattern with a geographic predicate, and it is what makes location-aware RAG and recommendations possible: the language model only ever sees candidates that are both semantically relevant and in the right place.
How fast is it, and where does it fit?
Be honest with yourself about scope: geospatial filtering runs as a scan over the candidate set your retriever produces, not a planet-scale geo index. In practice that is exactly what you want for the common case — you are refining a retrieved or metadata-narrowed set down to the ones in the right place, precisely. The pattern that stays fast: pair geo with a selective metadata filter or a vector query first, so geo evaluates over a focused candidate set rather than an entire large collection. Think "precise geo filtering on your retrieved results," not "the primary index for a billion global points." (Perf characteristics are being measured; this guide states behavior, not benchmark numbers.)
What can you build with it?
geo_radius around the user's location to find the nearest branches, ranked by the semantic or attribute signal you already search on.geo_bounding_box or geo_polygon.Doing it in Mixpeek
Two steps. First, put a
location field on your documents — a { "lat", "lon" } object (or a lon-first GeoJSON array) in the payload, alongside whatever else you index. Then add the operator to a retriever's attribute_filter stage next to your feature_search and metadata filters; the filter operators reference has the exact request shapes and a worked example, and the retriever stage catalog shows where the filter sits in a multi-stage pipeline. Geo works the same whether you run managed indexing or bring your own vectors to MVS — it is a filter over stored payloads, so any namespace with a location field can use it. For the broader picture of how filters interact with the vector search stage, see filtered vector search: pre-, post-, and in-place.