PostgreSQL 空间位置(geometry 经纬、点、线、面...)、行政地址(门牌、商圈、行政区...) 相互转换方法

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

标签

PostgreSQL , openstreetmap , 空间位置 , 点 , 线 , 面 , 行政地址 , 转换 , osm2pgsql , poi , 门牌 , 商圈 , 行政区


背景

空间位置(geometry 经纬、点、线、面...)、行政地址(门牌、商圈、行政区...) 相互转换需求,如果你有这方面的素材库,在PostgreSQL里面转换,性能是非常高效的。

例如输入任意一个空间对象,扫描出附近的空间对象,或者包含它的对象,或者它包含的对象。(构图)

输入任意一个空间对象,搜索离他最近的空间对象。

输入任意一个空间对象,以及其他的非空间过滤条件(使用btree_gist插件),搜索出附近的空间对象,或者包含它的对象,或者它包含的对象。或离他最近的空间对象。

DEMO

1、建表,存储空间、实体映射信息。

create table tbl_loc (  
  id int8 primary key,    
  level int2,     -- 空间对象的级别(国、省、市、区、县、街道、建筑、街道)  
  pos geometry,   -- 空间对象的位置(多边形、线段、点)  
  loc_name text   -- 空间对象的描述  
);  

2、创建空间+级别复合索引

create extension btree_gist;  
  
create index idx_tbl_loc_1 on tbl_loc using gist(level, pos);  

3、创建UDF接口函数

create or replace function get_loc_name(  
  int2,  -- 级别(国、省、市、区、县、街道、建筑、街道)  
  geometry    -- 输入一个空间对象(点、线段、多边形),找在某个级别内,离他最近的空间对象,并找出它的描述  
) returns tbl_loc as $$  
select tbl_loc from tbl_loc where level=$1 order by pos <-> $2 limit 1;  
$$ language sql strict;  

4、查看UDF接口函数执行计划

load 'auto_explain';  
set auto_explain.log_analyze =on;  
set auto_explain.log_buffers =on;  
set auto_explain.log_min_duration =0;  
set auto_explain.log_nested_statements =on;  
set auto_explain.log_timing =on;  
set auto_explain.log_verbose =on;  
set client_min_messages =log;  
  
postgres=# select * from get_loc_name(1::int2,st_setsrid(st_makepoint(110+random()*10,30+random()*10),4326));  
LOG:  duration: 0.171 ms  plan:  
Query Text:   
select tbl_loc from tbl_loc where level=$1 order by pos <-> $2 limit 1;  
  
Limit  (cost=0.42..0.96 rows=1 width=107) (actual time=0.168..0.168 rows=1 loops=1)  
  Output: tbl_loc.*, ((pos <-> $2))  
  Buffers: shared hit=6  
  ->  Index Scan using idx_tbl_loc_1 on public.tbl_loc  (cost=0.42..2455327.73 rows=4586107 width=107) (actual time=0.167..0.167 rows=1 loops=1)  
        Output: tbl_loc.*, (pos <-> $2)  
        Index Cond: (tbl_loc.level = $1)  
        Order By: (tbl_loc.pos <-> $2)  
        Buffers: shared hit=6  
LOG:  duration: 0.466 ms  plan:  
Query Text: select * from get_loc_name(1::int2,st_setsrid(st_makepoint(110+random()*10,30+random()*10),4326));  
Function Scan on public.get_loc_name  (cost=0.27..0.28 rows=1 width=74) (actual time=0.451..0.451 rows=1 loops=1)  
  Output: id, level, pos, loc_name  
  Function Call: get_loc_name('1'::smallint, st_setsrid(st_makepoint(('110'::double precision + (random() * '10'::double precision)), ('30'::double precision + (random() * '10'::double precision))), 4326))  
  Buffers: shared hit=6  
    id     | level |                        pos                         |             loc_name               
-----------+-------+----------------------------------------------------+----------------------------------  
 333848315 |     1 | 0101000020E610000000001C7BA1735C400000F03DF1984040 | 8cbcf713c4210ca4bbc09cd4c039c230  
(1 row)  

5、空间位置(geometry 经纬、点、线、面...)、行政地址(门牌、商圈、行政区...) 相互转换压测

首先写入一批随机空间对象数据(以点为例,写入约1亿个点 122536913)

vi test.sql  
  
\set id random(1,2000000000)  
\set level random(1,10)  
insert into tbl_loc values (:id, :level, st_setsrid(st_makepoint(110+random()*10, 30+random()*10), 4326), md5(random()::text)) on conflict(id) do nothing;  
  
  
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 32 -j 32 -T 600  

压测

vi test.sql  
  
select * from get_loc_name(1::int2,st_setsrid(st_makepoint(110+random()*10, 30+random()*10),4326));  
  
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 56 -j 56 -T 120  

性能,TPS: 10.3万。

transaction type: ./test.sql  
scaling factor: 1  
query mode: prepared  
number of clients: 56  
number of threads: 56  
duration: 120 s  
number of transactions actually processed: 12377402  
latency average = 0.543 ms  
latency stddev = 0.171 ms  
tps = 103143.196980 (including connections establishing)  
tps = 103153.166730 (excluding connections establishing)  
script statistics:  
 - statement latencies in milliseconds:  
         0.543  select * from get_loc_name(1::int2,st_setsrid(st_makepoint(110+random()*10, 30+random()*10),4326));  

使用PG的流复制,可以很容易把请求吞吐做上去,哪怕是对外提供高并发的转换类接口服务也是很轻松的。

如何得到 空间位置(geometry 经纬、点、线、面...)、行政地址(门牌、商圈、行政区...) 对应关系

一种方法是通过openstreetmap得到,openstreetmap是开放的,自由的,社会人都可以维护、获取的一个开源空间素材库。

1、导出映射关系

https://www.openstreetmap.org/

pic

https://www.openstreetmap.org/export#map=15/30.2601/120.1653

2、将空间位置(geometry 经纬、点、线、面...)、行政地址(门牌、商圈、行政区...) 对应关系导入到PostgreSQL

https://github.com/openstreetmap/osm2pgsql/releases

sudo yum install -y cmake3 make gcc-c++ boost-devel expat-devel zlib-devel \  
  bzip2-devel postgresql10-devel proj-devel proj-epsg lua-devel   
  
wget wget https://github.com/openstreetmap/osm2pgsql/archive/0.96.0.tar.gz  
tar -zxvf 0.96.0.tar.gz   
cd osm2pgsql-0.96.0/  
  
alias cmake=cmake3  
  
mkdir build && cd build  
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON  
make  
make install  
  
Install the project...  
-- Install configuration: "Debug"  
-- Installing: /usr/local/bin/osm2pgsql  
-- Set runtime path of "/usr/local/bin/osm2pgsql" to ""  
-- Installing: /usr/local/share/man/man1/osm2pgsql.1  
-- Installing: /usr/local/share/osm2pgsql/default.style  
-- Installing: /usr/local/share/osm2pgsql/empty.style  

3、导入到数据

osm2pgsql -d postgres -E 4326 ./map.osm    
 public | planet_osm_line       | table | postgres  
 public | planet_osm_point      | table | postgres  
 public | planet_osm_polygon    | table | postgres  
 public | planet_osm_roads      | table | postgres  

4、查询导入的一些对象

postgres=# select name,way,st_astext(way) from planet_osm_point limit 5;  
  name  |                        way                         |           st_astext             
--------+----------------------------------------------------+-------------------------------  
 湘湖   | 0101000020E6100000924149DCBE0E5E40F67CCD72D92A3E40 | POINT(120.2303992 30.1673805)  
 江虹路 | 0101000020E6100000741200D26D0C5E4030B6B52A2E2F3E40 | POINT(120.1942029 30.1842982)  
 江晖路 | 0101000020E6100000C0C469D2370D5E409862B3C81B2F3E40 | POINT(120.2065321 30.1840177)  
 西兴   | 0101000020E6100000EB1F9FEBD60D5E40433866D993303E40 | POINT(120.2162427 30.189756)  
 滨康路 | 0101000020E6100000E1F725D1810E5E400E034CCFAA2F3E40 | POINT(120.2266734 30.1862001)  
(5 rows)  

参考

https://www.openstreetmap.org/

https://github.com/openstreetmap/osm2pgsql/releases

http://postgis.net/

《OSM(OpenStreetMap) poi、路网 数据导入 PostgreSQL》

《GIS术语 - POI、AOI、LOI、路径、轨迹》

《HTAP数据库 PostgreSQL 场景与性能测试之 47 - (OLTP) 空间应用 - 高并发空间位置更新、多属性KNN搜索并测(含空间索引)末端配送类项目》

《[未完待续] HTAP数据库 PostgreSQL 场景与性能测试之 44 - (OLTP) 空间应用 - 空间包含查询(输入多边形 包含 表内空间对象)》

《HTAP数据库 PostgreSQL 场景与性能测试之 29 - (OLTP) 空间应用 - 高并发空间位置更新(含空间索引)》

《HTAP数据库 PostgreSQL 场景与性能测试之 6 - (OLTP) 空间应用 - KNN查询(搜索附近对象,由近到远排序输出)》

《HTAP数据库 PostgreSQL 场景与性能测试之 5 - (OLTP) 空间应用 - 空间包含查询(表内多边形 包含 输入空间对象)》

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
7月前
|
关系型数据库 分布式数据库 数据库
PolarDB对比X-Engine与InnoDB空间效率
本实验带您体验创建X-Engine和InnoDB两种不同的表存储引擎,通过Sysbench模拟数据注入的过程对比俩种表引擎的空间效率。
545 0
|
3月前
|
安全 关系型数据库 分布式数据库
在PolarDB中能否申请集群的公网地址?
在PolarDB中能否申请集群的公网地址?
40 2
|
3月前
|
存储 关系型数据库 分布式数据库
在PolarDB中,集群地址对应一个代理服务器,主地址也是对应一个代理服务器吗?
在PolarDB中,集群地址对应一个代理服务器,主地址也是对应一个代理服务器吗?
32 0
|
8月前
|
安全 关系型数据库 数据库
创建 PostgreSQL 表空间时没有指定空间的总大小
创建 PostgreSQL 表空间时没有指定空间的总大小
96 1
|
11月前
|
关系型数据库 定位技术 数据库
PostgreSQL技术大讲堂 - 第17讲:Vacuum空间管理工具
PostgreSQL从小白到专家,技术大讲堂 - 第17讲:Vacuum空间管理工具
149 0
|
关系型数据库 PostgreSQL
《PostgreSQL在阿里云的实践与发展》电子版下载地址
《PostgreSQL在阿里云的实践与发展》电子书
76 0
《PostgreSQL在阿里云的实践与发展》电子版下载地址
|
运维 关系型数据库 分布式数据库
《PolarDB for PostgreSQL 从入门到实战》电子版下载地址
本书由阿里云及网易数帆、美创科技、CUUG、恒辉信达等开源生态合作伙伴共同出品,从安装部署到运维实践、开发工具,八大章节轻松入门 PolarDB for PostgreSQL 开源数据库。
137 0
《PolarDB for PostgreSQL 从入门到实战》电子版下载地址
|
并行计算 算法 Cloud Native
PolarDB 开源版 使用PostGIS 数据寻龙点穴(空间聚集分析)- 大数据与GIS分析解决线下店铺选址问题
寻龙点穴是风水学术语。古人说:三年寻龙,十年点穴。意思就是说,学会寻龙脉要很长的时间,但要懂得点穴,并且点得准则难上加难,甚至须要用“十年”时间。 但是,若没正确方法,就是用百年时间,也不能够点中风水穴心聚气的真点,这样一来,寻龙的功夫也白费了。 准确地点正穴心,并不是一件容易的事,对初学者来说如此,就是久年经验老手,也常常点错点偏。 寻龙点穴旨在寻找龙气聚集之地,而现实中,我们也有类似需求,比如找的可能是人气聚集之地。 PolarDB 开源版 使用PostGIS 数据寻龙点穴(空间聚集分析)- 大数据与GIS分析解决线下店铺选址问题
478 0
PolarDB 开源版 使用PostGIS 数据寻龙点穴(空间聚集分析)- 大数据与GIS分析解决线下店铺选址问题
|
关系型数据库 数据库 RDS
《袋鼠云基于阿里云RDS的数据库架构实践》电子版地址
袋鼠云基于阿里云RDS的数据库架构实践
93 0
《袋鼠云基于阿里云RDS的数据库架构实践》电子版地址

相关产品

  • 云原生数据库 PolarDB