Шукаєте найшвидше рішення для аналізу в Полігоні на 200 мільйонів балів [закрито]


35

У мене є CSV, який містить 200 мільйонів спостережень у такому форматі:

id,x1,y1,x2,y2,day,color
1,"-105.4652334","39.2586939","-105.4321296","39.2236632","Monday","Black"
2,"-105.3224523","39.1323299","-105.4439944","39.3352235","Tuesday","Green"
3,"-104.4233452","39.0234355","-105.4643990","39.1223435","Wednesday","Blue"

Для кожного набору координат (x1 / y1 та x2 / y2) я хочу призначити тракт перепису чи блоку перепису США, до якого він потрапляє (я завантажив тут файл форми TIGER урочища перепису: ftp://ftp2.census.gov/ geo / tiger / TIGER2011 / TRACT / tl_2011_08_tract.zip ). Отже, мені потрібно зробити операцію «в точці в полігоні» двічі за кожне спостереження. Важливо, щоб матчі були дуже точними.

Який найшвидший спосіб зробити це, включаючи час на вивчення програмного забезпечення? У мене є доступ до комп’ютера з 48 Гб пам'яті - на випадок, якщо це може бути відповідним обмеженням.

Декілька ниток рекомендують використовувати PostGIS або Spatialite (Spatialite виглядає простіше у використанні - але чи він такий же ефективний, як PostGIS?). Якщо це найкращі варіанти, чи обов’язково потрібно заповнити просторовий індекс (RTree?)? Якщо так, то як це зробити (наприклад, використовуючи шаблон тракту перепису)? Я буду дуже вдячний за будь-які рекомендації, що включають приклад код (або вказівник на приклад код).

Перша моя спроба (до пошуку цього сайту) полягала у використанні ArcGIS для просторового з'єднання (лише x1 / y1) підпробових даних (100 000 балів) на Блоку перепису США. На це пішло 5 годин, перш ніж я вбив процес. Я сподіваюся на рішення, яке може бути реалізовано для всього набору даних за менше 40 годин обчислювального часу.

Вибачення за те, що було задано раніше - я прочитав відповіді, і мені залишається цікаво, як виконати рекомендації. Я ніколи не використовував SQL, Python, C, а ArcGIS використовував лише один раз раніше - я повний початківець.


3
40 годин дорівнювали б майже 2800 операціям "полігон" за секунду. Це просто не здається можливим у моїй свідомості. Я поняття не маю, який програмний продукт (ArcGIS, PostGIS, Spatialite тощо) є найшвидшим, але просторовий індекс без сумніву потрібен.
Uffe Kousgaard

1
Не повинно бути проблем, якщо багатокутники не складні. Виграш від індексу (в PostGIS) буде залежати від того, наскільки великі багатокутники. Чим менше полігонів (менших обмежувальних коробок), тим більше допоможуть індекси. Напевно, це можливо.
Nicklas Avén

1249 багатокутників з ~ 600 балів за багатокутник.
Уффе Кусгаард

3
@Uffe Kousgaard, так, це абсолютно можливо. Ви змусили мене спробувати. Відповідь нижче.
Nicklas Avén

Кудо за підйом на виклик! У деяких стендових тестах SpatialLite насправді працює швидше, ніж PostGIS, але ви повинні бути уважними, як налаштувати RTrees. Також я часто виявляв, що ArcGIS є повільнішим при запуску зсередини, але швидшим, коли працює із «автономним» модулем ArcPy «зовні».
MappaGnosis

Відповіді:


27

ST_DWithin був швидшим у моєму тесті, ніж ST_Intersects. Це дивно, тим більше, що підготовлений алгоритм геометрії передбачає подібні випадки. Я думаю, є ймовірність, що це буде набагато швидше, ніж я показав тут.


Я зробив ще кілька тестів, і дві речі майже в 10 разів подвоїли швидкість. По-перше, я спробував на більш новому комп’ютері, але все ж цілком звичайний ноутбук, можливо, крім SATA3 ssd -диски.

Тоді запит нижче займав 18 секунд замість 62 секунд на старому ноутбуці. Далі я виявив, що раніше я абсолютно помилявся, коли писав, що індекс на таблиці таблиці не потрібен. З цим індексом на місці ST_Intersects поводився як очікувалося, і все стало дуже швидко. Я збільшив кількість балів у табличній точці до 1 мільйона балів та запиту:

CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id 
FROM imported_ct , t WHERE ST_Intersects(imported_ct.geom , t.geom);

працює за 72 секунди. Оскільки є 1249 полігонів, 1249000000 тестів робиться за 72 секунди. Це робить близько 17000000 тестів за секунду. Або тестування майже 14000 балів проти всіх багатокутників за секунду.

Після цього тесту ваші 400000000 балів до тестування повинні тривати близько 8 годин без проблем з розподілом навантаження на кілька ядер. PostGIS ніколи не припиняє мене вражати :-)


По-перше, для візуалізації результату ви можете додати геометрію точки до отриманої таблиці, відкрити її в QGIS, наприклад, та накреслити її унікальними значеннями в полі import_ct.

По-друге, так, ви також можете отримати точки, що виходять за межі будь-якого багатокутника, скориставшись правим (або лівим) з'єднанням так:

CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id 
FROM imported_ct right join t ON ST_Intersects(imported_ct.the_geom , t.geom);

Я зробив кілька тестів, щоб перевірити, чи здається це можливим PostGIS.

Спочатку щось я не розумію. У вас є два очки за ряд. Чи завжди обидві точки в одному полігоні? Тоді досить зробити розрахунки по одній з точок. Якщо вони можуть бути у двох різних многокутниках, вам знадобиться спосіб з'єднати один точковий ряд з двома багатокутниками.

З тестів це здається можливим, але вам може знадобитися креативне рішення для поширення навантаження на більш ніж один процесор-ядро.

Я тестував 4-річний ноутбук з двоядерним процесором centrino (я думаю, приблизно 2,2 ГГц), 2 Гб оперативної пам’яті. Якщо у вас є 48 BG RAM, я думаю, у вас є і набагато більше процесорної потужності.

Що я зробив, це створити таблицю випадкових точок із 100000 балів, як це:

CREATE TABLE t AS
WITH r AS
(SELECT ST_Extent(the_geom)::geometry ext FROM imported_ct)
SELECT ST_Point(x,y) AS geom FROM 
(SELECT GENERATE_SERIES(1,100000)) s,
(SELECT ST_Xmin(ext)+(random()*(ST_Xmax(ext)-ST_Xmin(ext))) x, ST_Ymin(ext)+(random()*(ST_Ymax(ext)-ST_Ymin(ext))) y FROM r
) f;

Потім додайте gid на зразок:

ALTER TABLE t ADD COLUMN GID SERIAL;

Потім працює:

CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE ST_Dwithin(imported_ct.the_geom , t.geom,0);

займає приблизно 62 секунди (порівняйте ваш результат ArcGIS з однаковою кількістю балів). Результатом є таблиця, що з'єднує точки моєї таблиці t з gid в таблиці з переписом.

З цією швидкістю ви зробите 200 мільйонів балів приблизно за 34 години. Отже, якщо цього достатньо для перевірки однієї точки, мій старий ноутбук може це зробити з одним ядром.

Але якщо вам потрібно перевірити обидва пункти, це може бути складніше.

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

У своєму прикладі з 50000 очок та двома процесорними ядрами я спробував:

CREATE TABLE t1 as
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE t.gid >50000 and  ST_Dwithin(imported_ct.the_geom , t.geom,0);

на одному db-сеансі одночасно із запуском:

CREATE TABLE t2 as
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE t.gid <=50000 and  ST_Dwithin(imported_ct.the_geom , t.geom,0);

на іншому db-сеансі.

Це зайняло близько 36 секунд, тому це трохи повільніше, ніж перший приклад, ймовірно, залежно від запису диска одночасно. Але оскільки одночасно працюють бітові сердечники, це не зайняло більше 36 секунд мого часу.

Для об'єднання таблиць t1 і t2 a спробували:

CREATE TABLE t3 AS 
SELECT * FROM t1
UNION ALL
SELECT * FROM t2;

використовуючи приблизно півсекунди.

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

Можливо, варто відзначити, що приклад з Linux (Ubuntu). Використання Windows буде іншою історією. Але в мене працюють всі інші щоденні програми, тому ноутбук досить сильно завантажений від раніше. Тож, можливо, це може імітувати корпус Windows цілком добре, не відкриваючи нічого, крім pgadmin.


1
Я просто перейменував .tl_2011_08_trac в import_ct, тому що було легше писати. Отже, просто змініть import_ct у моєму запиті на .tl_2011_08_trac, і вам слід добре.
Nicklas Avén

2
@meer BTW, використовуючи template_postgis_20 як будь-що інше, ніж шаблон для майбутніх баз даних, не рекомендується. Оскільки у вас, здається, є PostGIS 2.0, якщо у вас також є PostgreSQL 9.1, ви можете просто створити новий db і запустити "CREATE EXTENSION POSTGIS;"
Nicklas Avén

1
Так, це був черговий друкарський помилок, який, я думаю, я виправив кілька хвилин тому. Вибач за це. Спробуйте також версію ST_Intersects, яка повинна бути набагато швидшою.
Nicklas Avén

1
@meer Причина, на яку не впливає кожна точка, полягає в тому, що випадкові точки розміщуються у прямокутнику, і я думаю, що карта не є прямокутним. Я буду редагувати публікацію, щоб показати, як бачити результат.
Nicklas Avén

1
@Uffe Kousgaard, так, я думаю, ви можете так сказати. Він займає один багатокутник за один раз і готує його, будуючи дерево країв. Потім він перевіряє всі точки (що індекс сортував як цікаві, перекриваючи скриньки) проти цього підготовленого багатокутника.
Nicklas Avén

4

Напевно, найпростіший спосіб - із PostGIS. В Інтернеті є кілька навчальних посібників, як імпортувати дані csv / txt в PostGIS. Посилання1

Я не впевнений у виконанні точкових полігонових пошуків у PostGIS; він повинен бути швидшим, ніж ArcGIS. Просторовий індекс GIST, який використовує PostGIS, досить швидко. Link2 Link3

Ви також можете перевірити геопросторовий індекс MongoDB . Але для цього потрібно трохи більше часу, щоб почати. Я вважаю, що MongoDB може бути дуже швидким. Я не перевіряв це за допомогою точкового пошуку в полігоні, тому не можу бути впевненим.

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