Search inside multiple geo-bounding boxes with Elasticsearch

14/01/2020 — 3 min de lecture
Photo by <a href="https://unsplash.com/@marjan_blan" target="_blank">Марьян Блан | @marjanblan</a> on <a href="https://unsplash.com" target="_blank">Unsplash</a>

Photo by Марьян Блан | @marjanblan on Unsplash

When you build a geographical search, you may want to allow your users to search inside multiple geo-bounding boxes.

Because the official documentation is only demonstrating geo-bounding box search using the filter constraint, you may have noticed that specifying many boxes will result in searching inside their intersection. For example, this query :

{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : [
                {
                    "geo_bounding_box" : {
                        "pin.location" : {
                            "top_left" : [-80.3, 40.73],
                            "bottom_right" : [-71.12, 40.02]
                        }
                    }
                },
                {
                    "geo_bounding_box" : {
                        "pin.location" : {
                            "top_left" : [-72.1, 44.25],
                            "bottom_right" : [-60.25, 40.51]
                        }
                    }
                }
            ]
        }
    }
}

Will give us the same results as :

"geo_bounding_box" : {
    "pin.location" : {
        "top_left" : [-72.1, 40.73],
        "bottom_right" : [-71.12, 40.51]
    }
}

Since we don't want to search inside their intersection, but only to extend the search for every geo-bounding box specified, the trick is to use should along with minimum_should_match :

{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "minimum_should_match": 1,
            "should" : [
                {
                    "geo_bounding_box" : {
                        "pin.location" : {
                            "top_left" : [-80.3, 40.73],
                            "bottom_right" : [-71.12, 40.02]
                        }
                    }
                },
                {
                    "geo_bounding_box" : {
                        "pin.location" : {
                            "top_left" : [-72.1, 44.25],
                            "bottom_right" : [-60.25, 40.51]
                        }
                    }
                }
            ]
        }
    }
}

That way, we only accept results that match at least 1 specified geo-bounding box.