7.2 地理数据:带坐标的文档如何旅行 本节摘要:geopoint 类型给文档装上经纬度,距离检索回答"三公里内有哪些网点",边界框检索回答"地图这块区域里有什么";地理聚合再按距离或网格分桶。本节讲 geopoint 的录入形态、两类检索写法与聚合姿势,末尾巡礼反向搜索与跨集群检索,把高级特性的地图边界画完整。 带坐标的旅程 坐标字段的两种录入形态 门店文档带一个 geopoint 字段,录入形态灵活: 经度在前是字符串与数组形态的铁律(地理行业惯例),对象形态最不易出错——团队协作时建议统一用对象。geopoint 底层把坐标编码成可区间比较的数值(地球投影成可排序的一维编码),距离计算与范围裁剪都靠它高效完成。
本节摘要:geo_point 类型给文档装上经纬度,距离检索回答"三公里内有哪些网点",边界框检索回答"地图这块区域里有什么";地理聚合再按距离或网格分桶。本节讲 geo_point 的录入形态、两类检索写法与聚合姿势,末尾巡礼反向搜索与跨集群检索,把高级特性的地图边界画完整。
门店文档带一个 geo_point 字段,录入形态灵活:
PUT branches/_doc/bj-001 { "name": "北苑服务网点", "location": { "lat": 39.9847, "lon": 116.3075 } }
以下形态等价 任选其一保持团队统一: 字符串形态 "116.3075,39.9847" 注意经度在前 数组形态 [116.3075, 39.9847] 同样经度在前 对象形态 lat lon 各自命名 最不易错
经度在前是字符串与数组形态的铁律(地理行业惯例),对象形态最不易出错——团队协作时建议统一用对象。geo_point 底层把坐标编码成可区间比较的数值(地球投影成可排序的一维编码),距离计算与范围裁剪都靠它高效完成。再复杂的形态(多边形、线路)属于 geo_shape 类型的领地,按需另学,网点场景 geo_point 足够。
问法一:三公里内有什么。
GET branches/_search { "query": { "bool": { "must": { "match": { "name": "服务网点" } }, "filter": { "geo_distance": { "distance": "3km", "location": { "lat": 39.9912, "lon": 116.3217 } } } } }, "sort": [ { "_geo_distance": { "location": { "lat": 39.9912, "lon": 116.3217 }, "order": "asc", "unit": "km" } } ] }
geo_distance 放 filter 里(距离是硬条件不是相关性),排序用 _geo_distance 按实际距离升序——响应里每条命中会带一个距离值,前端直接显示"距您 1.2 公里"。
问法二:地图这个框里有什么。
GET branches/_search { "query": { "geo_bounding_box": { "location": { "top_left": { "lat": 40.0100, "lon": 116.2800 }, "bottom_right": { "lat": 39.9700, "lon": 116.3500 } } } } }
地图产品拖动视野时,前端把可视范围换成左上右下两个角点发来即可。两种问法组合上 bool 与其他条件,"框内且营业中且评分高于四"这类复合地理需求照样翻译。

GET branches/_search { "size": 0, "aggs": { "by_ring": { "geo_distance": { "field": "location", "origin": { "lat": 39.9912, "lon": 116.3217 }, "ranges": [ { "to": 1000 }, { "from": 1000, "to": 3000 }, { "from": 3000, "to": 10000 } ] } } } }
geo_distance 聚合按距离环带分桶,"一公里内五家、一到三公里十四家"的覆盖报告一步到位;geohash_grid 聚合按地图网格分格,是热力图与地图打点的数据源,精度参数控制格子大小。第 6 章的嵌套语法在这里原样适用——环带里再嵌服务类型桶,报表立起第二个维度。
本章是高级特性的家,除地理之外再记两个入口,不展开但留路标。反向搜索(percolator):普通流程是"存文档、发查询",它反着来——存查询、发文档,回答"这条新文档会被哪些查询命中"。告警订阅正是此形态:把告警条件存成查询,日志流逐条过堂,命中即报警。跨集群检索:把远端集群登记为友邻,一条请求同时搜本地与远端,并购整合、多地域统一搜索的场景免去了数据搬运。两者加上第 8 章要讲的冻结索引(冷数据搜索),构成高级特性的地图片区——遇到对应场景,知道往哪个门里走。
背景:App 要上"附近的服务网点",产品要求按距离排序、显示距离、三公里内优先展示营业中的。操作:映射建 geo_point 对象形态;查询 filter 里 geo_distance 三公里、must 里 match 营业关键词,排序 _geo_distance 升序;分页沿用 5.3 的浅翻页(结果页场景)。结果:城市热点区域毫秒级响应;乡镇低密度区域偶发"三公里内为空",产品补充了兜底逻辑(无结果时扩大到十公里)。解读:地理查询的两问一聚覆盖了这类功能的全部需求面;"无结果"的兜底是产品侧的地理常识,不是引擎缺陷。变式:要做热力图时把查询换成 geohash_grid 聚合;要按行政区分统计时,写入端补一个区域编码字段(geo_point 反查行政区引擎不做,预计算是正解)。
⚠️ 常见坑:字符串形态经纬度写反(纬度在前),所有距离计算悄悄错位——点是能查出来的,距离全不对,最隐蔽的一类错。统一对象形态加一条录入校验,比事后排错省一下午。
💡 关键直觉:geo_point 解决"点与点、点与框"的关系;行政区、多边形这类"归属"关系应该在写入端预计算成普通字段。引擎擅长算距离,不擅长猜归属。
复杂形态归位。下一章是旅程最壮阔的一段:分片远行——集群解剖、路由再平衡、近实时幕后与备份护航。