做Geo行业这十几年,我看过的坑比吃过的米都多。最近不少同行在群里问,说Elasticsearch里的geo查询慢得像蜗牛,或者结果不准,甚至直接报错。说实话,这真不怪ES,大部分时候是你没搞懂底层逻辑,或者配置太随意。今天我就掏心窝子聊聊es geo查询那些事儿,不整虚的,全是干货。
首先得纠正一个误区,很多人以为把经纬度存进去就能查了。大错特错。你必须在mapping里把字段类型设为geo_point。别偷懒用text或者keyword,那查出来的数据就是废纸。我在早期做项目时,为了省事用了double类型存经纬度,结果后来做范围查询时,地球曲率根本算不准,偏差能达到好几公里。这种低级错误,新手最容易犯。
再来说说性能问题。很多老板抱怨系统卡顿,一查日志,发现是es geo查询全表扫描。为什么?因为你没建空间索引。ES默认是开启的,但如果你为了节省磁盘空间手动关了,或者索引量太大没做分片优化,那查询肯定慢。我见过一个案例,一个物流平台,每天几百万条轨迹数据,查询响应时间高达2秒。后来我把索引结构优化了一下,把高频查询的热点区域单独做了倾斜索引,响应时间直接降到50毫秒以内。这就是经验,光看文档没用,得动手调优。
还有一个大坑,就是geo_distance查询。很多人喜欢用这个查“附近的人”或“附近的店”。但要注意,geo_distance是基于球面距离计算的,如果数据量特别大,而且没有合理的过滤条件,它会非常消耗CPU。我的建议是,先做一个粗略的矩形范围过滤,也就是用geo_bounding_box,把范围缩小到一定程度,再在这个小范围内做精确的圆形距离计算。这样能减少90%以上的无效计算。别一上来就搞全量geo_distance,服务器会哭的。
另外,坐标格式也是个容易出错的地方。ES支持两种格式:数组格式和字符串格式。数组格式是[lon, lat],注意顺序,是经度在前,纬度在后。很多人搞反了,导致查出来的地点在太平洋中心或者南极洲。字符串格式是“lon,lat”,中间用逗号隔开。我推荐用数组格式,因为解析速度快,而且不容易出错。如果你用的是Kibana做可视化,一定要检查坐标轴是否正确,不然图表全是乱的,老板看了直摇头。
最后,聊聊数据清洗。真实世界的数据,经纬度往往是不规范的。有的带小数点后6位,有的带8位,有的甚至缺失。在入库前,一定要做数据清洗。缺失的坐标直接丢弃,或者标记为无效。精度不一致会导致索引大小不一,影响查询效率。我有个习惯,入库前用Python脚本跑一遍数据,把经纬度标准化到小数点后6位,这样既保证了精度,又控制了索引大小。
总结一下,es geo查询看似简单,实则门道很多。从mapping设计,到索引优化,再到查询策略,每一步都不能马虎。别指望靠运气,要靠经验和细节。希望这篇文章能帮你在避坑路上少走弯路。如果有具体问题,欢迎在评论区留言,我看到都会回。毕竟,独乐乐不如众乐乐,大家一起进步才是真本事。记住,技术没有银弹,只有最适合你业务的方案。多测试,多对比,才能找到那个最优解。别怕麻烦,前期的麻烦是为了后期的省心。加油吧,各位同行!