Продуктивність при обчисленні растрової статистики в PostGIS


9

Я намагаюся обчислити растрову статистику (хв, макс, середнє) для кожного багатокутника у векторному шарі, використовуючи PostgreSQL / PostGIS.

Ця відповідь GIS.SE описує, як це зробити, обчисливши перетин між полігоном та растром, а потім обчисливши середньозважене значення: https://gis.stackexchange.com/a/19858/12420

Я використовую наступний запит (де demмій растр, topo_area_su_regionмій вектор та toidунікальний ідентифікатор:

SELECT toid, Min((gv).val) As MinElevation, Max((gv).val) As MaxElevation, Sum(ST_Area((gv).geom) * (gv).val) / Sum(ST_Area((gv).geom)) as MeanElevation FROM (SELECT toid, ST_Intersection(rast, geom) AS gv FROM topo_area_su_region,dem WHERE ST_Intersects(rast, geom)) foo GROUP BY toid ORDER BY toid;

Це працює, але це занадто повільно. Мій векторний шар має 2489 тис. Функцій, кожен з яких займає близько 90 мс для обробки - це займе кілька днів, щоб обробити весь шар. Швидкість обчислення не здається значно поліпшеною, якщо я обчислюю лише min та max (що дозволяє уникнути дзвінків на ST_Area).

Якщо я роблю аналогічний розрахунок за допомогою Python (GDAL, NumPy та PIL), я можу значно скоротити кількість часу, необхідного для обробки даних, якщо замість векторизації растра (використовуючи ST_Intersection) я раструю вектор. Дивіться код тут: https://gist.github.com/snorfalorpagus/7320167

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

Питання : Чи є спосіб змусити PostGIS вести себе таким чином? тобто повернути значення всіх комірок з растру, до яких дотикується багатокутник, а не точне перетин.

Я дуже новачок у PostgreSQL / PostGIS, тому, можливо, є щось інше, що я не роблю правильно. Я запускаю PostgreSQL 9.3.1 і PostGIS 2.1 для Windows 7 (2.9 ГГц i7, 8 Гб оперативної пам’яті) і налаштував конфігурацію бази даних, як тут запропоновано: http://postgis.net/workshops/postgis-intro/tuning.html

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


1
Я відредагував свою відповідь. Я забув сказати, що перетин у моїй відповіді менш точний.
Стефан

Відповіді:


11

Ви праві, використання ST_Intersectionсповільнює ваш запит помітно.

Замість використання ST_Intersectionкраще обрізати ( ST_Clip) ваш растр з полігонами (вашими полями) і скинути результат у вигляді багатокутників ( ST_DumpAsPolygons). Таким чином, кожна растрова клітина буде перетворена на маленький багатокутник прямокутника з чіткими значеннями.

Для отримання мінімуму, максимуму або середнього значення з відвалів ви можете використовувати ті самі твердження.

Цей запит повинен зробити фокус:

SELECT 
    toid,
    Min((gv).val) As MinElevation,
    Max((gv).val) As MaxElevation,
    Sum(ST_Area((gv).geom) * (gv).val) / Sum(ST_Area((gv).geom)) as MeanElevation
FROM (
    SELECT 
        toid,
        ST_DumpAsPolygons(ST_Clip(rast, 1, geom, true)) AS gv
    FROM topo_area_su_region,dem 
        WHERE ST_Intersects(rast, geom)) AS foo 
            GROUP BY toid 
            ORDER BY toid;

У заяві ST_Clipви визначаєте растр, діапазон растрових (= 1), багатокутник і, якщо обрізка повинна бути ПРАВИЛЬНОЮ або ЛІЖНОЮ.

Крім того, ви можете використовувати avg((gv).val)для обчислення середнього значення.

EDIT

Результат вашого підходу точніший, але повільніший. Результати комбінації ST_Clipта ST_DumpAsPolygonsігнорування растрових клітин, які перетинаються з меншими за 50% (або 51%) своїми розмірами.

Ці два знімки екрана із перетину CORINE Land Use показують різницю. Перша картинка з ST_Intersection, друга з ST_Clipі ST_DumpAsPolygons.

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

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

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