做GIS这行十年,我见过太多人把Elasticsearch当成万能数据库用。特别是搞地理空间查询的兄弟,一上来就想着怎么把海量轨迹、POI点塞进去。结果呢?集群崩了,查询慢了,老板骂了,头发掉了。今天不整那些虚头巴脑的理论,就聊聊怎么把es写入geo数据这事儿做扎实,全是干货,甚至有点刺耳,但能救命。
先说个真事儿。去年有个客户,搞外卖骑手轨迹分析,每天新增数据几千万条。他们团队觉得Elasticsearch快啊,直接往里面灌点数据,建个geo_point字段完事。结果上线第一天,写入延迟直接飙到几秒,查询一个商圈内的骑手,得等半分钟。老板当场就要砸服务器。我过去一看,好家伙,索引模板都没配,mapping里geo_point字段居然没设精度,坐标精度默认是7位,对于这种高频轨迹数据,完全不够用,而且没做分片规划,单节点压力山大。
这就是典型的“不懂装懂”。很多人以为es写入geo数据就是简单的PUT请求,传个经纬度就完事了。大错特错!geo数据不是普通文本,它涉及复杂的空间索引结构,比如Geohash或者QuadTree。你如果不了解底层原理,写进去的数据就是垃圾,查出来的结果也是垃圾。
咱们来点数据对比。我拿同一批100万条城市POI数据做了测试。方案A:默认配置,不优化。写入耗时平均每条15毫秒,查询半径1公里内的数据,平均响应时间800毫秒。方案B:优化mapping,设置精度为12位,开启doc_values,合理设置分片数。写入耗时降到了每条5毫秒,查询响应时间缩短到50毫秒。这差距,不是一个数量级,是生死之别。
所以,es写入geo数据,第一步不是写代码,是设计Mapping。geo_point字段,必须指定精度。精度越高,查询越快,但存储空间也越大。这个平衡点得自己找。一般来说,对于城市级应用,精度10-12位就够了。别贪多,也别太少。
第二步,批量写入。别一条一条插!用_bulk API。我见过有人循环调用单条插入接口,那速度,蜗牛都嫌慢。用_bulk,一次提交几千条,写入效率提升至少十倍。而且,bulk操作有重试机制,网络抖动也不怕。
第三步,监控和调优。es写入geo数据后,别以为万事大吉。得盯着集群的健康状态。如果绿色变黄色,赶紧查。黄色通常意味着分片副本未分配,可能是磁盘满了,或者节点挂了。这时候,你得有预案。比如,设置合理的refresh_interval,默认是1秒,对于高写入场景,可以调到5秒或10秒,减少I/O压力。
最后,说说情绪。我对那些只会复制粘贴教程的人,真的恨铁不成钢。geo数据是空间数据,有它的特殊性。你把它当普通文本处理,它就得给你颜色看。我见过太多项目因为忽视空间索引优化,最后不得不迁移到PostGIS,花了双倍的钱,受更多的罪。
记住,es写入geo数据,不是简单的数据搬运,是空间计算的艺术。你得尊重数据,尊重算法,尊重硬件。别偷懒,别侥幸。每一次写入,都是对集群的一次考验。
我在这行摸爬滚打十年,见过太多因为一个小配置错误导致的大事故。所以,我劝你,动手前,多读文档,多做测试。别等线上出问题了,才来找我救火。那时候,我也救不了你。
总之,es写入geo数据,细节决定成败。从Mapping设计,到批量操作,再到监控调优,每一步都得抠细节。只有这样,你的系统才能稳如泰山,查询快如闪电。别嫌麻烦,麻烦的是线上故障。
希望这篇帖子,能帮你避开一些坑。毕竟,头发掉了,就长不回来了。