干了七年搜索和推荐,跟elasticsearch geo打交道的时间比陪女朋友的时间都长。说实话,这玩意儿刚上手觉得挺爽,存个经纬度就能查附近的人,但真到了生产环境,那坑多得能把你埋了。今天不整那些虚头巴脑的理论,就聊聊我最近踩的一个大雷,顺便给兄弟们排排雷。
先说个真事。上个月有个客户,做本地生活服务的,说他们的“附近商家”查询慢得像蜗牛,而且结果还经常不准。我一看日志,好家伙,查询耗时平均800毫秒,这在现在这个追求秒开甚至毫秒级的时代,简直是犯罪。更离谱的是,有些明明在隔壁街区的店,死活搜不到;而有些在地球另一端的店,居然因为坐标漂移被搜出来了。这体验,用户骂街是肯定的。
咱们先看看问题出在哪。很多人觉得,elasticsearch geo不就是存个lat,lon吗?太天真了。那个客户的数据里,经纬度精度居然保留到了小数点后8位甚至更多。你知道这意味着什么吗?意味着你存了个寂寞,还占用了大量的内存和磁盘空间。ES底层用的是geohash或者prefix tree,精度越高,树越深,查询时的计算量呈指数级上升。我对比了一下,把精度从8位砍到6位(大概14米精度),查询速度提升了近40%,内存占用直接降了30%。对于本地生活场景,14米的误差完全在可接受范围内,毕竟没人会为了找一家奶茶店,非要精确到米级,除非你是搞刑侦的。
再说说数据清洗。这是我最恨的一步,也是最容易被忽视的一步。很多业务系统直接拿前端传来的坐标往ES里塞,也不校验。结果呢?有的坐标是空的,有的是0,0,甚至还有那种明显是测试数据的奇葩坐标。我在ES里建了个脚本,专门跑一遍数据清洗,把无效坐标过滤掉,或者标记为异常。这一步虽然麻烦,但能避免后期查询时出现大量无效结果,导致相关性打分混乱。
还有啊,别迷信默认配置。那个客户的mapping里,geo_point字段没指定精度。ES默认精度是25米,但对于某些需要更精细定位的场景,比如共享单车停放点,25米可能就停错地方了。这时候你就得手动指定精度,比如0.01度,大概1公里左右,或者更细。但这有个代价,就是索引体积变大。所以,一定要根据业务需求来权衡,没有最好的配置,只有最适合的配置。
具体怎么做?我给你捋捋步骤。第一步,检查你的mapping,看看geo_point字段的精度设置是否合理。别一股脑儿全用默认值,得结合业务场景。第二步,数据入库前做清洗,过滤掉无效、异常坐标。这一步可以用Logstash或者自己写个ETL脚本,虽然麻烦,但一劳永逸。第三步,查询时加上距离过滤,别只靠相关性打分。比如,你要找1公里内的店,直接加个geo_distance filter,这样结果更精准,排序也更合理。第四步,定期监控查询性能,看看有没有慢查询日志,及时调整索引结构或分片策略。
最后说句心里话,elasticsearch geo这东西,用好了是真香,用不好是真要命。别指望它自动帮你搞定一切,你得懂它背后的原理,得知道数据是怎么存的,查询是怎么执行的。只有这样,你才能在遇到问题时,迅速定位,快速解决。别等到用户骂街了,才想起来去查文档,那时候黄花菜都凉了。
本文关键词:elasticsearch geo