Postgresql PostGIS使用时间戳检测交叉

Postgresql PostGIS使用时间戳检测交叉,postgresql,postgis,Postgresql,Postgis,我需要在数据库中存储一系列带有时间戳的GPS点(各种车辆的轨迹) 起初,我想自己写一些东西,但这需要更多的计算能力,然后只需要一个查询就可以了 我进行了一些探索,发现了PostGIS,但我不确定它是否适合或可能解决这个问题 目的是检查两辆车是否同时经过对方 我有一个带有坐标的表,每个坐标都在一个单独的行中,每一行都有一个和它相关联的时间戳 该表具有以下模式(车辆id、纬度、经度、时间戳) 因此,给定一辆车的多个坐标,我需要检查它是否同时与其他车辆交叉。我发现我可以使用ST_MakeLine从一系

我需要在数据库中存储一系列带有时间戳的GPS点(各种车辆的轨迹)

起初,我想自己写一些东西,但这需要更多的计算能力,然后只需要一个查询就可以了

我进行了一些探索,发现了PostGIS,但我不确定它是否适合或可能解决这个问题

目的是检查两辆车是否同时经过对方

我有一个带有坐标的表,每个坐标都在一个单独的行中,每一行都有一个和它相关联的时间戳

该表具有以下模式(车辆id、纬度、经度、时间戳)

因此,给定一辆车的多个坐标,我需要检查它是否同时与其他车辆交叉。我发现我可以使用ST_MakeLine从一系列GPS点创建一个线串,并看到有不同的交点函数,但这需要坐标完美匹配,这里的偏移量可能是30米,并且必须考虑时间戳

任何答案都会有帮助


谢谢

如果我正确理解了您的用例,我相信您不需要创建线串来检查轨迹是否在某个时间点相交或接近

数据样本:

CREATE TABLE t (vehicle_id INT, longitude NUMERIC, latitude NUMERIC, ts TIMESTAMP);

INSERT INTO t VALUES (1,1,1.1111,'2019-05-01 15:30:00'),
                     (1,1,2.1112,'2019-05-01 15:40:00'),
                     (1,1,3.1111,'2019-05-01 15:50:00'),

                     (2,2,2.1111,'2019-05-01 15:30:00'),
                     (2,1,2.1111,'2019-05-01 15:40:00'),
                     (2,1,4.1111,'2019-05-01 15:05:00');
正如您在上面的示例数据中所看到的,
vehicle_id
1和2在
2019-05-01 15:40:00
处彼此接近(小于30m),可以通过以下查询找到:

SELECT 
  t1.vehicle_id,t2.vehicle_id,t1.ts, 
  ST_AsText(ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY) AS p1,
  ST_AsText(ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) AS p2,
  ST_Distance(
    ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY,
    ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) AS distance
FROM t t1, t t2
WHERE 
  t1.vehicle_id <> t2.vehicle_id AND
  t1.ts = t2.ts AND
  ST_Distance(
    ST_MakePoint(t1.longitude,t1.latitude)::GEOGRAPHY,
    ST_MakePoint(t2.longitude,t2.latitude)::GEOGRAPHY) <= 30


 vehicle_id | vehicle_id |         ts          |       p1        |       p2        |  distance   
------------+------------+---------------------+-----------------+-----------------+-------------
          1 |          2 | 2019-05-01 15:40:00 | POINT(1 2.1112) | POINT(1 2.1111) | 11.05757826
          2 |          1 | 2019-05-01 15:40:00 | POINT(1 2.1111) | POINT(1 2.1112) | 11.05757826
(2 rows)
你可以这样填充它

INSERT INTO t (vehicle_id, geom, ts) 
VALUES (1,ST_MakePoint(1,1.1111),'2019-05-01 15:30:00');
如果您不想再次填充表,您可能只想将数据移动到另一列,并去掉(如果您愿意)纬度和经度:

ALTER TABLE t ADD COLUMN geom GEOGRAPHY;
UPDATE t SET geom = ST_MakePoint(longitude,latitude);
ALTER TABLE t DROP COLUMN longitude, DROP COLUMN latitude;
CREATE INDEX idx_point ON t USING GIST(geom);
SELECT vehicle_id,ts,ST_AsText(geom) FROM t;

 vehicle_id |         ts          |    st_astext    
------------+---------------------+-----------------
          1 | 2019-05-01 15:30:00 | POINT(1 1.1111)
          1 | 2019-05-01 15:40:00 | POINT(1 2.1112)
          1 | 2019-05-01 15:50:00 | POINT(1 3.1111)
          2 | 2019-05-01 15:30:00 | POINT(2 2.1111)
          2 | 2019-05-01 15:40:00 | POINT(1 2.1111)
          2 | 2019-05-01 15:05:00 | POINT(1 4.1111)
(6 rows)

嗨,吉姆·琼斯,非常感谢你的回答。它工作得很好。我修改了一个查询,在时间戳中添加了偏移量,方法是不检查时间戳之间是否相等,而是使用between
(t1.ts介于t2.ts-(interval'10s')和t2.ts+(interval'10s'))
,但我无法在工作时使用DISTINCT,我尝试选择DISTINCT ON(t1.vehicle\u id,t2.vehicle\u id)但它又给了我两张唱片。你知道如果有更多的记录,比如说10000辆车,每辆车有100个位置,这个查询将如何执行吗?在这个表中使用distinct可能有点棘手。基于这种结构,我看不到太多的选择
DISTINCT ON(ts,distance)
假设在同一时间内没有出现具有完全相同距离的其他点
DISTINCT ON(t1.车辆id+t2.车辆id,ts)
将为两个点的id创建一个虚拟签名,并查看它们是否同时发生。我希望它能给你一个方向。关于性能,它的性能不如在具有适当索引的表中已经具有地理坐标。这个查询在执行时创建它们,并且没有索引。啊,那么它可以直接存储为一个地理位置吗?那会更好,因为我不必逐个插入每条记录。但是在这种情况下,不可能对每个位置都有时间戳,对吗?是的,可以直接将它们存储为地理位置。对于每个位置,您仍然可以使用timestap。唯一的区别是纬度和经度值将存储在单个列中。这似乎令人困惑,但这是处理地理数据的最佳方式。。。您可以使用空间索引来加速查询。您的表结构类似于
(vehicle\u id INT、geom GEOGRAPHY、ts TIMESTAMP)
ALTER TABLE t ADD COLUMN geom GEOGRAPHY;
UPDATE t SET geom = ST_MakePoint(longitude,latitude);
ALTER TABLE t DROP COLUMN longitude, DROP COLUMN latitude;
CREATE INDEX idx_point ON t USING GIST(geom);
SELECT vehicle_id,ts,ST_AsText(geom) FROM t;

 vehicle_id |         ts          |    st_astext    
------------+---------------------+-----------------
          1 | 2019-05-01 15:30:00 | POINT(1 1.1111)
          1 | 2019-05-01 15:40:00 | POINT(1 2.1112)
          1 | 2019-05-01 15:50:00 | POINT(1 3.1111)
          2 | 2019-05-01 15:30:00 | POINT(2 2.1111)
          2 | 2019-05-01 15:40:00 | POINT(1 2.1111)
          2 | 2019-05-01 15:05:00 | POINT(1 4.1111)
(6 rows)