本文介紹了軌跡模型的用途、基本構成和快速入門等內容。
模型用途
簡介
軌跡模型是符合一定條件的移動對象集合,通常應用于交通、物流、出行、汽車等領域。
Ganos Trajectory是對象關系型數據庫PostgreSQL兼容版本(PolarDB PostgreSQL版)的一個時空引擎擴展,Trajectory是Ganos自主研發的一種數據類型,主要用來存儲移動對象的采樣點和屬性信息,并對其執行分析任務。
功能概述
Trajectory支持軌跡數據存儲與分析方面的多種功能:
軌跡構建:通過幾何形狀(geometry)和時間戳、數組、數據表等數據源構建軌跡。
軌跡編輯:編輯軌跡的時間、幾何、屬性、事件等對象信息,同時支持軌跡的抽稀、切分、平滑、子軌跡提取、時空特征編輯等能力。
軌跡分析:支持軌跡的空間關系判斷、時空關系判斷、相似度分析、特征提取等功能。
軌跡索引:即創建軌跡時空索引加速上述查詢分析。
更多內容請參見Trajectory SQL參考。
主要業務場景
下面列舉了幾個典型的軌跡模型應用場景。
歷史軌跡的歸檔存儲
將共享單車的一類的高頻采樣點聚合成為軌跡,利用軌跡簡化算法進行簡化和降采樣后,將簡化后的軌跡存儲到數據庫中或外部OSS存儲中,以節省存儲空間和存儲成本。Ganos支持以統一的方式訪問軌跡數據,無需注意其存儲在數據表內還是OSS中。
軌跡的時空分析和伴隨分析
通過給出一個關注的時空區域或時空軌跡,查找經過這個時空區域的軌跡或是查找和已知軌跡相似的軌跡,從而得到數據庫中值得關注的軌跡,用以支持定位一類用戶、發放優惠券等業務。
軌跡的特征提取和分析
對用戶的歷史軌跡,通過重采樣和漂移點去除來清洗數據后,提取出長度、持續時間、駐留點、彎道等統計信息,將其作為機器學習的特征信息輸入到神經網絡或其它算法中,用以生成用戶畫像來指導業務上對用戶的管理和推薦等。
基本構成
概述
現實世界中,一個運動物體會在不同的時刻,記錄其空間位置。一個物體的軌跡是一個包含時間和空間信息的點的序列,記錄了該物體在不同時刻的空間位置。
例如,某共享單車在2020-04-11 17:42:30時上報了其經緯度坐標(114.35, 39.28),則其在數據庫中可以表示為一條記錄:
time | x | y |
2020-04-11 17:42:30 | 114.35 | 39.28 |
通常,在軌跡的采樣點上,還會記錄一些其它信息。例如速度、方向等。這里假設其記錄了速度的數據:
time | x | y | speed |
2020-04-11 17:42:30 | 114.35 | 39.28 | 4.3 |
隨著時間的推移,將會有一系列軌跡點。這里假設其有三條記錄:
time | x | y | speed |
2020-04-11 17:42:30 | 114.35 | 39.28 | 4.3 |
2020-04-11 17:43:30 | 114.36 | 39.28 | 4.8 |
2020-04-11 17:45:00 | 114.35 | 39.29 | 3.5 |
則這三個點組合起來,就構成了一條時空軌跡,其形狀大致如下圖所示:
Ganos的軌跡模型將一個運動物體的多個軌跡點聚合起來存儲,和把每個軌跡點單獨存儲相比:一方面,我們可以針對多個軌跡點進行壓縮,節省存儲成本;另一方面,針對聚合后的軌跡,可以執行多種針對整條軌跡而非單個軌跡點的操作,例如:軌跡相交、提取子軌跡,軌跡相似性判斷等。
此外,Ganos還支持保存軌跡的事件屬性,其記錄和單個采樣點無關的、在不同時刻發生的事件信息。其格式為{type:timestamp}
的二元組,其中 type 為用戶自定義的事件編號(整數類型),timestamp為事件發生的時間。
存儲方式
在業務上,對于移動對象的軌跡,常見的三種表示方式:
方式一:存儲為表格中的行,每一行分別記錄時間、x坐標、y坐標等信息。
方式二:存儲為二維或三維的幾何類型LINESTRING/LINESTRING M,用M維度存儲時間戳。
方式三:存儲為軌跡類型。
其中,方式一更新方便,但查詢效率較低,存儲空間占用較多。方式二降低了更新效率,但增強了空間查詢效率,并節約了存儲空間,但無法存儲屬性信息。方式三在方式二的基礎上對時間的處理能力進一步增強,同時支持屬性和事件。用戶可以根據實際需要選擇存儲時使用的表示方式,并在查詢時轉化為其它表示方式進行處理和分析。
--構建存儲為行的數據,每一行代表一個軌跡點
CREATE TABLE sample_points(userid numeric, sample_time timestamp, x double precision, y double precision, z double precision, intensity int);
INSERT INTO sample_points VALUES
(1,'2020-04-11 17:42:30',114.35, 39.28, 4, 80),
(1,'2020-04-11 17:43:30',114.36, 39.28, 4, 30),
(1,'2020-04-11 17:45:00',114.35, 39.29, 4, 50),
(2,'2020-04-11 17:42:30',114.3, 39, 34, 60),
(2,'2020-04-11 17:43:30',114.3, 39, 38, 58);
--從行類型轉化為軌跡類型,每一行代表一個軌跡點
CREATE TABLE trajectory_table(userid numeric PRIMARY KEY, traj trajectory);
INSERT INTO trajectory_table
SELECT userid, ST_Sort(ST_MakeTrajectory(pnts.tjraw, true, '{"intensity"}'::cstring[]))
FROM
(SELECT sample_points.userid, array_agg(ROW(sample_points.sample_time, sample_points.x, sample_points.y, sample_points.z, sample_points.intensity)) as tjraw FROM sample_points GROUP BY userid) pnts;
--從軌跡類型轉化為行類型
SELECT f.* from trajectory_table,ST_AsTable(traj) as f(t timestamp, x double precision, y double precision, z double precision, intensity integer);
-- 轉化軌跡類型為LINESTRING類型,其中只包含空間信息
SELECT ST_trajspatial(traj) FROM trajectory_table;
-- 使用LINESTRING類型的空間形狀和時間范圍構建軌跡
SELECT ST_MakeTrajectory('STPOINT'::leaftype, st_geomfromtext('LINESTRING (114 35, 115 36, 116 37)', 4326), '[2010-01-01 14:30, 2010-01-01 15:30)'::tsrange, '{}');
輸出格式
Ganos Trajectory中的一條軌跡由時間、空間、屬性、事件四個部分構成,在將其轉化為文本輸出時,也會依照四個部分,格式化為JSON格式進行輸出。示例如下:
{
"trajectory": {
"version": 1,
"type": "STPOINT",
"leafcount": 3,
"start_time": "2010-01-01 14:30:00",
"end_time": "2010-01-01 15:30:00",
"spatial": "SRID=4326;LINESTRING(114 35,115 36,116 37)",
"timeline": [
"2010-01-01 14:30:00",
"2010-01-01 15:00:00",
"2010-01-01 15:30:00"
],
"attributes": {
"leafcount": 3,
"velocity": {
"type": "integer",
"length": 2,
"nullable": true,
"value": [120, 130, 140]
},
"accuracy": {
"type": "float",
"length": 4,
"nullable": false,
"value": [120.0, 130.0, 140.0]
},
"bearing": {
"type": "float",
"length": 8,
"nullable": false,
"value": [120.0, 130.0, 140.0]
},
"acceleration": {
"type": "string",
"length": 20,
"nullable": true,
"value": ["120", "130", "140"]
},
"active": {
"type": "timestamp",
"length": 8,
"nullable": false,
"value": [
"2010-01-01 14:30:00",
"2010-01-01 15:00:00",
"2010-01-01 15:30:00"
]
}
},
"events": [
{
"1": "2010-01-01 14:30:00"
},
{
"2": "2010-01-01 15:00:00"
},
{
"3": "2010-01-01 15:30:00"
}
]
}
}
其中:
version、type:固定值。
leafcount:表示軌跡采樣點個數。
start_time、end_time:表示軌跡的開始和結束時間。
spatial:表示軌跡的空間形狀,以WKT形式顯示。
timeline:表示采樣點的時間戳,以字符數組的格式顯示。
attributes:表示軌跡的屬性,其中leafcount是元素個數,其余的鍵是屬性的名稱,而屬性值中type是數據類型,length是數據類型的長度,nullable為是否接受空值。
events:表示軌跡的事件,其由多個鍵值對的數組組成。
空間參考系
空間參考系(Spatial Reference System,以下簡稱為SRS )定義了如何將Trajectory對象關聯到地球表面上某個具體位置。
Ganos使用一個整數來表示SRS的定義引用,稱為SRID。Trajectory對象通過其自身的SRID值與SRS關聯。
更多內容請參見空間參考。
數據列視圖
trajectory_columns是從數據庫系統目錄表中讀取全部柵格列的視圖,其結構如下:
列名 | 類型 | 說明 |
t_table_catalog | varchar(256) | 一般為固定值postgres。 |
t_table_schema | varchar(256) | 該表所在的schema。 |
t_table_name | varchar(256) | 該表的表名。 |
t_trajectory_column | varchar(256) | 該表中某個Trajectory列的列名。 |
可以通過如下語句查詢當前數據庫中全部幾何數據列:
SELECT * FROM trajectory_columns;
索引
Ganos為軌跡數據提供了GiST索引:
索引名稱 | 索引說明 | 索引特點 |
GiST (Generalized Search Tree) | GiST索引是一種平衡搜索樹,是最常用、最通用的空間索引方法,提供非常好的查詢性能。 | GiST索引允許定義一些規則將任意類型的數據分布在一棵平衡樹上,同時也允許定義一些方法訪問這些數據。 |
實現標準
Ganos軌跡模型實現了OGC Moving Features標準所定義的接口,同時對其進行了擴展。軌跡中的幾何屬性依照幾何模型進行實現,并可使用ST_trajectorySpatial函數將一條軌跡的幾何部分提取出來進行操作。
快速入門
簡介
快速入門文檔幫助用戶快速理解Ganos Trajectory引擎的基本用法,包括擴展創建、創建表、插入數據、創建索引、查詢、相似性分析等內容。
更多專業用法可參考Trajectory最佳實踐文章:
語法說明
創建擴展。
CREATE extension ganos_trajectory cascade;
說明建議將擴展安裝在public模式下,避免權限問題。
CREATE extension ganos_trajectory WITH schema public cascade;
創建軌跡表。
CREATE TABLE traj_table (id integer, traj trajectory);
插入軌跡數據。
INSERT INTO traj_table VALUES (1, ST_MakeTrajectory('STPOINT'::leaftype, st_geomfromtext('LINESTRING (114 35, 115 36, 116 37)', 4326), '[2010-01-01 14:30, 2010-01-01 15:30)'::tsrange, '{"leafcount": 3,"attributes" : {"velocity" : {"type":"integer","length":4,"nullable":false,"value":[120, 130, 140]},"accuracy":{"type":"integer","length":4,"nullable":false,"value":[120, 130, 140]},"bearing":{"type":"float","length":4,"nullable":false,"value":[120, 130, 140]},"acceleration":{"type":"float","length":4,"nullable":false,"value":[120, 130, 140]}}}')), (2, ST_MakeTrajectory('STPOINT'::leaftype, st_geomfromtext('LINESTRING (114 35, 115 36, 116 37)', 4326), '2010-01-01 14:30'::timestamp, '2010-01-01 15:30'::timestamp, '{"leafcount": 3,"attributes" : {"velocity" : {"type":"integer","length":4,"nullable":false,"value":[120, 130, 140]},"accuracy":{"type":"integer","length":4,"nullable":false,"value":[120, 130, 140]},"bearing":{"type":"float","length":4,"nullable":false,"value":[120, 130, 140]},"acceleration":{"type":"float","length":4,"nullable":false,"value":[120, 130, 140]}}}')), (3, ST_MakeTrajectory('STPOINT'::leaftype, st_geomfromtext('LINESTRING (114 35, 115 36, 116 37)', 4326), ARRAY['2010-01-01 14:30'::timestamp, '2010-01-01 15:00'::timestamp, '2010-01-01 15:30'::timestamp], '{"leafcount": 3,"attributes" : {"velocity" : {"type":"integer","length":4,"nullable":false,"value":[120, 130, 140]},"accuracy":{"type":"integer","length":4,"nullable":false,"value":[120, 130, 140]},"bearing":{"type":"float","length":4,"nullable":false,"value":[120, 130, 140]},"acceleration":{"type":"float","length":4,"nullable":false,"value":[120, 130, 140]}}}')), (4, ST_MakeTrajectory('STPOINT'::leaftype, st_geomfromtext('LINESTRING (114 35, 115 36, 116 37)', 4326), '[2010-01-01 14:30, 2010-01-01 15:30)'::tsrange, null));
創建軌跡索引并加速各類查詢。
--創建軌跡索引,加速時空過濾效率 CREATE index tr_index ON traj_table USING trajgist (traj); --空間查詢時,加速空間過濾 SELECT id, traj FROM traj_table WHERE st_3dintersects(traj, ST_GeomFromText('POLYGON((116.46747851805917 39.92317964155052,116.4986540687358 39.92317964155052,116.4986540687358 39.94452401711516,116.46747851805917 39.94452401711516,116.46747851805917 39.92317964155052))')); --時間查詢時,加速時間過濾 SELECT id, traj FROM traj_table WHERE st_TIntersects(traj, '2010-01-01 12:30:44'::timestamp,'2010-01-01 14:30:44'::timestamp); --時空查詢時,加速時空過濾 SELECT id, traj FROM traj_table WHERE st_3dintersects(traj, ST_GeomFromText('POLYGON((116.46747851805917 39.92317964155052,116.4986540687358 39.92317964155052,116.4986540687358 39.94452401711516,116.46747851805917 39.94452401711516,116.46747851805917 39.92317964155052))'),'2010-01-01 13:30:44'::timestamp,'2010-01-03 17:30:44'::timestamp);
查詢軌跡起、止時間。
SELECT st_startTime(traj), st_endTime(traj) FROM traj_table ; st_starttime | st_endtime ---------------------+--------------------- 2010-01-01 14:30:00 | 2010-01-01 15:30:00 2010-01-01 14:30:00 | 2010-01-01 15:30:00 2010-01-01 14:30:00 | 2010-01-01 15:30:00 2010-01-01 14:30:00 | 2010-01-01 15:30:00 (4 rows)
分析軌跡間的相近性。
With traj AS ( SELECT ST_makeTrajectory('STPOINT', 'LINESTRING(1 1, 5 6, 9 8)'::geometry, '[2010-01-01 11:30, 2010-01-01 15:00)'::tsrange, '{"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, ST_makeTrajectory('STPOINT', 'LINESTRING(1 0, 4 2, 9 6)'::geometry, '[2010-01-01 11:30, 2010-01-01 15:00)'::tsrange, '{"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"}]}') b) SELECT ST_euclideanDistance(a, b) FROM traj; st_euclideandistance ---------------------- 0.0888997369940162 (1 row)
刪除擴展(可選)。
DROP EXTENSION ganos_trajectory CASCADE;
SQL參考
詳細SQL手冊請參見Trajectory SQL參考。