栏目分类
热点资讯
PostgreSQL+GeoHash地图点位聚合实现代码
发布日期:2025-01-04 11:03 点击次数:174
PG数据库安装扩展
需要用到pg数据库的空间扩展postgis,在进行操作之前需要在数据库中安装扩展。
GeoHash
GeoHash是一种地址编码方法。他能够把二维的空间经纬度数据编码成一个字符串。具体原理这里不再详细说明,GeoHash算法大体上分为三步:
将经纬度变成二进制将经纬度的二进制合并通过Base32对合并后的二进制进行编码
Geohash比直接用经纬度的高效很多,而且使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。
GeoHash用一个字符串表示经度和纬度两个坐标。在数据库中可以实现在一列上应用索引(某些情况下无法在两列上同时应用索引)GeoHash表示的并不是一个点,而是一个矩形区域GeoHash编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索编码越长,表示的范围越小,位置也越精确。因此我们就可以通过比较GeoHash匹配的位数来判断两个点之间的大概距离
建表
在创建数据库表时,表中除了经纬度字段以外,再创建两个字段:
① 经纬度对应的Geometry字段(类型:geometry)
② 经纬度对应的geoHash值字段(类型:varchar)
如:alter table 表名 add 字段名 geometry(point, 4326); // 创建geometry字段alter table 表名 add 字段名 varchar; // 创建geoHash字段
JPA中定义
根据经纬度计算 geometry 和 geoHash
Java生成geometry和geoHash
geometry字段 和 geoHash字段均可以在java代码中根据经纬度生成。
根据经纬度生成geometry
使用org.locationtech.jts.io包下的WKTReader类,可以根据经纬度生成Geometry对象。
根据经纬度生成geoHash
数据库生成geometry和geoHash
当应用中对数据进行新增修改操作时,可以在代码中生成对应的geometry和geoHash字段的值。但有时候数据不在应用中录入,直接由数据工程师写入的话,就会出现:① 经纬度新增了但是geometry和geoHash字段的值为空
② 经纬度更新了但是没有更新geometry和geoHash字段的值
解决:
① 让数据工程师在写入经纬度的同时帮你存入或更新geometry和geoHash字段的值
② 自己手动执行sql语句,重新生成geometry和geoHash字段的值
③ 基于第2步,为表创建触发器,当对表进行insert或update(update更新经纬度字段)操作时,会自动存入或更新geometry和geoHash字段的值
两个相关函数
① ST_GeomFromText 函数
示例:ST_GeomFromText('POINT(120.1307732446746 30.2678227400894)', 4326)
说明:该函数返回经纬度对应的Geometry对象
② st_geohash 函数
示例:st_geohash(ST_GeomFromText('POINT(120.1307732446746 30.2678227400894)', 4326))
说明: 该函数返回经纬度对应的geoHash值
手动执行sql
手动执行sql, 查询所有经纬度不为空的数据,然后更新每条数据的geometry和geoHash字段的值
触发器生成geometry和geoHash
聚合查询
使用JPA的原生sql查询,@Query(nativeQuery = true, value="sql语句")
查询聚合数据
查询聚合详情
优化
geoHash目前聚合后发现在地图上展示效果不好,聚合点在地图上横竖规律排布,因此聚合后我们可以在java代码中进行融合优化处理。
思路:
将聚合后的每组聚合点里的点相加,然后除以聚合点的数量得出一个平均值(可以根据情况在这个平均数上乘以一个比例)
遍历聚合的list,将大于等于平均值的聚合点和小于平均值的聚合点拆开放在两个集合里(分别为A和B)
遍历小于平均值的聚合点集合(A),找到与当前点距离最近的高于平均数的一个聚合点b,把a融合至B
遍历B,重新计算并设置融合后的经纬度
到此这篇关于PostgreSQL+GeoHash地图点位聚合的文章就介绍到这了,更多相关PostgreSQL地图点位聚合内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!