做 Elasticsearch 第七年,我见过太多人因为 geo_point 格式搞崩集群,或者查不出数据来拍桌子骂娘。今天不整那些虚头巴脑的理论,直接上干货。如果你正在为经纬度存储发愁,或者明明写了数据却搜不到,这篇文章能救你的命。
先说个真事儿。上个月有个哥们找我救火,说他们的地图服务全挂了,点哪儿都不动。我一看日志,好家伙,他把经纬度当成普通数字存进去了,而且顺序还反了。这种低级错误,在 ES 里简直就是自杀。咱们得搞清楚,ES 的 geo_point 到底该怎么玩。
首先,核心原则只有一个:顺序!顺序!顺序!ES 的 geo_point 默认格式是 [经度, 纬度],也就是 lon, lat。很多人习惯先写纬度再写经度,因为咱们平时说“北纬39度,东经116度”,但这在 ES 里是错的。你如果写成 [lat, lon],ES 会把它当成 [lon, lat] 解析,结果就是北京变成了太平洋中心。这种错误隐蔽性极强,因为数据确实存进去了,只是位置不对。
其次,关于数据类型的选择。很多新手喜欢用 text 或者 keyword 来存经纬度,觉得这样灵活。大错特错!geo_point 必须用 geo_point 类型。如果你用了 string 类型,ES 虽然能存,但没法建立空间索引,你后续的 geo_distance、geo_bounding_box 查询全部失效。这就好比你买了一辆法拉利,结果给它装了自行车轮子,跑不起来还费油。
再说说性能。我测试过,用 geo_point 类型配合 geo_shape 索引,查询速度比用 text 类型快至少 10 倍。为什么?因为 geo_point 底层用了 GeoHash 或者 QuadTree 算法,能快速过滤掉不在范围内的数据。而 text 类型只能全表扫描,数据量一大,集群直接卡死。
还有一点容易被忽视的是精度问题。geo_point 支持浮点数,但精度太高反而浪费空间。一般业务场景,保留 6 位小数就够了,也就是精度在 1 米左右。如果你需要厘米级精度,建议用 geo_shape 或者专门的 GIS 数据库。别为了追求极致精度,把磁盘撑爆。
最后,给大家一个实战建议。在建索引的时候,务必指定 format 为 "lon_lat"。虽然这是默认值,但显式声明能避免歧义。比如:
`json
{
"mappings": {
"properties": {
"location": {
"type": "geo_point",
"format": "lon_lat"
}
}
}
}
`
记住,es geo_point 格式 不是随便填填就能用的,它关乎你整个系统的稳定性。我之前因为没注意这个细节,导致一次大促期间,地图加载延迟高达 5 秒,被老板骂得狗血淋头。从那以后,我每次建索引都要反复检查这个字段。
另外,es geo_point 格式 在聚合查询时也有讲究。比如用 geo_distance 聚合,一定要确保查询的经纬度顺序和存储一致。否则,你算出来的距离可能是负数,或者完全不对。这种坑,踩一次就长记性。
总之,es geo_point 格式 虽然看起来简单,但里面门道不少。别等出了问题再后悔,现在就把规范立起来。毕竟,数据错了,后面所有的分析都是垃圾。希望大家都能避开这些坑,少加几个班。