Оптимізація розрахунку найближчого сусіда за допомогою PostGIS


13

Я використовую PostGIS для обчислення найближчих сусідів багатокутників. Що я хочу обчислити - це мінімальна відстань від кожного багатокутника, до найближчого багатокутника.

До сих пір я отримав велику допомогу від Mike Toews ' відповіді (який я цитую зі зміною незначного) тут:

SELECT 
  a.hgt AS a_hgt,
  b.hgt AS b_hgt,
  ST_Distance(a.the_geom, b.the_geom) AS distance_between_a_and_b
FROM 
  public."TestArea" AS a, public."TestArea" AS b
WHERE
  a.hgt !=  b.hgt AND ST_Distance(a.the_geom, b.the_geom) < 400

Тоді я підрахував мінімум:

SELECT a_hgt, MIN(distance_between_a_and_b)
FROM public."lon_TestArea"
GROUP BY a_hgt

Однак моя задача полягає в тому, щоб обчислити це для великої кількості багатокутників (1 000 000). Оскільки вищевказаний розрахунок порівнює кожен багатокутник з кожним іншим багатокутником, я задумався, як я міг би покращити обчислення, щоб мені не довелося виконувати 10 ^ 12 обчислень.

Одна з думок, що я мав бути, буфер кожного багатокутника, а потім обчислити найближчим сусідам усі значення в буфері для цього багатокутника і записати мінімум. Я не впевнений, чи це найкращий підхід, чи є функція PostGIS, яку я повинен використовувати.


EDIT: Використовуючи одну із пропозицій Нікласа, я експериментую з ST_Dwithin():

CREATE TABLE mytable_withinRange AS SELECT 
  a.hgt AS a_hgt,
  b.hgt AS b_hgt,
  ST_DWithin(a.the_geom, b.the_geom, 400)
FROM 
  public."lon_TestArea" AS a, public."lon_TestArea" AS b

введіть тут опис зображення

Це повертає таблицю ідентифікатора кожного багатокутника і чи знаходиться він на певній відстані чи ні. Чи можливо побудувати оператор IF/ELSEтипу за допомогою SQL? (Я читав про використання CASEумови) Або я повинен спробувати приєднати таблицю, яку я створюю, до початкової таблиці, а потім знову запустити запит за допомогою ST_Distance?


погляньте на другий приклад у посиланні boston gis у моїй відповіді. ви повинні використовувати st_dwithin в частині запиту, де.
Nicklas Avén

Відповіді:


7

На сторінці BostonGIS є великий розділ "Найближчий сусід" .


Редагувати:

Як щодо

CREATE TABLE mytable_withinRange AS SELECT 
 a.hgt AS a_hgt,
 b.hgt AS b_hgt
FROM 
 public."lon_TestArea" AS a, public."lon_TestArea" AS b
WHERE 
 ST_DWithin(a.the_geom, b.the_geom, 400)

Щодо заяви CASE :

SELECT a,
   CASE WHEN a=1 THEN 'one'
        WHEN a=2 THEN 'two'
        ELSE 'other'
   END
FROM test;

Чи знаєте ви, чи лінія WHERE ST_DWithin(a.the_geom, b.the_geom, 400)буде перешкоджати відстаням, більшим, ніж тоді, 400щоб їх обчислити чи просто записати? Також, чи може випадок випадку використовуватись для числових обчислень? наприклад:CASE WHEN ST_DWithin(a.the_geom, b.the_geom, 400) == TRUE THEN ST_DWithin(a.the_geom, b.the_geom)
djq

1
@celenius Якщо відстань більше 400 м, у вибраній частині нічого не буде обчислено. Я не розумію, чому ви хочете помістити справи в суміш.
Nicklas Avén

@Nicklas нормально - я розумію. Я подумав, що це могло означати, що зберігаються лише відстані менше 400; це робить це набагато простіше, ніж я, хоча. Спасибі!
djq

3

Привіт

Деякі речі слід враховувати, щоб вони рухалися швидше, і деякі речі, які можуть бути можливими в майбутньому.

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

Як обговорювалося в іншому посиланні з Бостона, це правильний спосіб зробити це в PostGIS за допомогою ST_Dwithin . ST_Dwithin використовує індекс для пошуку сусідів у певному діапазоні.

Звичайно, від набору даних залежить, якщо достатньо просто використовувати фіксовану величину для st_DWithin для всіх полігонів або якщо вам потрібно зробити щось на кшталт underdark та wildintellect.

Друга річ - тут використовувати PostGIS 1.5+. Це тому, що обчислення від багатокутника до багатокутника набагато швидше з 1.5, якщо їхні граничні поля не перетинаються. Більше про це можна прочитати тут. .

Третє, що слід згадати, - майбутнє.

У PostgreSQL 9.1 буде щось, що називається knn-gist. Це індекс, який може не просто відповісти «так» чи «ні», але і повернути впорядкований результат безпосередньо з індексу. Про це ви можете прочитати тут .

Але ще потрібно буде багато попрацювати на стороні PostGIS, перш ніж knn gist допоможе для таких речей. Тут для цього є квиток .

З повагою

Ніклас


Дякую за пропозиції Ніклас; тому що мені було складно запускати pgAdmin / PostGIS і запускати, я думаю, що зараз не буду використовувати 1,5. Схоже, ST_Dwithin () - це спосіб вирішити це.
djq

2
встановлення 1.5 не вплине на зв’язок між postgresql та pgadmin. у вас може бути більше однієї версії postgis на сервері баз даних, а потім ви завантажите одну з них у базу даних. тож ви можете мати одну базу даних 1.4 та одну 1.5 та один сервер баз даних.
Nicklas Avén

1

Наступні сторінки, що стосуються магістерської роботи Натана Керра, дають хороший огляд цього прямого питання. Мій колега спробував метод Бостонгіса тут і тут , але в мене виникли деякі проблеми, щоб його правильно працювати.

Ще один підхід до роздумів, схожий на буфер, - це зробити прямокутник, що розширюється / стискається. В основному, проходьте 1, зробіть обмежувальне поле (це прямі + х одиниць до коробки оригінального полігону), що перетинається, що, на вашу думку, захопить хоча б одне перехрестя. Для даних, які отримали перехрестя, виконайте підзапит, який перевіряє ці збіги на найближчі. Для даних, які не вдалося збільшити, розгорніть обмежувальне поле та повторіть.

Очевидно, що це проблема рекурсивного програмування, і, можливо, краще зробити в Python з Shapely, ніж на 100% безпосередньо в постгітах.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.