基于Ganos轨迹模型:运输车辆到达性分析

本文介绍了时空数据库Ganos轨迹模型在运输车辆位置分析中的应用场景。Ganos通过在数据库中原生内置移动对象的存储、检索与分析能力,打造全球首个移动对象数据库,为交通、物流、出行、生活服务类客户提供海量轨迹数据的分析挖掘能力。

能力介绍

关于轨迹模型

轨迹模型是时空对象中的一个重要模型,旨在支持对行人、汽车、船只、飞机等移动对象的处理与分析。

轨迹数据在应用中可以从两种视角进行分析。一种视角是将轨迹视为离散的点集,从而对其进行操作。另一种视角是将轨迹视为一条连续的线,表示为随时间变化的空间折线。这两种表示方法各有适用的范围。连续的轨迹线对采样频率不敏感,可作为折线进行各类空间运算。相较之下,离散的轨迹点对采样方式和采样频率的敏感性更高,但在算法上更加友好和简单。常见的相似度计算、轨迹切分等函数通常基于对点的操作。

轨迹常用操作

在实际使用中,常常出现需要满足特定条件的轨迹采样点的情况。例如:

  • 实时数据的存储

    搭载GPS的汽车、共享单车等交通工具,其轨迹点的产生频率极为迅速,可能每1至5秒就会生成一个新的采样点。在实时检测场景中,实时轨迹点具有重要的应用价值。然而,当轨迹点数量过多时,个别点所提供的信息实际上有限,但却占用了大量的存储空间。因此,需要去除一些轨迹点,以尽量保留轨迹信息的前提下,降低存储空间的占用。

  • 轨迹数据的预处理

    在实际场景中,由于多种原因,采样数据往往存在不准确的情况。非人为因素包括定位系统的误差、信号传递质量的不稳定以及设备的损坏等。人为因素则包括手动关闭采样或在未进行采样时移动物体等。在这些情况下,通常需要对轨迹上的特殊点进行特殊处理,诸如漂移点、驻留点和跳跃点。

  • 轨迹特征提取

    在业务应用中,许多情况下不仅需要直接使用轨迹,还需提取轨迹的一些特征信息。最基础的特征信息包括长度、点数、时间范围等,而高阶特征则涵盖轨迹之间的相似度、密度聚类的聚簇位置等。在许多高阶特征的计算中,通常采用离散的近似算法,如动态时间规整(DTW)、最小连续子序列(LCSS)、编辑距离(EDR)等。这类算法对前述的轨迹简化和采样不准确问题往往较为敏感,使用经过简化的轨迹或采样不均匀的轨迹可能导致结果的显著差异。因此,通常需要对轨迹进行重采样,以使得点与点之间的时间或空间差值趋于均匀。

案例场景

场景概述

交通运输公司每日管理着大量的运输车辆。这些车辆配备了GPS系统,能够每隔数秒获取实时位置信息。同时,车辆位置信息与车辆状态信息、运输单信息等业务数据进行关联,为后续开展深度轨迹分析与挖掘奠定基础。主要应用场景包括:

  • 轨迹存储查询与展示:运输车辆的轨迹数据主要包括运输单、经度、纬度和时间这四个字段,推送频率为每5秒生成一个数据点。在正常情况下,一个公司每天有数百至数千辆车同时在途,预计每天会写入千万级的轨迹数据。在获取轨迹数据后,需要进行轨迹预处理(如压缩、抽稀等),并将处理结果展示于业务系统上。

  • 到达性分析:为了确保运输车辆的及时到达,通常会在地图上设定多个电子围栏(例如高速公路出口等重要位置)。如果在特定时间点车辆尚未触及这些电子围栏,则意味着该车辆可能无法在规定时间内将货物送达客户。因此,需要触发预警,以通知相关工作人员进行处理。

  • 停留点分析:长途运输车辆通常需要在途中进行休息。为了避免驾驶人员因夜间驾驶而带来的潜在安全隐患,有必要对运输车辆在夜间是否存在停留点进行监管(即大量轨迹在空间位置上的静止)。如果在夜间时间段内未出现停留点,则需提醒驾驶员尽快进行休息。

  • 轨迹相似度:运输车队中的部分车辆出现了位置偏离,可能是由于车辆驶入错误的路线,从而导致货运到达性风险的产生。为此,需要根据多辆车辆轨迹的相似性,识别异常轨迹,以便及时发现潜在风险。

场景分析

为实现上述场景,可能需要对车辆轨迹进行预处理、分析与压缩,最终以支持前端展示。可能用到的主要功能包括::

  1. 轨迹切分(ST_Split):通过几何对象将一条轨迹切分为多条子轨迹,可以帮助业务将一辆运输车的总体轨迹按照不同的运货单进行分割。

  2. 轨迹构造(ST_append):通过向一条轨迹中不断追加新的轨迹点,可以获得全新的轨迹对象,从而帮助业务实时构建不断延长的轨迹。

  3. 轨迹空间关系判断(ST_intersects):判断轨迹是否与几何对象相关,有助于业务分析在相关时间段内是否触及了电子围栏的规定范围。

  4. 轨迹驻点(ST_StayPoint):提取轨迹中的停留点,可以帮助业务分析在任意时间段内车辆的停留时长,从而判断是否存在疲劳驾驶的行为。

  5. 轨迹简化(ST_Compress):压缩轨迹能够帮助业务根据空间距离偏移阈值、角度偏离阈值及加速度偏离阈值等标准进行数据压缩,从而减少最终渲染的数据量。

最佳实践

安装插件

执行如下SQL语句,安装所需插件。

CREATE EXTENSION ganos_spatialref;
CREATE EXTENSION ganos_geometry;
CREATE EXTENSION ganos_trajectory;

轨迹表配置

执行如下SQL语句,配置轨迹点表、轨迹表和电子围栏表。

-- 定义轨迹点表,包含运输单号、经度、纬度、时间四个字段
CREATE TABLE bill_point(id integer, longitude double precision, latitude double precision, sample_time timestamp);

-- 定义轨迹表, 包含运输单号、轨迹对象两个字段
CREATE TABLE bill_traj(id integer UNIQUE, traj trajectory);

--创建空间索引
CREATE INDEX ON bill_traj USING gist(traj);

-- 定义电子围栏表,包含围栏查询的id,时间和空间范围
CREATE TABLE fence(id integer, fence_time timestamp, area geometry);

-- 建立id和时间索引
CREATE INDEX ON fence USING btree(id);
CREATE INDEX ON fence USING btree(fence_time);

-- 创建Trigger函数
CREATE OR REPLACE FUNCTION trajectory_sync_point() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO bill_traj
SELECT NEW.id, ST_MakeTrajectory(array_agg(ROW(NEW.sample_time, NEW.longitude, NEW.latitude)), false, '{}'::cstring[])
ON CONFLICT(id) DO UPDATE
  SET traj = ST_Append(bill_traj.traj, excluded.traj);
RETURN NULL;
END;
$$
LANGUAGE plpgsql STRICT PARALLEL SAFE;

-- 创建同步Trigger
CREATE TRIGGER point_trigger AFTER INSERT ON bill_point
    FOR EACH ROW EXECUTE PROCEDURE trajectory_sync_point();

通过点表插入数据并执行电子围栏查询

  1. 通过在轨迹点表中插入点,进而在轨迹表中构建轨迹数据。

    -- 向点表插入id为1的轨迹数据
    INSERT INTO bill_point VALUES (1, 2, 2, '2000-01-01 00:01:00'), (1, 2.1, 2, '2000-01-01 00:02:00'), (1, 2.2, 2, '2000-01-01 00:03:00');
    
    -- 从轨迹表中查询,确认点表的新的点已经成功同步到轨迹表
    SELECT * FROM bill_traj;
    
    -- 查看id为1的轨迹中的所有点
    SELECT f.* FROM (SELECT traj FROM bill_traj WHERE id = 1) a, ST_AsTable(a.traj) AS f(t timestamp,x double precision, y double precision);
  2. 对轨迹表中的轨迹数据执行实时的电子围栏查询。

    -- 设置电子围栏,这里我们设置为:在2000-01-01 00:05:00通过一个经度在 2.3,纬度在2附近的区域
    INSERT INTO fence VALUES(1, '2000-01-01 00:05:00', ST_MakeEnvelope(2.29,1.99,2.31,2.01)); 
    
    -- 我们假设业务上每隔一分钟执行一次电子围栏的扫描,则使用下列语句。
    -- now() >= fence.fence_time AND now() - '60 s'::interval < fence.fence_time 这里我们因为一分钟执行一次,因此只截取在这一分钟需要判断的fence。这里使用当前的时间减去fence设定的时间,小于1分钟则代表我们目前需要对此fence进行判断
    -- fence.id = bill_traj.id 提取对应的轨迹
    -- ST_EndTime(bill_traj.traj) >= fence.fence_time 代表确认轨迹的末尾已经超过此时间
    -- ST_2DIntersects(bill_traj.traj, fence.area)检查相交
    -- 此时没有因为迟到而触发电子围栏的查询,返回空
    SELECT fence.id FROM fence JOIN bill_traj ON now() >= fence.fence_time AND now() - '60 s'::interval < fence.fence_time AND fence.id = bill_traj.id AND ST_EndTime(bill_traj.traj) >= fence.fence_time AND NOT ST_2DIntersects(bill_traj.traj, fence.area);
    
    -- 新插入一个点,此时轨迹的时间到达了电子围栏的设定时间,此点不在围栏范围内,触发电子围栏
    INSERT INTO bill_point VALUES (1, 2.25, 2, '2000-01-01 00:05:00');
    
    -- 查看此时id为1的轨迹的点
    SELECT f.* FROM (SELECT traj FROM bill_traj WHERE id = 1) a, ST_AsTable(a.traj) AS f(t timestamp,x double precision, y double precision);
    
    -- 现在我们假设当前时间是2000-01-01 00:05:00。执行下列语句,查询所有fence是否被触发;此时发现id为1的电子围栏被触发,说明对应的车辆已经迟到
    SELECT fence.id FROM fence JOIN bill_traj ON fence.id = bill_traj.id AND ST_EndTime(bill_traj.traj) >= fence.fence_time AND NOT ST_2DIntersects(bill_traj.traj, fence.area);
    
    -- 此时又输入了一个新增轨迹点,其空间上进入了电子围栏,说明此时此车辆已经经过指定地点。此时再进行查询,就发现没有电子围栏被触发,所有车辆状态正常
    INSERT INTO bill_point VALUES (1, 2.3, 2, '2000-01-01 00:06:00');
    
    SELECT fence.id FROM fence JOIN bill_traj ON fence.id = bill_traj.id AND ST_EndTime(bill_traj.traj) >= fence.fence_time AND NOT ST_2DIntersects(bill_traj.traj, fence.area);
    
    -- 查看此时id为1的轨迹的点
    SELECT f.* FROM (SELECT traj FROM bill_traj WHERE id = 1) a, ST_AsTable(a.traj) AS f(t timestamp,x double precision, y double precision);
    
    -- 轨迹点继续输入,离开电子围栏,但不再影响电子围栏是否被触发
    INSERT INTO bill_point VALUES (1, 2.3, 2.1, '2000-01-01 00:07:00');
    INSERT INTO bill_point VALUES (1, 2.2, 1.9, '2000-01-01 00:08:00');

直接构造轨迹数据并求取驻点

  1. 可以不通过点表,直接在轨迹表中构造一条较长的轨迹数据。

    --根据分别指定轨迹的时间,空间对象来创建轨迹
    INSERT INTO bill_traj SELECT
    2, ST_makeTrajectory ('STPOINT'::leaftype, 'LINESTRING(0 0,1 1,2 2,2 2,2 2,2 3,3 4,2 4,2 3,2 3,2 3,2 2,2 1,2 0,1 0,0 0,-1 0)'::geometry, '{"2000-01-01 00:12:34","2000-01-01 00:23:37","2000-01-01 00:34:41","2000-01-01 00:45:45","2000-01-01 00:56:48","2000-01-01 01:07:52","2000-01-01 01:18:56","2000-01-01 01:30:00","2000-01-01 01:41:03","2000-01-01 01:52:07","2000-01-01 02:03:11","2000-01-01 02:14:14","2000-01-01 02:25:18","2000-01-01 02:36:22","2000-01-01 02:47:25","2000-01-01 02:58:29","2000-01-01 03:09:33"}'::timestamp[], NULL);
  2. 通过对轨迹的驻留点进行检测,可以判断车辆是否进行了足够的休息,以及其休息的具体位置。

    -- 获取id为2的轨迹的驻留点。
    -- 其中,第一个参数代表轨迹,第二个参数代表对轨迹按5分钟为采样间距进行采样,第三个参数和第四个参数代表将距离在0.1以内,时间差在15分钟以内的点视为临近点,第五个参数代表一个点的临近点数量超过3个就确定其在此处驻留
    SELECT ST_StayPoint(traj, '5 minute', 0.1, '15 minute', 3) from bill_traj where id =2 ;

    返回两个驻留点:

                                           st_staypoint                                       
    ------------------------------------------------------------------------------------------
     (010100000000000000000000400000000000000040,"2000-01-01 00:34:41","2000-01-01 00:56:48")
     (010100000000000000000000400000000000000840,"2000-01-01 01:41:03","2000-01-01 02:03:11")
  3. (可选)实际业务中,可以对驻留点查询结果进行加工。

    -- 获取两个驻留点的位置
    SELECT ST_AsText((ST_StayPoint(traj, '5 minute', 0.1, '15 minute', 3)).point) from bill_traj where id =2 ;
    
    -- 检查此轨迹的驻留(休息)总时长是否超过30分钟。如果没超过,可能代表其疲劳驾驶
    SELECT SUM(duration) >= '30 minute'::interval FROM (SELECT (ST_StayPoint(traj, '5 minute', 0.1, '15 minute', 3)).endt - (ST_StayPoint(traj, '5 minute', 0.1, '15 minute', 3)).startt as duration  from bill_traj where id =2 ) staytime;

轨迹简化

对于点数较多的轨迹点,可以使用ST_Compress函数对其进行简化,以便于后续的展示。

-- 获取简化后的轨迹,可以看到,id为2的轨迹简化后由17个点简化为7个点。参数0.2代表简化后的轨迹距离原轨迹最大距离为0.2。此简化后的轨迹可以用于前端显示。
SELECT ST_Compress(traj, 0.2) FROM bill_traj;

-- 查看简化后的id为2的轨迹的所有采样点
SELECT f.* FROM (SELECT traj FROM bill_traj WHERE id = 2) a, ST_AsTable(ST_Compress(a.traj, 0.2)) AS f(t timestamp,x double precision, y double precision);

总结

Ganos轨迹模型提供了一系列云原生的移动对象数据类型、函数以及存储过程,帮助您高效管理、查询和分析时空轨迹数据。相较于传统方案,Ganos的轨迹模型具备原生数据类型及空间索引,查询效率很高。同时,轨迹模型提供了包括轨迹构造、轨迹处理、轨迹属性、轨迹事件、轨迹空间关系、轨迹时空关系、轨迹统计、轨迹量测、轨迹相似度等十余大类、数百个算子的支持,具备较强的易用性。目前,Ganos轨迹模型在交通运输、快递物流、快捷出行、生活服务及公共安全等领域具备了十分完善的能力供给与应用案例,服务了多种客户群体,为客户的智能化位置服务应用提供了稳定、高效和健全的时空基础保障。