使用st_dwithin限制将表原始分为Postgres中的块

问题描述 投票:1回答:1

我得到了一个带有线串的表格,我希望将其分成块,这些块的id列表不高于每个提供的编号,并且只存储一定距离内的行。

例如,我有一个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个ID,每条线的距离彼此相差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,但是当线条彼此接近时,它将返回所有未分割成块的块。

我还尝试使用一些递归魔法,就像Paul Ramsey here提供的答案中那样。但我不知道如何修改查询以返回有限的分组ID列表。

postgresql recursion postgis recursive-query
1个回答
1
投票

我不确定这是否是最好的答案,所以如果有人有更好的方法或知道如何改进提供的答案随时更新它。通过对Paul回答的一点修改,我设法创建了以下查询,这些查询正在按照我的要求进行。

    -- 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;

唯一的问题是,当块中的ID数量增加时,性能非常纯净。对于每行有300行和20个ID的表,执行时间大约为15分钟,即使是几何和id列上的索引也是如此。

© www.soinside.com 2019 - 2024. All rights reserved.