es中geo point表示:别被官方文档忽悠,实战里这坑我踩过

es中geo point表示:别被官方文档忽悠,实战里这坑我踩过

刚入行搞Elasticsearch的时候,我也以为地理坐标这东西挺简单,不就是经纬度吗?直接往里塞数字完事。结果呢?第一次上线搞定位服务,查询慢得像蜗牛,还经常查不到数据,当时我就懵了。后来折腾了好几天,翻遍了各种技术论坛,才算是摸透了es中geo point表示的门道。今天不扯那些虚的,就聊聊我在项目里实打实遇到的问题和解决办法,希望能帮兄弟们省点头发。

首先得说清楚,es中geo point表示的核心数据结构是lat和lon。很多新手喜欢用数组形式,比如[116.40, 39.90],这确实能跑通,但我强烈建议用对象形式{"lat": 116.40, "lon": 39.90}。为啥?因为数组有时候顺序搞反了,或者解析的时候出了岔子,排查起来能把你逼疯。对象形式语义更明确,尤其是在处理复杂业务逻辑的时候,代码可读性高了不少。记得有一次,因为一个同事手滑把lon写成了lat,导致整个商圈的定位全偏了,查日志查了半天才发现是字段映射的问题,这教训太深刻了。

再来说说精度问题。这是个大坑。默认情况下,es对经纬度的精度处理并不是无限高的。如果你在做高精度的室内定位或者非常精细的区域划分,默认的精度可能不够用。这时候你需要在mapping里显式指定precision参数。比如,你可以设置成"40m",这样es在内部处理空间索引时会更加精确。但是要注意,精度越高,索引体积越大,查询性能也会受影响。我之前的一个项目,因为没注意这个平衡,索引数据量直接翻倍,集群负载飙升,运维同事差点跟我急眼。所以,es中geo point表示的时候,一定要根据业务需求来定精度,别盲目追求高精度。

还有一个容易被忽视的点,就是坐标系的转换。国内大部分地图服务用的是GCJ-02坐标系,而es默认支持的是WGS-84。如果你直接把高德或百度地图拿到的坐标塞进es,那查询出来的位置绝对是错的,而且错得离谱。我见过有人直接硬转,结果偏差了几百米,客户投诉都打爆了。正确的做法是在数据入库前,就在应用层做好坐标系转换,或者使用专门的插件来处理。别指望es能自动帮你搞定这些脏活累活,它只是个搜索引擎,不是GIS系统。

关于查询性能,geo_shape和geo_point虽然都能用,但场景不一样。geo_point适合点查询,比如找附近的餐厅;geo_shape适合面查询,比如判断某个点是否在某个行政区域内。如果你把面数据当成点数据来存,那查询效率会低得让你怀疑人生。我有一次为了省事,把多边形区域简化成了中心点,结果查询结果完全不对,后来重新调整mapping,用了geo_shape类型,虽然配置麻烦了点,但查询速度和质量都上去了。

最后提一嘴,es中geo point表示在聚合分析的时候也有讲究。比如你要做热力图分析,或者按区域统计数量,记得开启doc_values,否则聚合操作会非常慢。还有,别在高频查询的字段上搞太复杂的脚本,es对脚本的支持虽然好,但性能损耗也不小。

总之,搞地理空间数据,细节决定成败。别光看官方文档,多看看实战中的坑,多测测性能。希望这些经验能帮你在es的地理查询路上少踩点雷。毕竟,代码写得好,下班才能早。