PgSQL · GIS应用 · 物流, 动态路径规划

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 背景双十一背后的技术系列文章《聊一聊双十一背后的技术 - 分词和搜索》每年双十一的交易额都创新高,今年也不例外,双十一几乎成了各种IT系统的大考,物流也不例外。每次双十一快递几乎都被爆仓,但是随着技术的发展,今年,听说双十一刚过,小伙伴们的包裹差不多都收到了,今年的快递效率怎么如此之高呢?今天,来给大家分享一下物流与背后的数据库技术,当然我讲的还是PostgreSQL, Gre

背景

双十一背后的技术系列文章

《聊一聊双十一背后的技术 - 分词和搜索》

每年双十一的交易额都创新高,今年也不例外,双十一几乎成了各种IT系统的大考,物流也不例外。

每次双十一快递几乎都被爆仓,但是随着技术的发展,今年,听说双十一刚过,小伙伴们的包裹差不多都收到了,今年的快递效率怎么如此之高呢?

今天,来给大家分享一下物流与背后的数据库技术,当然我讲的还是PostgreSQL, Greenplum, PostGIS一类,大伙了解我的。

物流行业是被电子商务催生的产业之一。

快件的配送和揽件的调度算法是物流行业一个非常重要的课题,直接关系到配送或揽件的时效,以及物流公司的运作成本。

好的算法,可以提高时效,降低成本,甚至可以更好的调动社会资源,就像滴滴打车一样,也许能全民参与哦。

以后也许上班路途还能顺路提供快递服务呢。

本文将以物流行业为例,给大家分析一下PostgreSQL与Greenplum在地理位置信息处理,最佳路径算法,机器学习等方面的物流行业应用方法。

要素分析

物流做的事情很简单,寄件,送件。

物流环节的要素有几个,都与位置有关

screenshot

  • 寄件人
  • 揽件员
    PS,揽件人通常不是直接将货收到仓库,而是网点。所以网点到仓库也是需要调度的,本文未涉及。
    调度方法与配送差不太多。

  • 货物
  • 仓库
  • 运输工具
  • 派件员
  • 收件人

如果引入时间属性,则更具有想象空间,例如前面提到的像滴滴打车一样,也许能全民参与哦。

我们这里先从简单的入手,假设现在只关心位置信息。

1. 寄件

货物从寄件人到揽件员,通常是预约的操作,而且寄件人可以直接去网点办理寄件,所以没有太多的算法在里面。

如果派件和揽件混合在一起的话,可以用KNN算法来解决,再结合派件点路径调度,选出最佳的揽件人。

例如,寄件人当前位置,与快递员调度的下一个位置,进行KNN运算,因此B来揽件是成本最低的。

screenshot

2. 货物在仓库之间流转的物流调度

screenshot

假设上图为仓库的位置,两个仓库之间如果开通了线路的话,就以线段连接起来。

每个仓库负责一个区域,这个区域是一个几何的图形。

通过寄件人和收件人的位置,与仓库的区域进行点面判断,找出寄件人的仓库与收件人的仓库。

快件为点,仓库为面,寄件时根据寄件人填写的寄件和收件信息转换为寄件和收件两个经纬度,通过这两个经纬度与快递公司的仓库表进行点面包含的判断匹配,就可以找出快件对应的起点和重点的仓库。

screenshot

点面判断

screenshot

有了源和目标就可以通过pgrouting提供的各种最佳路径算法算出每件货物的最佳路径。

本文后面会有demo来讲解如何使用pgrouting计算最佳路径。

screenshot

仓库之间的货车的工作就简单了,装满就走 或 分波次(考虑到时效) 的原则,负责好两个直连节点的来回运输,并不是一辆车完成整个货物的从起点到终点的运输。

例如负责A和B之间线路的货车,只在AB之间跑运输。

screenshot

3. 货物从终点仓库到网点的物流调度

货物在抵达目标仓库后,首先要将货物分拣到派件的网点。

其实也是一个点面判断的过程,网点覆盖的派件范围为面,快件则为点,点面判断找出对应的网点。

从仓库到网点,也可以使用仓库建流转的原理,计算出最佳线路。货车只负责2个网点之间的货物流转即可。

4. 派件

进入派件的流程,也就是货物在抵达收件人手中的最后一公里要做的事情。

为了更好的实现派件调度,需要对快件进行聚合操作,根据位置进行聚合。

原理和前面类似,还是要做点面判断,只是目标更加精确,例如精确到小区或者很小的区域。

screenshot

派件除了要考虑快件的目的地(聚合后的),还需要考虑快件的体积,重量,以及快递员的运货能力(体积与重量) 。

假设一个网点当前收到的快件覆盖了以下需要派送的点(聚合后的),同时每个点的货物体积总和如数字所表示。

路径规划与前面不一样的地方,这里规划的是多个点作为目标。

screenshot

多点目标的最佳路径,用意是确保相邻目标的连续性,确保切分不同网点的快件后,拿到快件的人跑的是还是相邻的点。

例如中心是网点的位置,其他点是目标位置,目标位置的数字是体积,假设每个快递员一次运输的体积是7000,虚线是一个快递员拿到的一趟的快件。

这种方法确保了每趟的快件是连续的。

screenshot

多点目标的最佳路径规划,在本文后面的部分也会有DEMO。

地址转换成坐标

如何将地址转换成坐标,不在本文的讨论范围,很多做导航的公司都可以输出这个能力。

但是作为快递公司,还有一种方法可以获得精确的坐标信息,例如快递员的手持GPS终端,收件时扫个条码,同时上报位置信息。

有了一定的基数后,通过文本分析和机器学习,也可以输出地址转坐标的能力。

如果基数非常庞大,可以选择基于PostgreSQL的Greenplum数据仓库,进行文本分析与机器学习(支持MADlib库,支持R)。

Greenplum支持文本分析,支持地理位置信息处理,支持MADlib机器学习库,还支持R语言自定义函数,python函数,支持分布式并行计算。 最重要的是它开源,绝对是有文本和地理位置分析需求的用户最好的选择。

最佳路径运算

以仓库之间的数据流转为例

需要用到PostgreSQL数据库的PostGIS与pgrouting

基础数据需求,用来表示开通了运输航线的仓库之间的线段数据,公里数据。

Road link ID (gid)  唯一,指路段号    
Road class (class_id)    
Road link length (length),长度,公里数    
Road name (name),路名    
Road geometry (the_geom),线段(可以是多点线段,也可以是双点线段)    

假设表名为ways,里面存储的就是仓库之间的线段信息

               Table "public.ways"  
  Column  |           Type            | Modifiers  
----------+---------------------------+-----------  
 gid      | bigint                    |  
 class_id | integer                   | not null  
 length   | double precision          |  
 name     | character(200)            |  
 osm_id   | bigint                    |  
 the_geom | geometry(LineString,4326) |  
Indexes:  
    "ways_gid_idx" UNIQUE, btree (gid)  
    "geom_idx" gist (the_geom)  

1. 生成拓扑

要生成最佳路径,首先要生成合法的拓扑,否则怎么生成路径呢?

生成拓扑前,需要添加两个字段,用来存储线段的首尾编号

-- Add "source" and "target" column  
ALTER TABLE ways ADD COLUMN "source" integer;  
ALTER TABLE ways ADD COLUMN "target" integer;  

调用pgr_createTopology生成拓扑,注意就是生成线段的首位编号的过程

pgr_createTopology(  
'<table>',   -- 需要生成拓扑的表名  
float tolerance,   --  容错值,例如线段的端不能完全吻合时,允许多少误差,单位一般为角度或公里数  
'<geometry column>',   --  线段列名  
'<gid>')  --  gid  

例如,ABC三条线段,其中B线段的两端都没有和AC完全吻合,误差分别为1米和10米,所以需要设置容错。
screenshot

生成线段,实际上就是设置source和target的ID,设置完后,可能就变成这样的了
screenshot

例子

-- Run topology function  
SELECT pgr_createTopology('ways', 0.00001, 'the_geom', 'gid');  

2. 生成最佳路径

pgrouting支持的最佳路径算法很多

screenshot

这里以Shortest Path A*和Shortest Path Dijkstra为例,介绍如何生成最佳路径

如果仓库之间的线段支持双向,回来的成本是多少?

如果回程要考虑堵车更多一点,那么成本就不仅仅是公里数了,还需要加上堵车的成本。

screenshot

本例加上回程成本的字段,并设置为公里数,也就是说这条线段支持回程。

ALTER TABLE ways ADD COLUMN reverse_cost double precision;  
UPDATE ways SET reverse_cost = length;  

2.1 Shortest Path Dijkstra算法举例

调用

pgr_costResult[] pgr_dijkstra(  
text sql, -- 用于计算最佳路径的数据来源, 用SQL表示, 例如   
          -- SELECT id (gid), source (线段起点id), target (线段重点ID), cost (起点到重点的成本) [,reverse_cost (重点到起点的成本)] FROM edge_table  
integer source,   --  规划路径的起点  
integer target,   --  规划路径的终点  
boolean directed,   --  if the graph is directed  
boolean has_rcost  -- if true, the reverse_cost column of the SQL generated set of rows will be used for the cost of the traversal of the edge in the opposite direction.  
);    

返回多行,即路径。

a set of pgr_costResult (seq (序号), id1 (起点id), id2 (目标ID, -1表示终点), cost (这一段的成本)) rows, that make up a path.      

例子

从30到60的最佳路径

SELECT seq, id1 AS node, id2 AS edge, cost FROM pgr_dijkstra('  
                SELECT gid AS id,  
                         source::integer,  
                         target::integer,  
                         length::double precision AS cost  
                        FROM ways',  
                30, 60, false, false);  
  
 seq | node | edge |        cost  
-----+------+------+---------------------  
   0 |   30 |   53 |  0.0591267653820616  
   1 |   44 |   52 |  0.0665408320949312  
   2 |   14 |   15 |  0.0809556879332114  
   ...  
   6 |   10 | 6869 |  0.0164274192597773  
   7 |   59 |   72 |  0.0109385169537801  
   8 |   60 |   -1 |                   0  
(9 rows)  

2.2 Shortest Path A*算法举例

与Shortest Path Dijkstra算法类似,只是SQL需要用到每条线段的起点和重点的坐标,其他参数和pgr_dijkstra都一样。

ALTER TABLE ways ADD COLUMN x1 double precision;  
ALTER TABLE ways ADD COLUMN y1 double precision;  
ALTER TABLE ways ADD COLUMN x2 double precision;  
ALTER TABLE ways ADD COLUMN y2 double precision;  
  
UPDATE ways SET x1 = ST_x(ST_PointN(the_geom, 1));  -- 线段起点坐标x  
UPDATE ways SET y1 = ST_y(ST_PointN(the_geom, 1));  -- 线段起点坐标y  
  
UPDATE ways SET x2 = ST_x(ST_PointN(the_geom, ST_NumPoints(the_geom)));  -- 线段终点坐标x  
UPDATE ways SET y2 = ST_y(ST_PointN(the_geom, ST_NumPoints(the_geom)));  -- 线段终点坐标y  

调用

pgr_costResult[] pgr_astar(  
sql text,     -- SELECT id, source, target, cost, x1, y1, x2, y2 [,reverse_cost] FROM edge_table ,包含了起点和重点坐标,计算速度比Shortest Path A*算法快一点  
source integer,     
target integer,   
directed boolean,   
has_rcost boolean    
);  

返回结果与pgr_dijkstra一样

a set of pgr_costResult (seq, id1, id2, cost) rows, that make up a path.    

例子

SELECT seq, id1 AS node, id2 AS edge, cost FROM pgr_astar('  
                SELECT gid AS id,  
                         source::integer,  
                         target::integer,  
                         length::double precision AS cost,  
                         x1, y1, x2, y2  
                        FROM ways',  
                30, 60, false, false);  

结果

 seq | node | edge |        cost  
-----+------+------+---------------------  
   0 |   30 |   53 |  0.0591267653820616  
   1 |   44 |   52 |  0.0665408320949312  
   2 |   14 |   15 |  0.0809556879332114  
   ...  
   6 |   10 | 6869 |  0.0164274192597773  
   7 |   59 |   72 |  0.0109385169537801  
   8 |   60 |   -1 |                   0  
(9 rows)  

2.3 生成多目标最佳路径

在使用导航时,我们可以选择途径点,这其实就是多目标规划的一种常见场景。

例如从杭州到万载,途径江山去丈母娘家休息一晚。

本例使用的算法是Multiple Shortest Paths with kDijkstra

用法与kDijkstra类似,只有一个参数不一样,就是targets是使用数组表示的。

生成分段成本
pgr_costResult[] pgr_kdijkstraCost(text sql, integer source,  
                 integer[] targets, boolean directed, boolean has_rcost);  

例子

从10出发,到达60,70,80

SELECT seq, id1 AS source, id2 AS target, cost FROM pgr_kdijkstraCost('  
                SELECT gid AS id,  
                         source::integer,  
                         target::integer,  
                         length::double precision AS cost  
                        FROM ways',  
                10, array[60,70,80], false, false);  
  
 seq | source | target |       cost  
-----+--------+--------+------------------  
   0 |     10 |     60 | 13.4770181770774  
   1 |     10 |     70 | 16.9231630493294  
   2 |     10 |     80 | 17.7035050077573  
(3 rows)  
生成路径
pgr_costResult[] pgr_kdijkstraPath(text sql, integer source,  
                 integer[] targets, boolean directed, boolean has_rcost);  

例子

从10出发,到达60,70,80

SELECT seq, id1 AS path, id2 AS edge, cost FROM pgr_kdijkstraPath('  
                SELECT gid AS id,  
                         source::integer,  
                         target::integer,  
                         length::double precision AS cost  
                        FROM ways',  
                10, array[60,70,80], false, false);  
  
		 seq | path | edge |        cost  
-----+------+------+---------------------  
   0 |   60 | 3163 |   0.427103399132954  
   1 |   60 | 2098 |   0.441091435851107  
...  
  40 |   60 |   56 |  0.0452819891352444  
  41 |   70 | 3163 |   0.427103399132954  
  42 |   70 | 2098 |   0.441091435851107  
...  
 147 |   80 |  226 |  0.0730263299529259  
 148 |   80 |  227 |  0.0741906229622583  
(149 rows)  

小结

本文用到哪些技术

1. 点面判断

用法请参考PostGIS手册

2. 点面判断后,按面进行聚合

3. 路径规划

具体的用法请参考pgrouting的手册以及workshop

4. 支持哪些最优算法

非常多,具体的用法请参考pgrouting的手册以及workshop

5. UDF

PostgreSQL支持python, R, C等各种自定义函数的语言

6. 机器学习

PostgreSQL与Greenplum都支持MADlib库,对于Greenplum的R用户,可以使用Greenplum进行隐式的并行数据挖掘,处理大数据量的挖掘很有帮助

7. 地址转换成坐标

8. 聚类算法

如果小区信息在数据库中存储的不是面,而是点,那么派件的点面判断,可以用PostgreSQL或者Greenplum的K-Means聚类算法,将快件与小区进行聚合,达到同样的目的。

用法举例

    SELECT kmeans(ARRAY[x, y, z], 10) OVER (), * FROM samples;  
    SELECT kmeans(ARRAY[x, y], 2, ARRAY[0.5, 0.5, 1.0, 1.0]) OVER (), * FROM samples;  
    SELECT kmeans(ARRAY[x, y, z], 2, ARRAY[ARRAY[0.5, 0.5], ARRAY[1.0, 1.0]]) OVER (PARTITION BY group_key), * FROM samples;  

第一个参数是需要参与聚类分析的数组,第二个参数是最终分成几类(输出结果时类是从0开始的,如分2类的话,输出是0和1)。

第三个参数是种子参数,可以是1维或2维数组,如果是1维数组,必须是第一个参数的元素个数乘以第二个元素的值。(可以认为是给每一个类分配一个种子)。

我们需要指定的种子数组,即网点覆盖的小区或写字楼等组成的点值数组。

PostgreSQL在地理位置处理的领域一直处于非常领先的地位,用户群体也非常的庞大,PostGIS和pgrouting只是这个领域的两插件。

以前还写过一篇point cloud的数据处理相关文章,有兴趣的童鞋可以参考如下

PostGIS和pgrouting在阿里云的RDS PG数据库都有提供,欢迎使用。

祝大家玩得开心,欢迎随时来 阿里云促膝长谈 业务需求 ,恭候光临。

阿里云的小伙伴们加油,努力做 最贴地气的云数据库

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
9月前
|
定位技术
GIS空间分析 网络分析4服务区分析
在本文中,你将学习到GIS空间分析中网络分析4服务区分析的详细过程
114 0
|
1月前
|
存储 算法 Cloud Native
Ganos地理网格引擎支撑无人机路径规划能力实践
随着新能源技术的迅猛发展,低空经济已经逐步成为新的战略性新兴产业,但不同于传统的地表活动,低空活动具有立体性、区域性、融合性等特点,这些特点对于如何安全引导低空活动的顺利开展带来了一系列需要解决的技术问题。Ganos地理网格引擎提供了基于网格的路径规划能力,可以使用DEM、DSM、倾斜摄影等数据构建复杂环境下的无人机路径规划应用。
|
9月前
|
定位技术
GIS空间分析 网络分析3寻找最近的消防站
在本文中,你将学习到GIS空间分析中网络分析3寻找最近的消防站的详细流程
89 0
|
算法 BI 定位技术
GIS教程-空间分析之水文分析
GIS教程-空间分析之水文分析
GIS教程-空间分析之水文分析
|
并行计算 算法 Cloud Native
PolarDB 开源版 使用PostGIS 数据寻龙点穴(空间聚集分析)- 大数据与GIS分析解决线下店铺选址问题
寻龙点穴是风水学术语。古人说:三年寻龙,十年点穴。意思就是说,学会寻龙脉要很长的时间,但要懂得点穴,并且点得准则难上加难,甚至须要用“十年”时间。 但是,若没正确方法,就是用百年时间,也不能够点中风水穴心聚气的真点,这样一来,寻龙的功夫也白费了。 准确地点正穴心,并不是一件容易的事,对初学者来说如此,就是久年经验老手,也常常点错点偏。 寻龙点穴旨在寻找龙气聚集之地,而现实中,我们也有类似需求,比如找的可能是人气聚集之地。 PolarDB 开源版 使用PostGIS 数据寻龙点穴(空间聚集分析)- 大数据与GIS分析解决线下店铺选址问题
476 0
PolarDB 开源版 使用PostGIS 数据寻龙点穴(空间聚集分析)- 大数据与GIS分析解决线下店铺选址问题
|
存储 自动驾驶 物联网
明日14点开播!孪生全空间数据库Ganos V5.0解读
《数据库风向标》是一档聚焦数据库新趋势与新技术的视频栏目,节目每期会请到几位资深技术大咖,与大家共话数据库热点话题。
明日14点开播!孪生全空间数据库Ganos V5.0解读
|
XML JSON API
商圈库_功能_求差获取商圈 | 学习笔记
快速学习商圈库_功能_求差获取商圈。
102 0
|
存储 分布式计算 监控
前沿分享|上海市新能源汽车数据平台 王成名: 车联网全景监控数据时空超融合数据库方案
本篇内容为2021云栖大会-企业级云原生数据库最佳实践论坛中,上海市新能源汽车数据平台 王成名关于“车联网全景监控数据时空超融合数据库方案”的分享。
692 0
前沿分享|上海市新能源汽车数据平台 王成名:  车联网全景监控数据时空超融合数据库方案
|
关系型数据库 测试技术 PostgreSQL
PgSQL · 应用案例 · 相似人群圈选,人群扩选,向量相似 使用实践
背景 PostgreSQL 相似插件非常多,插件的功能以及用法如下: 《PostgreSQL 相似搜索插件介绍大汇总 (cube,rum,pg_trgm,smlar,imgsmlr,pg_similarity) (rum,gin,gist)》 相似人群分析在精准营销,推荐系统中的需求很多。
2378 0