在实际计算时,由于轨迹模块涉及的对象(轨迹类型,或几何类型)常常十分复杂,在分析时可能会使用计算较为简单的矩形框对象描述查询或简化计算。
在轨迹模块,使用BoxNdf类型表示矩形框。
BoxNdf对象表示在时空中的一个多维立方体区域,其由x,y,z(空间),t(时间)
四个坐标轴上的最小值和最大值表示。每个矩形框包含的维度可能不同,有的矩形框只记录x、y维度信息,有些则可能记录x,y,z,t四个维度的信息。
在查询时,可以利用轨迹或几何类型的外包矩形框来辅助查询。例如下图就是一条在x,y,t空间中的运动的轨迹和它对应的外包矩形框。
在Ganos Trajectory模块中,使用BoxNDF类型表示外包框。对于轨迹、几何类型,可以求得其外包框,也可以提取其在特定时间段的子外包框。
提取几何类型的外包框,也可以在外包框上附加时间范围(2000-01-01 00:00:10至02:13:20)。
WITH geom AS( SELECT ('POLYGON((12.7243236691148 4.35238368367118,12.9102992732078 1.49748113937676,12.5926592946053 1.67643963359296' || ',12.0197574747333 3.19258554889152,12.7243236691148 4.35238368367118))')::geometry a ) SELECT ST_MakeBox(a),ST_MakeBox(a,'2000-01-01 00:00:10'::timestamp, '2000-01-01 02:13:20'::timestamp) from geom;
提取轨迹类型的外包框,也可以提取轨迹在限定时间内的子轨迹的外包框。
With traj AS ( Select ST_makeTrajectory( 'STPOINT', 'LINESTRING(0 0, 50 50, 100 100)'::geometry, tsrange('2000-01-01 00:00:00'::timestamp, '2000-01-01 00:01:40'::timestamp), '{"leafcount":3, "attributes":{ "velocity": {"type": "integer","length": 2,"nullable" : true,"value": [120,130,140]}, "accuracy": {"type": "float", "length": 4, "nullable" : false,"value": [120,130,140]}, "bearing": {"type": "float", "length": 8, "nullable" : false,"value": [120,130,140]}, "acceleration": {"type": "string", "length": 20, "nullable" : true,"value": ["120","130","140"]}, "active": {"type": "timestamp","nullable" : false,"value": ["Fri Jan 01 11:35:00 2010", "Fri Jan 01 12:35:00 2010", "Fri Jan 01 13:30:00 2010"]} }, "events": [{"2" : "Fri Jan 02 15:00:00 2010"}, {"3" : "Fri Jan 02 15:30:00 2010"}] }') a ) SELECT ST_MakeBox(a), ST_MakeBox(a,'1999-12-31 23:00:00'::timestamp, '2000-01-01 00:00:30'::timestamp) from traj;
在较为复杂的应用场景中,对轨迹的处理时常分为两步:
根据轨迹的外包框信息过滤掉大部分的无关数据。
对剩余的数据进行精细处理。
例如,需要用轨迹间的LCSS相似度查找在某数据集中和一条查询轨迹相似的轨迹,如果直接计算查询轨迹和数据集中所有轨迹的LCSS相似度再进行排序,则计算量会很大。
可以假设和查询轨迹相似的轨迹必然与查询轨迹的外包框相交,或是距离在一定范围内,然后只计算符合条件的轨迹和查询之间的相似度,得到一个近似的结果。
外包框相交:
-- 将轨迹SRID统一设置为4326 UPDATE trajectory_table SET traj = ST_SetSRID(traj,4326) WHERE ST_SRID(traj)!=4326; With query AS ( SELECT '{"trajectory":{"version":1,"type":"STPOINT","leafcount":3,"start_time":"2020-04-11 17:42:30","end_time":"2020-04-11 17:45:00","spatial":"SRID=4326;LINESTRING(114.35 39.28 4,114.36 39.28 4,114.35 39.29 4)","timeline":["2020-04-11 17:42:30","2020-04-11 17:43:30","2020-04-11 17:45:00"],"attributes":{"leafcount":3,"intensity":{"type":"integer","length":4,"nullable":true,"value":[80,30,50]}}}}'::trajectory q) SELECT ST_lcsDistance(traj, q, 500), trajectory_table.* FROM trajectory_table, query WHERE traj && q ORDER BY ST_lcsDistance(traj, q, 500);
外包框空间距离小于500米,时间距离小于1小时:
-- 将轨迹SRID统一设置为4326 UPDATE trajectory_table SET traj = ST_SetSRID(traj,4326) WHERE ST_SRID(traj)!=4326; With query AS ( SELECT '{"trajectory":{"version":1,"type":"STPOINT","leafcount":3,"start_time":"2020-04-11 17:42:30","end_time":"2020-04-11 17:45:00","spatial":"SRID=4326;LINESTRING(114.35 39.28 4,114.36 39.28 4,114.35 39.29 4)","timeline":["2020-04-11 17:42:30","2020-04-11 17:43:30","2020-04-11 17:45:00"],"attributes":{"leafcount":3,"intensity":{"type":"integer","length":4,"nullable":true,"value":[80,30,50]}}}}'::trajectory q) SELECT ST_lcsDistance(traj, q, 500), trajectory_table.* FROM trajectory_table, query WHERE traj && ST_ExpandTemporal(ST_ExpandSpatial(ST_MakeBox(q), 500/110000), 3600) ORDER BY ST_lcsDistance(traj, q, 500);
说明由于对轨迹调用ST_Buffer函数时无法使用traj列的索引,因此必须扩展q,将q的外包框扩大相应距离。
由于轨迹使用经纬度坐标,需要先将500米转为经纬度范围,一经纬度大约110km。一小时为3600秒。
常用外包框相交算子:
算子 | 说明 |
&& | 两个对象的外包框在二维(x,y)上相交。 |
&/& | 两个对象的外包框在三维(x,y,z)上相交。 |
&#& | 两个对象的外包框在二维(x,y)和时间(t)上相交。 |
&/#& | 两个对象的外包框在三维(x,y,z)和时间(t)上相交。 |
外包框算子支持轨迹类型(Trajectory)、几何类型(Geometry)、外包框类型(BoxNDF)之间的运算。
使用算子时,可以自动应用之前创建的索引。例如如果在traj_col列上建立了索引,则使用traj_col && ST_MakeEnvelope(0,0,1,1)
时,就可以使用索引加速查询。
在traj_col上进行了其它操作,如ST_Buffer(traj_col),ST_Buffer(traj_col)&&ST_MakeEnvelope(0,0,1,1)
将无法使用索引。