Найближча проблема сусіда в Postgis 2.0 за допомогою індексу GIST (<-> функція)


25

Я намагаюся використовувати нову функцію Postgis 2.0 <-> (Geometry Distance Centroid), щоб обчислити для кожного рядка моєї таблиці (cosn1) відстань до найближчого багатокутника того ж класу.

Я намагався використовувати наступний код:

WITH index_query AS (
  SELECT g1.gid As ref_gid, ST_Distance(g1.the_geom,g2.the_geom) As ENN    
    FROM "cosn1" As g1, "cosn1" As g2   
    WHERE g1.gid <> g2.gid AND g1.class = g2.class
    ORDER BY g1.gid, g1.the_geom <-> g2.the_geom) 
SELECT DISTINCT ON (ref_gid) ref_gid, ENN 
    FROM index_query
ORDER BY ref_gid, ENN;

Але тоді я усвідомлюю попередження:

Примітка: індекс вводиться лише в тому випадку, якщо одна з геометрій є константою (а не в підзапиті / cte). наприклад, 'SRID = 3005; POINT (1011102 450541)' :: геометрія замість a.geom

Це означає, що індекс не буде використаний взагалі, і запит займе майже той самий час, що і до використання:

SELECT DISTINCT ON(g1.gid)  g1.gid As ref_gid, ST_Distance(g1.the_geom,g2.the_geom) As ENN    
    FROM "cosn1" As g1, "cosn1" As g2   
    WHERE g1.gid <> g2.gid AND g1.class = g2.class
    ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom)

Чи може хтось вказати мені на вирішення, що дозволяє мені покращити ефективність мого запиту?

Велике спасибі.


Оскільки відповіді ще не було, ви можете запитати це у списку розсилки PostGIS.
ГІС-Джонатан

Я вже це зробив, але також без жодних відповідей.
Олександр Нето

3
Ви можете використовувати g1.gid> g2.gid в пункті where, що зменшить кількість обчислень відстані, які вам потрібно зробити. На жаль, доки оператор <-> не працює без констант, ми не побачимо значного покращення швидкості в такому вигляді запиту.
Джон Пауелл

Джоне, мені потрібно зберегти всі дітки, навіть ті, які повторюються, як мені потрібно оновити EEN для кожного з многокутників у моїй таблиці «cosn1». Але те, що ви сказали, дало мені ідею. Я міг би зробити так, як ви кажете, використовуючи g1.gid> g2.gis, щоб зменшити обчислення відстані, але зберігаючи g1.gid та g2.gid в результаті. Після цього я міг об'єднати два підзапроси (один з g1.gis як gid, а другий з g2.gid). Спасибі
Олександр Нето

Я виявив, що можливим рішенням для вирішення постійної проблеми буде використання <-> всередині функції SQL, використовуючи the_geom як параметр. Я зробив кілька тестів, а в деяких випадках це набагато швидше (). Але в моєму випадку, оскільки відстані знаходяться всередині однієї таблиці, багато обчислень відстані повторюються під час процесу, що робить його повільніше, ніж використання прямого запиту.
Олександр Нето

Відповіді:


2

Гум, який робив кілька тестів на моїй машині, звучав так, що цей оператор <-> працює неправильно. Я не впевнений, що це помилка, але він повідомив нульову відстань на не перекритих геометріях. Інтригуючого немає?

Що ж щодо справедливої ​​традиційної оптимізації запитів SQL? Оскільки ці несподівані результати з оператором <->, я замінюю його на st_centroid. Отримайте набагато кращі результати в швидкості.

Семантика надії з st_overlaps зберігається однаково. Принаймні це я зрозумів з документації про <->

З документів на Postigs <->

Для інших типів геометрії повертається відстань між центроїдами, що обмежують плаваючу точку.

На моїх тестових даних з ~ 5,5k багатокутників швидкість зростала від ~ 1000 секунд до ~ 5 секунд без просторової індексації.

У будь-якому випадку, чому використовувати DISTINCT ON для групування? Я бачу, як деякі люди використовують його, але не існує група для усунення дублікатів?

Ваш запит із стандартними оптимізаціями SQL без введення помилки st_centroid

select g1.gid, min( st_distance( g1.the_geom, g2.the_geom ) ) AS enn
FROM 
  "cosn1" AS g1, "cosn1" AS g2
WHERE
  g1.gid <> g2.gid
  AND g1.class = g2.class
  AND g1.the_geom && g2.the_geom
GROUP BY
  g1.gid

Зі святом Різдва!


Вибачте, але ваша відповідь не вирішує проблему. Насправді це набагато швидше, але результати не точні, оскільки кінцевий результат обчислюється за допомогою центроїдів полігонів замість їх реальної геометрії. <-> має на меті оптимізувати пошук кандидатів до найближчого сусіда, але врешті-решт, слід використовувати реальні геометрії для обчислення відстані до найкращих кандидатів. Я також спробував використовувати MIN \ GROUP BY замість DISTINCT ON \ ORDER BY, і це здається повільніше.
Олександр Нето

Але посібник postgis для оператора <-> зазначає, що він використовує centroid для неточкових геометрій. Тож моє рішення дало б вам подібні результати. Це має дати такі самі результати, як і ваш головний запит. Перевірте, чи результати з оператором <-> також вірні. Він повідомив мені про геометрію нульової довжини на моїх тестових даних, щоб результати її могли бути порушені, і це рішення дало більш точні дані. Якщо ви зможете опублікувати зразки записів із помилками на певному сайті пасти, ми можемо виявити недоліки у вирішенні.
cavila

Якщо ви перевірите мій запит, оператор <-> буде використовуватися лише для замовлення кандидатів, остаточний результат обчислюється за допомогою фактичних геометрій. У будь-якому випадку, як я вже говорив раніше, <-> підвищення продуктивності працює лише з фіксованими точками. Це було моє оригінальне запитання.
Олександр Нето

Отже, чи погоджуєтесь ви, що верхній запит не еквівалентний нижньому? Оскільки порядок зміниться, тому що оператор <-> ЗАМОВИТЬ st_centroid, а st_distance дасть вам диференційоване значення? Інший порядок може спричинити різний запит, оскільки перший рядок передає пункт DISTINCT ON? Дійсний запит був би нижчим, який потребує покращення швидкості?
cavila

Так, перший запит - це збільшити швидкість на нижньому. І так, це може дати дещо інший результат, оскільки g1.geom <-> g2.geom використовує центроїди, а це означає, що перший рядок може бути не ближчим. Для того, щоб це працювало, я вважаю, що мені доведеться встановити обмеження для порядку за допомогою пункту сказати межа 10, а потім витягнути реальні значення відстані. Можна навіть використовувати <#>, що використовує обмежувальні поля замість центроїдів.
Олександр Нето
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.