Групповые полигоны с Postgis (новичок) - PullRequest
0 голосов
/ 12 апреля 2020

Доброе утро всем, я пытаюсь сгруппировать многоугольники, которые касаются друг друга, в один многоугольник.

Я использую следующую формулу:

drop table if exists filtre4;
create table filtre4 as
(

select st_unaryunion(unnest(st_clusterintersecting(geom))) as geom
    from data
)

Она отлично работает, когда у меня менее 6 000 000 предметов. пример: у меня появляется обычное сообщение с количеством созданных сущностей. https://zupimages.net/viewer.php?id=20 / 15 / iel c .png

Но если я превышаю 6 000 000 объектов, запрос завершается, но элемент не создается в таблице. У меня есть это сообщение, которое отображается, но ничего не возвращает мне. https://zupimages.net/viewer.php?id=20 / 15 / o41z.png

Я не понимаю.

Спасибо.

1 Ответ

0 голосов
/ 18 апреля 2020

Итак, я думаю, что вы использовали PgAdmin для выполнения запросов. Как ни странно, иногда, даже если есть ошибка памяти или другие ошибки времени выполнения, вы не будете уведомлены. (То же самое случилось со мной во время тестирования.) В таком случае я бы порекомендовал вам сохранить запрос в виде файла sql и запустить его с psql, чтобы убедиться, что вы получаете сообщение об ошибке:

psql -U #your_username -d #your_database -f "#your_sqlfiile.sql"

Итак, первое, что я хотел бы сделать, это настроить "work_mem" в postgresql .conf. Значение по умолчанию составляет 4 МБ, учитывая ваши спецификации, вы, вероятно, можете обрабатывать больше памяти за операцию. Я бы предложил 64 МБ для запуска в соответствии со следующей статьей:

https://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server

После этого обязательно перезагрузите сервер.

Итак, Я использовал сопоставимый набор данных и получил проблемы с памятью. Настройка work_mem была первой частью. Геохеширование применимо к вашему набору данных, потому что вам нужны меньшие группы кластеров, чтобы разместить обработку в памяти, а геохешинг позволяет вам упорядочивать ваши геометрические элементы так, чтобы он уменьшал количество операций сортировки, необходимых при выполнении ST_CLUSTERINTERSECTING (я не думаю, у вас есть атрибуты для группировки, исходя из того, что я понимаю). Вот что делает следующий пример:

  1. Создает выходную таблицу или усекает ее, если она существует, создает последовательность или сбрасывает ее, если она существует
  2. "упорядоченный" Извлечение геометрии из входной таблицы и порядок по геохе sh (* геометрия должна быть в градусах, например, EPSG 4326, чтобы геоха sh)
  3. «сгруппировалась» Используйте последовательность, чтобы поместить данные в x количество групп , Здесь я делю на 10000, но идея в том, что ваше общее число сущностей, разделенное на x, даст вам y групп. Попробуйте сделать группы достаточно маленькими, чтобы уместиться в памяти, но достаточно большими, чтобы быть эффективными. Затем он берет каждую группу, выполняет ST_CLUSTERINTERSECTING, снимает гнездо и, наконец, ST_UNARYUNION.
  4. Вставляет значение с помощью ST_COLLECT и другого ST_UNARYUNION геометрии.

Вот код:

DO $$
DECLARE
    input_table VARCHAR(50) := 'valid_geom';
    input_geometry VARCHAR(50) := 'geom_good';
    output_table VARCHAR(50) := 'unary_output';
    sequence_name  VARCHAR(50) := 'bseq';
BEGIN
    IF NOT EXISTS (SELECT 0 FROM pg_class where relname = format('%s', output_table)) 
    THEN
        EXECUTE '                                                        
        CREATE TABLE ' || quote_ident(output_table) || '( 
           geom geometry NOT NULL)';
    ELSE
        EXECUTE '                                                        
        TRUNCATE TABLE ' || quote_ident(output_table);                                                         
    END IF;
    IF EXISTS (SELECT 0 FROM pg_class where relname = format('%s', sequence_name)) 
    THEN
        EXECUTE '                                                    
        ALTER SEQUENCE ' || quote_ident(sequence_name) || ' RESTART';
    ELSE
        EXECUTE '                                                    
        CREATE SEQUENCE ' || quote_ident(sequence_name);
    END IF;

    EXECUTE '                                                        
    WITH ordered AS (
      SELECT ' || quote_ident(input_geometry) || ' as geom
      FROM ' || quote_ident(input_table) || '
      ORDER BY ST_GeoHash(geom_good)
    ),
    grouped AS (
      SELECT nextval(' || quote_literal(sequence_name) || ') / 10000 AS id, 
      ST_UNARYUNION(unnest(ST_CLUSTERINTERSECTING(geom))) AS geom
      FROM ordered
      GROUP BY id
    )

    INSERT INTO ' || quote_ident(output_table) || '
    SELECT ST_UNARYUNION(ST_COLLECT(geom)) as geom FROM grouped';

END;    
$$;

Предостережения:

  1. Измените объявленные переменные в соответствии с вашими потребностями.

  2. Поскольку входная геометрия называется «geom» as geom не удастся, поэтому я бы изменил SELECT ' || quote_ident(input_geometry) || ' as geom на SELECT ' || quote_ident(input_geometry).

  3. Убедитесь, что все ваши входные геометрии верны, или ST_UNARYUNION не удастся. Оформить заказ ST_ISVALID и ST_MAKEVALID.

  4. Как уже говорилось, геохеширование требует, чтобы проекция была в градусах. Оформить заказ ST_TRANSFORM, (я преобразовал свои данные геометрии в 4326).

Дайте мне знать, если у вас есть еще вопросы.

...