当物流调度遇见PostgreSQL-机器学习
《当物流调度遇见PostgreSQL-机器学习》要点: 原题目:当物流调度遇见PostgreSQL - GIS,routing,机器学习 (狮子,女巫,魔衣橱) 配景 物流行业是被电子商务催生的财产之一. 快件的配送和揽件的调度算法是物流行业一个非常重要的课题,直接关系到配送或揽件的时效,以及物流公司的运作本钱. 好的算法,可以提高时效,降低本钱,甚至可以更好的调动社会资源,就像滴滴打车一样,也许能全民参与哦. 以后也许上班路途还能顺路提供快递服务呢. 本文将以物流行业为例,给大家分析一下PostgreSQL与Greenplum在地理位置信息处理,最佳路径算法,机器学习等方面的物流行业应用办法. 要素阐发 物流做的事情很简单,寄件,送件. 物流环节的要素有几个,都与位置有关
如果引入时间属性,则更具有想象空间,例如前面提到的像滴滴打车一样,也许能全民介入哦. 我们这里先从简单的入手,假设现在只关心位置信息. 1. 寄件 货物从寄件人到揽件员,通常是预约的操作,而且寄件人可以直接去网点解决寄件,所以没有太多的算法在里面. 如果派件和揽件混合在一起的话,可以用KNN算法来办理,再结合派件点路径调度,选出最佳的揽件人. 例如,寄件人当前位置,与快递员调度的下一个位置,进行KNN运算,因此B来揽件是本钱最低的. 2. 货物在仓库之间流转的物流调度 假设上图为仓库的位置,两个仓库之间如果开通了线路的话,就以线段连接起来. 每个仓库负责一个区域,这个区域是一个几何的图形. 通过寄件人和收件人的位置,与仓库的区域进行点面判断,找出寄件人的仓库与收件人的仓库. 快件为点,仓库为面,寄件时根据寄件人填写的寄件和收件信息转换为寄件和收件两个经纬度,通过这两个经纬度与快递公司的仓库表进行点面包括的判断匹配,就可以找出快件对应的起点和重点的仓库. 点面判断 有了源和目标就可以通过pgrouting提供的各种最佳路径算法算出每件货物的最佳路径. 本文后面会有demo来讲解如何使用pgrouting计算最佳路径. 仓库之间的货车的工作就简单了,装满就走 或 分波次(考虑到时效) 的原则,负责好两个直连节点的来回运输,并不是一辆车完成整个货物的从出发点到终点的运输. 例如负责A和B之间线路的货车,只在AB之间跑运输. 3. 货物从终点仓库到网点的物流调度 货物在抵达目标仓库后,首先要将货物分拣到派件的网点. 其实也是一个点面判断的过程,网点覆盖的派件范围为面,快件则为点,点面判断找出对应的网点. 从仓库到网点,也可以使用仓库建流转的原理,计算出最佳线路.货车只负责2个网点之间的货物流转即可. 4. 派件 进入派件的流程,也便是货物在抵达收件人手中的最后一公里要做的事情. 为了更好的实现派件调度,必要对快件进行聚合操作,根据位置进行聚合. 原理和前面类似,还是要做点面判断,只是目标更加精确,例如精确到小区或者很小的区域. 派件除了要考虑快件的目的地(聚合后的),还必要考虑快件的体积,重量,以及快递员的运货能力(体积与重量) . 假设一个网点当前收到的快件覆盖了以下必要派送的点(聚合后的),同时每个点的货物体积总和如数字所表示. 路径规划与前面纷歧样的地方,这里规划的是多个点作为目标. 多点目标的最佳路径,用意是确保相邻目标的连续性,确保切分分歧网点的快件后,拿到快件的人跑的是还是相邻的点. 例如中心是网点的位置,其他点是目标位置,目标位置的数字是体积,假设每个快递员一次运输的体积是7000,虚线是一个快递员拿到的一趟的快件. 这种办法确保了每趟的快件是连续的. 多点目标的最佳路径规划,在本文后面的部门也会有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" columnALTER 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米,所以必要设置容错. 生成线段,实际上便是设置source和target的ID,设置完后,可能就变成这样的了 例子 -- Run topology function SELECT pgr_createTopology('ways',0.00001,'the_geom','gid'); 2. 生成最佳路径 pgrouting支持的最佳路径算法很多 http://docs.pgrouting.org/2.2/en/doc/index.html 这里以Shortest Path A*和Shortest Path Dijkstra为例,介绍如何生成最佳路径 http://workshop.pgrouting.org/chapters/shortest_path.html 如果仓库之间的线段支持双向,回来的本钱是多少? 如果回程要考虑堵车更多一点,那么本钱就不仅仅是公里数了,还需要加上堵车的本钱. 本例加上回程本钱的字段,并设置为公里数,也就是说这条线段支持回程. 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_tableinteger source,-- 规划路径的起点integer target,-- 规划路径的终点boolean directed,-- if the graph is directedboolean 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)); -- 线段出发点坐标xUPDATE ways SET y1 = ST_y(ST_PointN(the_geom,1)); -- 线段出发点坐标yUPDATE ways SET x2 = ST_x(ST_PointN(the_geom,ST_NumPoints(the_geom))); -- 线段终点坐标xUPDATE 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,cost FROM pgr_astar(' SELECT gid AS id, length::double precision AS cost, x1,y2 FROM ways',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, length::double precision AS cost FROM ways', 10,array[60,80],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,id1 AS path,cost FROM pgr_kdijkstraPath(' SELECT gid AS id,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) 小结 本文用到哪些技术
PostgreSQL在地理位置处置的领域一直处于非常领先的地位,用户群体也非常的庞大,PostGIS和pgrouting只是这个领域的两插件. 以前还写过一篇point cloud的数据处置相关文章,有兴趣的童鞋可以参考如下 https://yq.aliyun.com/articles/57095 更多深度技术内容,请存眷云栖社区微信公众号:yunqiinsight. 编程之家PHP培训学院每天发布《当物流调度遇见PostgreSQL-机器学习》等实战技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培养人才。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |