পোস্টজিআইএস-এ সংযুক্ত আস্তরণের তালিকাবদ্ধকরণ?


12

আমার কাছে রাস্তার একটি টেবিল রয়েছে যা আমি বৈশিষ্ট্যের একটি সেটের উপর ভিত্তি করে নির্বাচন করেছি (আসুন এটি বলা যাক speed_limit < 25)। রাস্তাগুলির এমন কয়েকটি দল রয়েছে যা স্থানীয়ভাবে সুসংগত; আমি সংযুক্ত লাইনস্ট্রিংগুলির এই সেটগুলিকে জ্যামিতিক সংগ্রহগুলিতে গ্রুপ করতে চাই। নীচের চিত্রটিতে দুটি জ্যামিতি সংগ্রহ থাকবে: একটি লাল রেখার সাথে এবং একটি নীল রেখার সাথে।

এখানে চিত্র বর্ণনা লিখুন

আমি কয়েকটি "দ্রবীভূত করা, ডিগ্রিগ্রেট" ক্যোয়ারীগুলি চালানোর চেষ্টা করেছি:

SELECT (ST_Dump(st_union)).geom
FROM 
    (SELECT ST_Union(geom) FROM roads) sq

আমি যা চেষ্টা করেছি তার প্রত্যেকটি দিয়ে আমি একটি একক বৈশিষ্ট্য ( ST_Union) বা আমার মূল জ্যামিতি ( ST_Dumpএর ST_Union) দিয়ে শেষ করি।

একরকম WITH RECURSIVEযাদু নিয়ে এটি করা সম্ভব ?


"(ST_Dump (st_union)) এর সাথে কিছু ঠিক দেখাচ্ছে না ge" জিওম "
মার্টিন এফ

যেহেতু তিনি ওরফে এস 07 ইউনিয়ন (জিওম) করেননি নতুন জহমের নামটি উত্তরাধিকার সূত্রে ফাংশনটির নামটি স্ট_উনিয়ন হয়ে গেছে। এজন্য এটিকে কিছুটা মজাদার দেখাচ্ছে
LR1234567

উত্তর:


19

সুতরাং, উদাহরণস্বরূপ। দুটি প্রান্তের সংযুক্ত গ্রুপ সহ একটি সাধারণ টেবিল:

drop table lines;
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(10 10, 10 11)');
insert into lines (id, geom) values ( 12, 'LINESTRING(10 11, 11 11)');
insert into lines (id, geom) values ( 13, 'LINESTRING(11 11, 11 12)');
insert into lines (id, geom) values ( 14, 'LINESTRING(11 12, 12 12)');
create index lines_gix on lines using gist(geom);

এখন, এখানে একটি পুনরাবৃত্ত ফাংশন যা একটি প্রান্তের আইডি দেওয়া, সমস্ত প্রান্ত স্পর্শ করে যা স্পর্শ করে:

CREATE OR REPLACE FUNCTION find_connected(integer) returns integer[] AS
$$
WITH RECURSIVE lines_r AS (
  SELECT ARRAY[id] AS idlist, geom, id
  FROM lines 
  WHERE id = $1
  UNION ALL
  SELECT array_append(lines_r.idlist, lines.id) AS idlist, 
         lines.geom AS geom, 
         lines.id AS id
  FROM lines, lines_r
  WHERE ST_Touches(lines.geom, lines_r.geom)
  AND NOT lines_r.idlist @> ARRAY[lines.id]
)
SELECT 
  array_agg(id) AS idlist
  FROM lines_r
$$ 
LANGUAGE 'sql';

এটি কেবল আমাদের প্রতিটি গোষ্ঠী জমে যাওয়ার পরে খুঁজে বের করার প্রয়োজন রাখে, এমন একটি প্রান্তের আইডি যা ইতিমধ্যে কোনও গোষ্ঠীর অংশ নয়। দুঃখজনকভাবে, যার জন্য দ্বিতীয় পুনরাবৃত্তি কোয়েরি প্রয়োজন requires

WITH RECURSIVE groups_r AS (
  (SELECT find_connected(id) AS idlist, 
          find_connected(id) AS grouplist, 
          id FROM lines WHERE id = 1)
  UNION ALL
  (SELECT array_cat(groups_r.idlist,find_connected(lines.id)) AS idlist,
         find_connected(lines.id) AS grouplist,
         lines.id
  FROM lines, groups_r
  WHERE NOT idlist @> ARRAY[lines.id]
  LIMIT 1)
)
SELECT id, grouplist
FROM groups_r;   

যা একসাথে নেওয়া বীজ আইডি এবং প্রতিটি গ্রুপ এটি জমে একটি দুর্দান্ত সেট ফেরত দেয়। আমি ম্যাপিংয়ের জন্য জ্যামিতি তৈরির জন্য আইডি এর অ্যারেগুলিকে আবারো কোয়েরিতে রূপান্তরিত করার জন্য এটি একটি অনুশীলন হিসাবে পাঠকের কাছে রেখেছি।

 id |   grouplist   
----+---------------
  1 | {1,2,3,4}
 11 | {11,12,13,14}
(2 rows)

আমি মনে করি এই কোডটি সহজ হতে পারে, যদি পোস্টগ্রিজ এসকিউএলে জ্যামিতি টাইপ সমর্থনকারী হ্যাশিংকে সমর্থন করে (যখন আপনি একটি সহজ আরসিটিই লেখেন যাতে আইডির সংগ্রহকারী অ্যারে জড়িত না, আপনি একটি ত্রুটি পান "সমস্ত কলামের ডেটাটাইপগুলি অবশ্যই হ্যাশেবল হতে হবে"), তাই একটি রয়েছে আমার জন্য সামান্য বর্ধনের অনুরোধ।
পল র্যামসে

এটি একটি সত্যিই দুর্দান্ত উপায়। বৃহত্তর পরীক্ষার সেটটিতে প্রয়োগ করার সাথে সাথে আমি কিছু অদ্ভুত ফলাফলগুলি লক্ষ্য করছি; আমি যদি দেখি আমি সমস্যাটিকে একটি সাধারণ উদাহরণে হ্রাস করতে পারি কিনা। 100 লাইন: 85 টি ক্লাস্টার, বৃহত্তম ক্লাস্টার = 3, 0.03 এস //// 200 লাইন: 144 ক্লাস্টার, বৃহত্তম ক্লাস্টার = 9, 0.08 এস //// 300 লাইন: 180 ক্লাস্টার, বৃহত্তম ক্লাস্টার = 51, 0.16 এস /// / 400 লাইন: 188 ক্লাস্টার, বৃহত্তম ক্লাস্টার = 41, 0.27 এস //// 500 লাইন: 176 ক্লাস্টার, বৃহত্তম ক্লাস্টার = 112, 0.56 এস //// 600 লাইন: 143 ক্লাস্টার, বৃহত্তম ক্লাস্টার = 449, 1.0 এস // // 650 লাইন: 133 ক্লাস্টার, বৃহত্তম ক্লাস্টার = 7601, 6.8 এস
ডাবস্টন

টেস্ট ডেটার এই যুক্ত করতে ডুপ্লিকেট ID- র কারণ হবে grouplistঅ্যারে: insert into lines (id, geom) values ( 15, 'LINESTRING(0 0, 10 10)');। পরিবর্তন array_agg(id)ফাংশন বিনিময়ে করার array_agg(DISTINCT id)সমস্যাটির সমাধান বলে মনে হয়।
dbaston

এটি একটি ভাল সমাধান, সুতরাং এখন আমরা কীভাবে জ্যামিতিগুলিকে একটি টেবিলের মধ্যে সংরক্ষণ করতে পারি যাতে আমরা সংযুক্ত রেখাগুলি দেখতে পারি?
জাকারিয়া মওকসিট

6

এখানে একটি পদ্ধতির যা ক্রমবর্ধমান একত্রিত ক্লাস্টারগুলিকে একসাথে অস্থায়ী টেবিল ব্যবহার করে। আমি অস্থায়ী টেবিলের পদ্ধতির জন্য সত্যই যত্ন নিচ্ছি না, তবে এটি লাইন সংখ্যা বৃদ্ধির পাশাপাশি বেশ ভালভাবে সম্পাদন করছে বলে মনে হয় (আমার ইনপুটটিতে আমার কাছে 1.2 এম লাইন রয়েছে)।

DO
$$
DECLARE
this_id bigint;
this_geom geometry;
cluster_id_match integer;

id_a bigint;
id_b bigint;

BEGIN
DROP TABLE IF EXISTS clusters;
CREATE TABLE clusters (cluster_id serial, ids bigint[], geom geometry);
CREATE INDEX ON clusters USING GIST(geom);

-- Iterate through linestrings, assigning each to a cluster (if there is an intersection)
-- or creating a new cluster (if there is not)
FOR this_id, this_geom IN SELECT id, geom FROM lines LOOP
  -- Look for an intersecting cluster.  (There may be more than one.)
  SELECT cluster_id FROM clusters WHERE ST_Intersects(this_geom, clusters.geom)
     LIMIT 1 INTO cluster_id_match;

  IF cluster_id_match IS NULL THEN
     -- Create a new cluster
     INSERT INTO clusters (ids, geom) VALUES (ARRAY[this_id], this_geom);
  ELSE
     -- Append line to existing cluster
     UPDATE clusters SET geom = ST_Union(this_geom, geom),
                          ids = array_prepend(this_id, ids)
      WHERE clusters.cluster_id = cluster_id_match;
  END IF;
END LOOP;

-- Iterate through the clusters, combining clusters that intersect each other
LOOP
    SELECT a.cluster_id, b.cluster_id FROM clusters a, clusters b 
     WHERE ST_Intersects(a.geom, b.geom)
       AND a.cluster_id < b.cluster_id
      INTO id_a, id_b;

    EXIT WHEN id_a IS NULL;
    -- Merge cluster A into cluster B
    UPDATE clusters a SET geom = ST_Union(a.geom, b.geom), ids = array_cat(a.ids, b.ids)
      FROM clusters b
     WHERE a.cluster_id = id_a AND b.cluster_id = id_b;

    -- Remove cluster B
    DELETE FROM clusters WHERE cluster_id = id_b;
END LOOP;
END;
$$ language plpgsql;

পুরোপুরি কাজ করে
জাকারিয়া মওকসিট

এই টুইটটি আপনার পক্ষে কাজ করেছে! ST_ClusterIntersectingপোস্টজিআইএস- এ ফাংশনটি লেখার আগে আমি এই উত্তরটি লিখেছিলাম । যদি আপনার ডেটা মেমরির সাথে ফিট করার মতো যথেষ্ট ছোট হয় তবে আমি আরও পারফরম্যান্ট সমাধানের জন্য এটি পরীক্ষা করে দেখার পরামর্শ দেব।
dbaston

এই প্রশ্নের সন্ধান আমাকে এখানে এনেছে। পুনরাবৃত্তি এবং st_clusterintersecting চেষ্টা করে কিন্তু st_clusterDBScan সবচেয়ে উপযুক্ত হিসাবে দেখা গেছে be যদি অন্য কাউকেও এখানে আনা হয়। postgis.net/docs/manual-dev/ST_ClusterDBSCAN.html
D_C

সম্মত, এস.জি.ক্লসটারডিবিএসসিএন পোস্টজিআইএস ২.৩+ এর জন্য যাওয়ার প্রায় সর্বকালের সেরা উপায়
dbaston
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.