聊一聊双十一背后的技术 - 物流, 动态路径规划

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 背景 物流行业是被电子商务催生的产业之一。 快件的配送和揽件的调度算法是物流行业一个非常重要的课题,直接关系到配送或揽件的时效,以及物流公司的运作成本。 好的算法,可以提高时效,降低成本,甚至可以更好的调动社会资源,就像滴滴打车一样,也许能全民参与哦。 以后也许上班路途还

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

《聊一聊双十一背后的技术 - 物流, 动态路径规划》

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

《聊一聊双十一背后的技术 - 强奸式秒杀技术实现》

《聊一聊双十一背后的技术 - 毫秒分词算啥, 试试正则和相似度》

云栖聚能聊 - 聊一聊双十一背后的数据库技术

标签

PostgreSQL , 物流 , 路径规划 , LBS , PostGIS , Greenplum , 最短路径 , 双十一 , 地理位置信息 , 快递 , 菜鸟物流 , 菜鸟


背景

每年双十一的交易额都创新高,今年也不例外,双十一几乎成了各种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。
http://workshop.pgrouting.org/chapters/topology.html

基础数据需求,用来表示开通了运输航线的仓库之间的线段数据,公里数据。
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支持的最佳路径算法很多
http://docs.pgrouting.org/2.2/en/doc/index.html

screenshot

这里以Shortest Path A*和Shortest Path Dijkstra为例,介绍如何生成最佳路径
http://workshop.pgrouting.org/chapters/shortest_path.html

如果仓库之间的线段支持双向,回来的成本是多少?
如果回程要考虑堵车更多一点,那么成本就不仅仅是公里数了,还需要加上堵车的成本。
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)

小结

本文用到哪些技术

  • 点面判断
    用法请参考PostGIS手册
  • 点面判断后,按面进行聚合
  • 路径规划
    具体的用法请参考pgrouting的手册以及workshop
  • 支持哪些最优算法
    非常多,具体的用法请参考pgrouting的手册以及workshop
  • UDF
    PostgreSQL支持python, R, C等各种自定义函数的语言
  • 机器学习
    PostgreSQL与Greenplum都支持MADlib库,对于Greenplum的R用户,可以使用Greenplum进行隐式的并行数据挖掘,处理大数据量的挖掘很有帮助
  • 地址转换成坐标
  • 聚类算法
    如果小区信息在数据库中存储的不是面,而是点,那么派件的点面判断,可以用PostgreSQL或者Greenplum的K-Means聚类算法,将快件与小区进行聚合,达到同样的目的。

用法举例:
http://blog.163.com/digoal@126/blog/static/163877040201571745048121/

    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的数据处理相关文章,有兴趣的童鞋可以参考如下
https://yq.aliyun.com/articles/57095

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

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

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

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
7月前
|
监控 数据挖掘 API
阿里巴巴API接口技术揭秘:轻松驾驭电商数据,提升业务效率
阿里巴巴API接口技术揭秘:轻松驾驭电商数据,提升业务效率
158 1
|
7月前
|
算法 数据挖掘 双11
新锐品牌如何在大促期间实现品效协同的户外营销?——探究徕芬双11高效拉新背后的奥秘
新锐品牌如何在大促期间实现品效协同的户外营销?——探究徕芬双11高效拉新背后的奥秘
|
人工智能 自然语言处理 算法
电商行业智能搜索技术原理全解析
对于电商平台来说,智能搜索功能是至关重要的。本文剖析电商行业的搜索专属特点和业务需求,并介绍开放搜索提供的【电商行业模板】智能搜索能力,希望带给企业更多提升业务转化的思路和解决方案~
2870 1
电商行业智能搜索技术原理全解析
|
人工智能 运维 搜索推荐
电商行业实践专栏上线|阿里巴巴风控实战如何解决大规模风控的技术难点?
Flink-learning 学训平台第 4 期课程——电商行业实践专栏上线啦!
790 0
电商行业实践专栏上线|阿里巴巴风控实战如何解决大规模风控的技术难点?
|
运维 Cloud Native 机器人
《2023云原生实战案例集》——01 汽车/制造——节卡机器人 云拨测测助力全面优化海外网站性能
《2023云原生实战案例集》——01 汽车/制造——节卡机器人 云拨测测助力全面优化海外网站性能
《2023云原生实战案例集》——01 汽车/制造——节卡机器人  云拨测测助力全面优化海外网站性能
|
架构师 UED
聚焦Web3.0时代下元宇宙社交新浪潮,阿里云特此追热点规划音视频领域线上宣讲会
7月20日 19:00-20:10,阿里云智能-产品解决方案架构师李鑫《Web3.0布局深化,链路升级加速音视频出海进程》主题演讲,扫码报名,观看直播!
415 0
聚焦Web3.0时代下元宇宙社交新浪潮,阿里云特此追热点规划音视频领域线上宣讲会
|
供应链 算法 数据管理
解决方案应用实例 |数据中台“开天眼”,波司登实现数字化新起飞
数年前,波司登遭遇了奇怪的现象:有的地方库存积压,而有的地方却无货可卖。后来接入了数据管理,全国的生产销售行为实现一盘货,波司登实现了数字化时代的新起飞。但人们并不知道,波司登背后的那个数据专家是谁?正是阿里云数据中台。
657 0
解决方案应用实例 |数据中台“开天眼”,波司登实现数字化新起飞
|
缓存 移动开发 前端开发
618 大促背后的淘系前端技术体系
2020年618大促已经过去,作为淘系每年重要的大促活动,淘系前端在其中扮演着什么样的角色,如何保证大促的平稳进行?又在其中应用了哪些新技术? 淘系技术特此推出「618 系列|淘系前端技术分享」,为大家介绍 618 中的前端身影。本篇的作者是来自于营销活动团队的墨冥,为大家介绍618大促背后的淘系前端技术体系。
2909 0
618 大促背后的淘系前端技术体系
|
负载均衡 应用服务中间件 nginx
一对一直播系统开发,解决技术难点是重点
在大量用户涌入平台的情况下,一对一直播系统开发还是要面临众多难题,只有解决这些技术难题,才能让一对一直播系统运行更加稳定。