Разделите таблицу сырых на куски в Postgres с пределом st_dwithin - PullRequest
0 голосов
/ 17 сентября 2018

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

Например, я получил таблицу с 14 строками

create table lines ( id integer primary key, geom geometry(linestring) );
insert into lines (id, geom) values ( 1, 'LINESTRING(0 0, 0 1)');
insert into lines (id, geom) values ( 2, 'LINESTRING(0 1, 1 1)');
insert into lines (id, geom) values ( 3, 'LINESTRING(1 1, 1 2)');
insert into lines (id, geom) values ( 4, 'LINESTRING(1 2, 2 2)');
insert into lines (id, geom) values ( 11, 'LINESTRING(2 2, 2 3)');
insert into lines (id, geom) values ( 12, 'LINESTRING(2 3, 3 3)');
insert into lines (id, geom) values ( 13, 'LINESTRING(3 3, 3 4)');
insert into lines (id, geom) values ( 14, 'LINESTRING(3 4, 4 4)');
create index lines_gix on lines using gist(geom);

Я хочу разбить его на куски с 3 идентификаторами для каждого чанка со строками, которые находятся в пределах 2 метров друг от друга или от первого.

Результат, который я пытаюсь получить из этого примера:

| Chunk No.|  Id chunk list |
|----------|----------------|
|     1    |    1, 2, 3     |
|     2    |    4, 5, 6     |
|     3    |    7, 8, 9     |
|     4    |   10, 11, 12   |
|     5    |      13, 14    |

Я пытался использовать st_clusterwithin , но когда линии расположены близко друг к другу, он возвращает все из них, не разбитые на куски.

Я также пытался использовать некоторые с рекурсивной магией, например, из ответа, предоставленного Полом Рэмси здесь . Но я не знаю, как изменить запрос так, чтобы он возвращал ограниченный сгруппированный список идентификаторов.

1 Ответ

0 голосов
/ 17 сентября 2018

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

    -- Create function for easier interaction
CREATE OR REPLACE FUNCTION find_connected(integer, double precision, integer, integer[])
  returns integer[] AS
$$
WITH RECURSIVE lines_r AS -- Recursive allow to use the same query on the output - is like continues append to result and use it inside a query
    (SELECT ARRAY[id] AS idlist,
            geom, id
           FROM lines
           WHERE id = $1
    UNION ALL
    SELECT array_append(lines_r.idlist, lines.id) AS idlist, -- append id list to array
           lines.geom                             AS geom,   -- keep geometry
           lines.id                               AS id -- keep source table id
    FROM (SELECT * FROM lines WHERE NOT $4 @> array[id]) lines, lines_r -- from source table and recursive table
    WHERE ST_DWITHIN(lines.geom, lines_r.geom, $2) -- where lines are within 2 meters
      AND NOT lines_r.idlist @> ARRAY[lines.id] -- recursive id list array not contain lines array
     AND array_length(idlist, 1) <= $3
    )
SELECT idlist
FROM lines_r WHERE array_length(idlist, 1) <= $3 ORDER BY array_length(idlist, 1) DESC LIMIT 1;
$$
LANGUAGE 'sql';

-- Create id chunks
WITH RECURSIVE groups_r AS (
    (SELECT find_connected(id, 2, 3, ARRAY[id]) AS idlist, find_connected(id, 2, 3, ARRAY[id]) AS grouplist, id
                             FROM lines WHERE id = 1)
    UNION ALL
    (SELECT array_cat(groups_r.idlist, find_connected(lines.id, 2, 3, groups_r.idlist)) AS idlist,
            find_connected(lines.id, 2, 3, groups_r.idlist)            AS grouplist,
            lines.id
     FROM lines,
          groups_r
     WHERE NOT groups_r.idlist @> ARRAY[lines.id]
     LIMIT 1))
SELECT 
--        (SELECT array_agg(DISTINCT x) FROM unnest(idlist) t (x))    idlist, -- left for better understanding what is happening
       row_number() OVER () chunk_id,
       (SELECT array_agg(DISTINCT x) FROM unnest(grouplist) t (x)) grouplist,
       id input_line_id
FROM groups_r;

Единственная проблема заключается в том, что производительность достаточно чистая, когда количество идентификаторов в чанкеувеличение.Для таблицы с 300 строками и 20 идентификаторами на чанк время выполнения составляет около 15 минут, даже с индексами по геометрии и столбцам идентификаторов.

...