PostGIS: лучший способ найти пользователей, которые пересекали пути за последние n дней? - PullRequest
2 голосов
/ 13 апреля 2020

У меня есть таблица, в которой я храню данные о местоположении пользователей, когда они бегают, ездят на велосипеде, гуляют и т. Д. c. Таблица имеет следующий вид:

CREATE TABLE public.user_location (
    app_user_id int4 NOT NULL,
    location_uuid uuid NOT NULL,
    .....
    location_timestamp timestamptz NOT NULL,
    app_user_location geometry(POINT, 4326) NOT NULL,
    coordinate_accuracy float8 NULL,
);

Поле location_timestamp содержит местоположение, в которое было записано время, а поле app_user_location содержит координаты GPS. Данные о местоположении принимаются каждые 100 метров, если пользователь движется (например, езда на велосипеде / бег трусцой и т. Д. c.). За дни, недели и месяцы я собрал миллионы точек. Что я хотел бы сделать, это выяснить, какие пользователи пересекали пути в последние n дней (или в любой данный день), то есть они были рядом друг с другом в один и тот же момент времени. Простым примером будет, если пользователь бегал трусцой в течение 5 км. Мне нужно найти других пользователей, которых он «встречал» во время пробежки.

Я создал индекс для столбца app_user_location. Далее мне нужно было бы сделать ближайшего соседа для набора баллов для пользователя в данный день (или в данный момент времени). Я могу сделать это в al oop, но мне было интересно, есть ли лучший SQL способ сделать это?

Заранее спасибо.

1 Ответ

2 голосов
/ 13 апреля 2020

Вот первое go в чем-то, я не проверял это!

Если все ваши пользователи не живут на экваторе, я бы рекомендовал использовать географию вместо геометрии для определения местоположения пользователя - это упростит расчеты расстояния. Если вы используете версию postgres с поддержкой сгенерированных столбцов, вы можете сделать

ALTER TABLE user_location ADD COLUMN app_user_location_geog GEOGRAPHY(POINT, 4326)
    GENERATED ALWAYS AS (app_user_location) STORED;

Затем вы можете найти идентификаторы, основанные на сопоставлении метки времени и ST_DWithin. Вероятно, для этого потребуется указатель на столбец географии и метки времени.

SELECT
  user1.app_user_id AS user1_id,
  user2.app_user_id AS user2_id,
  user1.app_user_location_geog AS user1_location,
  user2.app_user_location_geog AS user2_location,
  user1.location_timestamp AS crossing_time
FROM
  user_location user1
  JOIN user_location user2 
    ON user1.app_user_id != user2.app_user_id
    -- geo timestamps occurred within a minute of each other
    AND
      user1.location_timestamp >= user2.location_timestamp - INTERVAL '30 seconds'
    AND
      user2.location_timestamp <= user2.location_timestamp + INTERVAL '30 seconds'
    AND
      -- geographies were within 10 meters of each other
      ST_DWithin(user1.app_user_location_geog, user2.app_user_location_geog, 10)

...