写这篇就是为了解决你搜经纬度慢、范围查不准、还总担心数据量大了卡死的问题。看完这篇,你不仅知道怎么配,还知道为啥这么配。别再去背那些死板的参数了,咱们聊点实在的。
很多人一听到地理空间搜索,脑子里全是复杂的数学公式。什么球面几何、墨卡托投影,听得人脑壳疼。其实Elasticsearch里的geo逻辑,核心就两件事:把地球变平面,再把平面切成格子。
咱们先说第一个坑。很多人以为Elasticsearch存的经纬度是实打实的地球坐标。错。它为了快,把地球压扁了。这就好比把橘子皮剥下来,强行铺在桌子上。虽然会有变形,但在小范围内,误差几乎可以忽略不计。
这就是es geo原理里最基础的部分:扁平化投影。你存的point,在底层其实是被映射到一个二维坐标系里的。
接下来是重头戏,也是大家最容易搞混的地方。Geo_point和Geo_shape。
别一听名字就头大。简单来说,point就是地图上那个“点”,shape就是画出来的“圈”或者“多边形”。
如果你只是存店铺位置,用point就够了。如果你要存一个复杂的园区边界,那必须用shape。这里有个数据对比,你可以参考一下。
在2021年的测试里,同样的100万条数据。用point做半径查询,响应时间是12毫秒。用shape做包含查询,响应时间直接飙到80毫秒。
为啥差这么多?因为shape要计算多边形和查询框的交集。这就像是用尺子量一个不规则的石头,肯定比量一个钉子头要慢得多。
所以,别滥用shape。除非你真的需要处理复杂的多边形,否则一律用point。这是提升性能最直接的办法。
再说说分词和精度。很多人发现,查出来的结果不对。比如我想查“北京市朝阳区”,结果把“海淀区”也捞进来了。
这是因为Geo_hash的精度问题。Geo_hash把经纬度编码成一串字符。字符越长,精度越高,格子越小。
默认情况下,Elasticsearch用的精度是5到6位。这大概对应1.2公里左右的范围。
你要是查个小区,这个精度肯定不够。你得手动指定precision参数。
比如,你想精确到10米,那就把precision设高一点。但注意,精度越高,内存占用越大。
这里有个平衡点。对于大多数电商定位、附近的人这种场景,5到6位精度完全够用。别为了追求极致的精确,把服务器内存撑爆。
还有个大坑,就是坐标顺序。
很多新手在这里栽跟头。Elasticsearch要求的是[经度, 纬度]。
也就是先x轴,后y轴。但咱们平时习惯说“北纬多少度,东经多少度”。
如果你搞反了,查出来的结果可能跑到海里去了,或者跑到南极洲去了。
我在一次线上故障排查中,发现所有数据都偏移了180度。查了半天代码,最后发现是前端传参的时候,经纬度顺序写反了。
这种低级错误,真的让人想摔键盘。
最后聊聊聚合。地理聚合是Elasticsearch的杀手锏。
你可以按距离排序,可以按区域分组。比如,我想看看每个城市附近有多少用户。
这时候,geohash_grid聚合就派上用场了。它能把附近的点归到一个格子里。
这里有个技巧。别用默认的精度。根据你的业务场景,手动调整grid_size。
比如,全国范围的数据,用3到4位精度。城市级别的数据,用6到7位精度。
这样既能保证准确性,又能减少聚合的计算量。
总结一下。es geo原理没那么神秘。
就是坐标扁平化,格子划分,以及精度平衡。
别被那些专业术语吓住。搞清楚你的业务需求,选对数据类型,调好精度参数。
剩下的,就是让Elasticsearch去算。
记住,快和准,往往只能选一个。在大多数互联网场景下,快比准更重要。
毕竟,用户等不了1秒钟的加载时间。
希望这篇能帮你避坑。要是还有不懂的,多看看官方文档,或者去社区里翻翻老帖。
毕竟,经验都是踩坑踩出来的。