Sql 从GPS日志计算用户的距离和持续时间
我正在使用一个全球定位系统数据集的人的流动性为。在我的原始GPS表中,轨迹是所有用户的GPS序列:Sql 从GPS日志计算用户的距离和持续时间,sql,postgresql,gps,aggregate-functions,postgis,Sql,Postgresql,Gps,Aggregate Functions,Postgis,我正在使用一个全球定位系统数据集的人的流动性为。在我的原始GPS表中,轨迹是所有用户的GPS序列: CREATE TABLE trajectories ( user_id integer, session_id bigint NOT NULL, "timestamp" timestamp with time zone NOT NULL, lat double precision NOT NULL, lon double precision NOT NULL
CREATE TABLE trajectories
(
user_id integer,
session_id bigint NOT NULL,
"timestamp" timestamp with time zone NOT NULL,
lat double precision NOT NULL,
lon double precision NOT NULL,
alt double precision,
CONSTRAINT trajectories_pkey PRIMARY KEY (session_id, "timestamp")
);
SELECT * FROM trajectories ORDER BY user_id, timestamp LIMIT 10;
user_id | session_id | timestamp | lat | lon | alt
---------+----------------+------------------------+-----------+------------+-----
1 | 20081023025304 | 2008-10-23 02:53:04+01 | 39.984702 | 116.318417 | 492
1 | 20081023025304 | 2008-10-23 02:53:10+01 | 39.984683 | 116.31845 | 492
1 | 20081023025304 | 2008-10-23 02:53:15+01 | 39.984686 | 116.318417 | 492
1 | 20081023025304 | 2008-10-23 02:53:20+01 | 39.984688 | 116.318385 | 492
1 | 20081023025304 | 2008-10-23 02:53:25+01 | 39.984655 | 116.318263 | 492
1 | 20081023025304 | 2008-10-23 02:53:30+01 | 39.984611 | 116.318026 | 493
1 | 20081023025304 | 2008-10-23 02:53:35+01 | 39.984608 | 116.317761 | 493
1 | 20081023025304 | 2008-10-23 02:53:40+01 | 39.984563 | 116.317517 | 496
1 | 20081023025304 | 2008-10-23 02:53:45+01 | 39.984539 | 116.317294 | 500
1 | 20081023025304 | 2008-10-23 02:53:50+01 | 39.984606 | 116.317065 | 505
(10 rows)
上面的SELECT查询显示了用户1的GPS点序列,从当前行程会话的起始点_id=20081023025304开始。我想使用此表中的原始数据将计算出的出行指标插入一个新表中,我定义为:
CREATE TABLE trip_metrics(
user_id INT,
session_id BIGINT,
lat_start DOUBLE PRECISION,
lat_end DOUBLE PRECISION,
lon_start DOUBLE PRECISION,
lon_end DOUBLE PRECISION,
trip_starttime timestamp,
trip_endtime timestamp,
trip_duration DOUBLE PRECISION,
trip_distance DOUBLE PRECISION,
PRIMARY KEY (user_id, session_id, trip_starttime)
);
此trip_metrics表的要点是存储分析结果,以便lat_start,lon_start取给定示例中起始位置的lat,lon值:39.984702,116.318417,trip_starttimestamp在本例中取起始时间2008-10-23 02:53:04+01,因此lat_end,lon_end,trip_endtime分别取起始时间
最后使用lat_start/end、lon_start/end来计算该用户在这次旅行中所覆盖的距离。最终结果应该是:
+---------+----------------+-----------+-----------+------------+------------+------------------------+------------------------+---------------+---------------+
| user_id | session_id | lat_start | lat_end | lon_start | lon_end | trip_starttime | trip_endtime | trip_duration | trip_distance |
+---------+----------------+-----------+-----------+------------+------------+------------------------+------------------------+---------------+---------------+
| 1 | 20081023025304 | 39.984702 | 39.984606 | 116.318417 | 116.317065 | 2008-10-23 02:53:04+01 | 2008-10-23 02:53:50+01 | | |
+---------+----------------+-----------+-----------+------------+------------+------------------------+------------------------+---------------+---------------+
计算行程持续时间和行程距离后,行程持续时间的值当然是行程结束时间-行程开始时间
几天来,我一直在研究如何在PostgrSQL数据库中实现这一点,只过滤北京市纬度39.85-40.05和经度116.25-116.5范围内的旅行,因为有些旅行跨越城市之外。我为这个用户创建了一个包含2次旅行的GPS点的db小提琴,每个10点
我将非常感谢任何关于这方面的指导,以便在我目前的研究中取得进展
编辑
遇到此函数时,可以使用haversine公式计算距离。我创建了这个函数,但我不知道如何使用它来获得trip_distance值
要更轻松地计算距离,您必须安装,正如您在标记中所建议的:
CREATE EXTENSION postgis;
该功能正是您所需要的,例如快速和肮脏:
WITH j AS (
SELECT user_id, session_id,
max(timestamp ORDER BY timestamp),
min(timestamp ORDER BY timestamp)
FROM trajectories t
GROUP BY user_id,session_id
)
SELECT
s.user_id,s.session_id,
lat_start,lon_start,
lat_end,lon_end,
trip_starttime,
trip_endtime,
age(trip_endtime,trip_starttime),
ST_Distance(
ST_MakePoint(lon_start,lat_start)::geography,
ST_MakePoint(lon_end,lat_end)::geography) AS trip_distance
FROM
(SELECT
j.user_id, j.session_id,
t.timestamp AS trip_starttime,
lat AS lat_start, lon AS lon_start FROM j
JOIN trajectories t ON t.timestamp = j.min
AND t.session_id = j.session_id AND t.user_id = j.user_id) s,
(SELECT
j.user_id, j.session_id,
t.timestamp AS trip_endtime,
lat AS lat_end,lon AS lon_end FROM j
JOIN trajectories t ON t.timestamp = j.max
AND t.session_id = j.session_id AND t.user_id = j.user_id) e
WHERE s.user_id = e.user_id AND s.session_id = e.session_id;
user_id | session_id | lat_start | lon_start | lat_end | lon_end | trip_starttime | trip_endtime | age | trip_distance
---------+----------------+-----------+-----------+-----------+------------+------------------------+------------------------+----------+------------------
1 | 20081023025304 | 39.984702 | 16.318417 | 39.984606 | 116.317065 | 2008-10-23 03:53:04+02 | 2008-10-23 03:53:50+02 | 00:00:46 | 8012597.30391588
另一方面:将经度和纬度存储在分开的列中几乎总是一个坏主意。如果可能,将它们存储到几何图形或地理列中。一开始这似乎是必要的,但PostGIS提供了大量的信息
进一步阅读:
将postgis添加到数据库中,然后阅读更多关于其中几何/地理功能的信息。您可以轻松计算距离st_distancegeom、geom或使用它将路径存储为单个记录。更多你会发现在这里添加到我的知识请,你能解释子查询s吗?我想知道您是如何访问t.timestamp、lat AS lat_start、lon AS lon_start FROM j的,子查询j只返回四个属性:user_id、session_id min/max timestamp。s和e子查询只匹配开始和结束记录的准确时间。我写这个连接是为了得到开始记录和结束记录的坐标。我使用j子查询的想法是获取所有的max和min值。这个问题是一个快速的解决方案,我相信减少它是可能的,但我想它给了你一个很好的开端,我明白了。我注意到的唯一问题是,对于具有大量GPS记录的用户,lat_start/end、lon_start/end从用户记录中获取的最大/最小lat/lon值不是开始/结束坐标,因此距离计算不准确。我注意到用户10在一次行程中超过8小时,但计算距离为123.731米。当我使用该用户的lat/lon开始/结束值进行检查时,该值是trip记录的最小值/最大值,而不是开始/结束坐标。用户10的8小时记录是否包含相同的会话id?是的,我可以确认它们具有相同的会话id。
WITH j AS (
SELECT user_id, session_id,
max(timestamp ORDER BY timestamp),
min(timestamp ORDER BY timestamp)
FROM trajectories t
GROUP BY user_id,session_id
)
SELECT
s.user_id,s.session_id,
lat_start,lon_start,
lat_end,lon_end,
trip_starttime,
trip_endtime,
age(trip_endtime,trip_starttime),
ST_Distance(
ST_MakePoint(lon_start,lat_start)::geography,
ST_MakePoint(lon_end,lat_end)::geography) AS trip_distance
FROM
(SELECT
j.user_id, j.session_id,
t.timestamp AS trip_starttime,
lat AS lat_start, lon AS lon_start FROM j
JOIN trajectories t ON t.timestamp = j.min
AND t.session_id = j.session_id AND t.user_id = j.user_id) s,
(SELECT
j.user_id, j.session_id,
t.timestamp AS trip_endtime,
lat AS lat_end,lon AS lon_end FROM j
JOIN trajectories t ON t.timestamp = j.max
AND t.session_id = j.session_id AND t.user_id = j.user_id) e
WHERE s.user_id = e.user_id AND s.session_id = e.session_id;
user_id | session_id | lat_start | lon_start | lat_end | lon_end | trip_starttime | trip_endtime | age | trip_distance
---------+----------------+-----------+-----------+-----------+------------+------------------------+------------------------+----------+------------------
1 | 20081023025304 | 39.984702 | 16.318417 | 39.984606 | 116.317065 | 2008-10-23 03:53:04+02 | 2008-10-23 03:53:50+02 | 00:00:46 | 8012597.30391588