搞懂geo_shape映射,别再让地图数据乱成一锅粥了

搞懂geo_shape映射,别再让地图数据乱成一锅粥了

前两天有个哥们儿找我吐槽,说他的Elasticsearch里存了一堆地理坐标,结果一查数据,要么查不到,要么查出来的全是隔壁省的数据。我一看他的配置,好家伙,直接用lat/lng两个字段硬扛,连个像样的空间索引都没建。这就像是你让一个盲人去画地图,怎么可能不出错?

其实很多做后端开发的兄弟,一听到geo_shape映射就头大。觉得这东西太学术,太复杂。但说实话,只要搞清楚了原理,它比简单的点查询强大太多了。

咱们先说个真事儿。我有个朋友做物流轨迹分析的,他们公司要统计某个区域在过去一周内有多少辆车经过。如果只用简单的范围查询,那误差大得吓人。比如一个圆形的配送区,你用矩形框去套,角落里的数据要么被误杀,要么被多算。

这时候,geo_shape映射就派上用场了。

它支持多边形、圆形、甚至复杂的几何图形。你可以把配送区域精确地画成一个多边形,然后告诉ES:“只查在这个多边形内部的数据”。这就叫精准打击。

当然,配置起来确实有点门槛。你得先定义好mapping。

比如这样:

`json

PUT /my_index

{

"mappings": {

"properties": {

"location": {

"type": "geo_shape"

}

}

}

}

`

看着挺简单,对吧?但这里有个坑。很多新手直接往里塞经纬度数组,结果查询死活报错。因为geo_shape需要的是WKT格式或者GeoJSON格式。

WKT格式长这样:POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))。

如果你不懂GIS,可能会觉得这玩意儿太硬核。别慌,其实你不需要手敲这些代码。现在有很多前端地图库,比如Leaflet或者OpenLayers,它们能直接把你在地图上画的框,转换成标准的GeoJSON。

你只需要把这个JSON对象,通过API传给后端,后端再存进ES里。

这就解决了数据录入的难题。

接下来是查询环节。这也是最容易翻车的地方。

很多人喜欢用match查询,或者term查询。但在geo_shape面前,这些都不管用。你得用geo_shape查询,并且指定关系。

常用的关系有:intersects(相交)、within(包含)、disjoint(不相交)。

比如,你想找所有经过某条道路的车辆,用intersects最合适。因为车辆可能在道路的任何位置,只要沾边就算。

但如果你想找完全在某个小区内的车辆,就得用within。

这里我要强调一点,geo_shape映射对性能的影响比简单的点查询要大。因为它涉及到复杂的几何计算。

如果你的数据量特别大,比如几亿条轨迹,建议你先做个空间索引优化。比如使用geohash或者grid,虽然精度会稍微牺牲一点,但查询速度能提升好几个数量级。

别为了追求极致的精度,把服务器搞崩了。

另外,还有一个容易被忽视的问题:坐标系。

一定要确保你的数据坐标系和ES默认的一致。通常是WGS84。如果你用的是GCJ02(高德那种),直接存进去,查出来的位置可能偏了几百米。

我见过有人因为没转换坐标系,导致客户投诉说定位不准,最后查了半天才发现是这个问题。

所以,在数据入库前,做个坐标转换是必须的。

总结一下,geo_shape映射虽然上手有点难,但一旦用顺了,你会发现它简直是处理空间数据的利器。

它不是万能的,但在需要精确几何关系的场景下,它无可替代。

别怕麻烦,多试几次。

当你第一次看到查询结果完美匹配你画的图形时,那种成就感,真的爽。

记住,技术这东西,不怕难,就怕你不肯动手试。

本文关键词:geo_shape映射