地理位置边界框(geo_bounding_box)查询

允许使用一个边界框基于点位置过滤命中的查询。假设以下索引的文档:

PUT /my_locations
{
    "mappings": {
        "properties": {
            "pin": {
                "properties": {
                    "location": {
                        "type": "geo_point"
                    }
                }
            }
        }
    }
}

PUT /my_locations/_doc/1
{
    "pin" : {
        "location" : {
            "lat" : 40.12,
            "lon" : -71.34
        }
    }
}

然后,可以使用geo_bounding_box过滤器执行下面这个简单的查询:

GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top_left" : {
                            "lat" : 40.73,
                            "lon" : -74.1
                        },
                        "bottom_right" : {
                            "lat" : 40.01,
                            "lon" : -71.12
                        }
                    }
                }
            }
        }
    }
}

查询选项

选项 描述

_name

可选,用来标识过滤器名称的字段

validation_method

设置为IGNORE_MALFORMED以接受无效的纬度或经度值的 geo point,设置为COERCE以尝试推断正确的纬度或经度。(默认为 STRICT)。

type

设置为indexedmemory之一,以定义该过滤器是在索引中执行还是在内存中执行。 更多细节见下面的类型。 默认为 memory(即:在内存中执行)。

接受的格式

geo_point类型可以接受地理坐标点的不同表示方式非常相似,过滤器也可以接受它:

作为 lat lon 属性
GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top_left" : {
                            "lat" : 40.73,
                            "lon" : -74.1
                        },
                        "bottom_right" : {
                            "lat" : 40.01,
                            "lon" : -71.12
                        }
                    }
                }
            }
        }
    }
}
作为 lat lon 数组

格式为[lon, lat],注意,此处 lon/lat 的顺序是为了符合GeoJSON

GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top_left" : [-74.1, 40.73],
                        "bottom_right" : [-71.12, 40.01]
                    }
                }
            }
        }
    }
}
作为 lat lon 字符串

格式为lat,lon

GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top_left" : "40.73, -74.1",
                        "bottom_right" : "40.01, -71.12"
                    }
                }
            }
    }
}
}
作为众所周知的文本(Well-Known Text, WKT)的边界框
GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "wkt" : "BBOX (-74.1, -71.12, 40.73, 40.01)"
                    }
                }
            }
        }
    }
}
geohash
GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top_left" : "dr5r9ydj2y73",
                        "bottom_right" : "drj7teegpus6"
                    }
                }
            }
        }
    }
}

当 geohash 用于指定边界框的边界时,geohash 被视为矩形。 边界框的定义方式是:其左上角对应于top_left参数中指定的 geohash 的左上角,其右下角定义为bottom_right参数中指定的 geohash 的右下角。

为了指定与 geohash 的整个区域相匹配的边界框,可以在top_leftbottom_right参数中指定 geohash:

GET my_locations/_search
{
    "query": {
        "geo_bounding_box" : {
            "pin.location" : {
                "top_left" : "dr",
                "bottom_right" : "dr"
            }
        }
    }
}

在本例中,geohash dr将生成边界框查询,其左上角为45.0,-78.75,右下角为39.375,-67.5(为什么呢????)

顶点(Vertices)

边界框的顶点可以由top_leftbottom_righttop_rightbottom_left 参数设置。 除了这种下划线连接的名称格式,还支持小驼峰格式:topLeftbottomRighttopRightbottomLeft。 也可以使用简单的名称topleftbottomright来分别设置值,而不是成对设置值。

GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top" : 40.73,
                        "left" : -74.1,
                        "bottom" : 40.01,
                        "right" : -71.12
                    }
                }
            }
        }
    }
}

geo_point 类型

过滤器要求在相关字段中设置geo_point类型。

一个文档包含多个位置

过滤器可以处理每个文档的多个位置/坐标点。 一旦单个位置/坐标点与过滤器匹配,该文档就将包含在过滤器中。

类型

默认情况下,边界框执行的类型设置为memory,这意味着在内存中检查文档是否落在边界框范围内。 在某些情况下,indexed选项的执行速度会更快(但请注意,在这种情况下,geo_point类型必须有 lat 和 lon 索引)。 请注意,使用indexed选项时,不支持文档的每个字段有多个位置。 这里有一个例子:

GET my_locations/_search
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "pin.location" : {
                        "top_left" : {
                            "lat" : 40.73,
                            "lon" : -74.1
                        },
                        "bottom_right" : {
                            "lat" : 40.10,
                            "lon" : -71.12
                        }
                    },
                    "type" : "indexed"
                }
            }
        }
    }
}

忽略未映射的字段 (ignore unmapped)

如果ignore_unmapped选项设置为true,将忽略未映射的字段,并且此查询不会匹配任何文档。 这在查询可能具有不同映射的多个索引时非常有用。 当设置为false(默认值)时,如果字段未映射,查询将抛出异常。

关于精度的提示

地理坐标点的精度有限,并且在索引时总是向下舍入。 在查询期间,边界框的上边界被向下舍入,而下边界被向上舍入。 因此,由于舍入误差,下边界(边界框的底部和左侧边缘)上的点可能不会进入边界框。 同时,沿着上边界(顶部和右侧边缘)的点可能被查询选中,即使它们位于边缘的稍外侧。 舍入误差在纬度上应小于4.20e-8度,在经度上应小于8.39e-8度,这意味着即使在赤道上误差也小于1厘米。