200 milyon puanlık Poligon Nokta Analizi için en hızlı çözümü arıyor [kapalı]


35

Aşağıdaki formatta 200 milyon gözlem içeren bir CSV'm var:

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"

Her bir koordinat grubu için (x1 / y1 ve x2 / y2), içine düşen ABD Sayım Yolu veya Sayım Bloğunu atamak istiyorum (Sayım TIGER şekil dosyasını buraya indirdim: ftp://ftp2.census.gov/ coğrafi / kaplan / TIGER2011 / TRACT / tl_2011_08_tract.zip ). Bu nedenle, her gözlem için iki kez bir poligon noktası işlemi yapmam gerekiyor. Kibritlerin çok doğru olması önemlidir.

Yazılımı öğrenmek için zaman dahil, bunu yapmanın en hızlı yolu nedir? İlgili kısıtlama olması durumunda, 48 GB Bellek içeren bir bilgisayara erişimim var.

Birkaç konu PostGIS veya Spatialite kullanmanızı önerir (Spatialite kullanımı daha kolay görünüyor - fakat PostGIS kadar verimli mi?). Bunlar en iyi seçenekse, Mekansal Dizini (RTree?) Doldurmak zorunlu mudur? Öyleyse, bunu nasıl yapar (örneğin, Sayım Yolu Şekil Dosyasını kullanarak)? Örnek kod (veya örnek kodun işaretçisi) içeren öneriler için minnettar olurum.

İlk teşebbüsüm (bu siteyi bulmadan önce), ABD Nüfus Sayımı Bloku'ndaki verilerin alt örneğinin (100.000 puan) uzamsal birleşimini (yalnızca x1 / y1) yapmak için ArcGIS'i kullanmaktan ibaretti. Süreci öldürmeden 5 saatten fazla sürdü. Veri setinin tamamında 40 saatin altındaki hesaplama süresinde uygulanabilecek bir çözüm bulmayı umuyorum.

Daha önce sorulan bir soruyu sormak için özür dilerim - Cevapları okudum ve tavsiyelerin nasıl uygulanacağını merak ediyorum. SQL, Python, C'yi hiç kullanmamıştım ve ArcGIS'i daha önce sadece bir kez kullanmıştım - tam bir acemi değilim.


3
40 saat, saniyede neredeyse 2800 nokta-poligon noktası işlemine eşittir. Sadece aklımda ses gelmiyor. Hangi yazılım parçasının (ArcGIS, PostGIS, Spatialite vb.) En hızlı olduğu konusunda hiçbir fikrim yok, ama mekansal bir endekse kuşkusuz gerekli değil.
Uffe Kousgaard

1
Çokgenler karışmazsa sorun olmaz. Endeksten (PostGIS'te) elde edilen kazanç, çokgenlerin büyüklüğüne bağlı olacaktır. Küçük poligonlar (daha küçük sınırlayıcı kutular), indeksler daha fazla yardımcı olur. Muhtemelen mümkün.
Nicklas Avén

Poligon başına ~ 600 puan ile 1249 poligon.
Uffe Kousgaard

3
@Uffe Kousgaard, evet kesinlikle mümkün. Denememi istedin. Aşağıdaki cevabı görün.
Nicklas Avén

Meydan yükselişi için Kudos! Bazı tezgah testlerinde SpatialLite aslında PostGIS'ten daha hızlı performans gösterir, ancak RTrees'inizi nasıl kurduğunuza dikkat etmeniz gerekir. Ayrıca ArcGIS'i 'içeriden' çalışırken daha yavaş, ancak 'bağımsız' bir ArcPy modülüyle 'dışarıda' çalışırken daha hızlı buldum.
MappaGnosis

Yanıtlar:


26

ST_DWithin testimde ST_Iersters'ten daha hızlıydı. Bu şaşırtıcı, özellikle hazırlanan geometri algoritmasının bu gibi durumlarda devreye girmesi gerektiği için. Bunun gösterdiğimden çok daha hızlı olma ihtimali olduğunu düşünüyorum.


Biraz daha testler yaptım ve iki şey neredeyse 10 katına çıktı. İlk önce, daha yeni bir bilgisayarda denedim, ama hala oldukça sıradan bir dizüstü bilgisayar, belki de SATA3 ssd diskleri dışında.

Daha sonra aşağıdaki sorgu eski dizüstü bilgisayarda 62 saniye yerine 18 saniye sürdü. Daha sonra, puan tablosundaki endeksin gerekmediğini yazdığımda daha önce tamamen yanlış olduğumu öğrendim. Bu indeks yerinde iken ST_Intersects beklendiği gibi davrandı ve işler çok hızlı oldu. Puan tablosundaki puan sayısını 1 milyon puana ve sorguyu arttırdım:

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 saniye içinde çalışır. 1249 poligon olduğu için 72 saniyede 1249000000 testi yapılır. Bu saniyede yaklaşık 17000000 test yapar. Veya saniyede tüm poligonlara karşı neredeyse 14000 puan test etmek.

Bu testten 400000000 test edilebilecek puanınız, yükü birkaç çekirdeğe dağıtmakta sorun yaşamadan yaklaşık 8 saat sürmelidir. PostGIS beni etkilemek için asla durmaz :-)


İlk olarak, sonucu görselleştirmek için sonuç geometrisini sonuç tablosuna ekleyebilir, örneğin QGIS'de açabilir ve import_ct alanında benzersiz değerlerle stillendirebilirsiniz.

İkincisi, evet, ayrıca böyle bir sağ (veya sol) birleşimini kullanarak herhangi bir poligonun dışına düşen noktaları elde edebilirsiniz:

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'in mümkün olup olmadığını doğrulamak için bazı testler yaptım.

İlk önce anlamadığım bir şey var. Satır başına iki puanınız var. Her zaman her iki nokta da aynı poligonda mı? O zaman noktalardan bir tanesinde hesaplamaları yapmak yeterlidir. İki farklı poligonda olabilirlerse, bir nokta sırasını iki poligona bağlamanın bir yoluna ihtiyacınız olacaktır.

Testlerden mümkün gibi görünüyor, ancak yükü birden fazla işlemci çekirdeğine yaymak için yaratıcı bir çözüme ihtiyacınız olabilir.

İki çekirdekli centrino işlemci (yaklaşık 2.2GHz sanırım) 2GB RAM ile 4 yaşında bir dizüstü bilgisayarda test ettim. 48 BG RAM'iniz varsa sanırım çok daha fazla cpu gücünüz var.

Yaptığım şey, bunun gibi 100000 puan ile rastgele bir nokta tablosu oluşturmaktı:

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;

Sonra bir gid ekleyerek:

ALTER TABLE t ADD COLUMN GID SERIAL;

Sonra çalışıyor:

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);

yaklaşık 62 saniye sürer (ArcGIS sonucunuzla aynı miktarda puanla karşılaştırın). Sonuç, benim masamdaki t noktalarını sayım yolundaki masanın içindeki gid ile birleştiren bir tablodur.

Bu hızla yaklaşık 34 saatte 200 değirmen puanı yapacaksınız. Öyleyse, noktalardan birini kontrol etmek yeterliyse, eski dizüstü bilgisayarım bunu bir çekirdekle yapabilir.

Ancak her iki noktayı da kontrol etmeniz gerekirse, daha zor olabilir.

Daha sonra, db'ye karşı birden çok oturumu başlatarak ve farklı sorgular çalıştırarak yükü birden fazla çekirdeğe manuel olarak dağıtabilirsiniz.

Örneğimde 50000 puan ve iki cpu çekirdeği ile denedim:

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);

Bir db oturumunda koşarken aynı anda:

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);

başka bir db oturumunda.

Bu yaklaşık 36 saniye sürdü, bu yüzden muhtemelen aynı anda disk yazmaya bağlı olarak ilk örnekten biraz daha yavaştı. Ancak, çekirdek çekirdekleri aynı anda çalıştığı için zamanımın 36 saniyesinden fazla bir zaman almadı.

T1 ve t2 tablolarını birleştirmek için:

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

yaklaşık yarım saniye kullanarak.

Dolayısıyla, daha yeni donanım ve yükü birçok çekirdeğe dağıtmakla, gerçek dünya test durumundan daha yavaş olsa bile bu kesinlikle mümkün olmalıdır.

Örnegin Linux (Ubuntu) oldugunu farketmeye deger olabilir. Windows kullanarak başka bir hikaye olacak. Ancak çalışan diğer tüm günlük uygulamalarım var, böylece dizüstü bilgisayar eskisinden çok ağır bir şekilde yüklendi. Bu nedenle, windows kasasını pgadmin dışında bir şey açmadan oldukça iyi bir şekilde taklit edebilir.


1
.Tl_2011_08_trac dosyasını, import_ct olarak değiştirdim, çünkü yazmak daha kolaydı. Bu yüzden, benim sorguğumda import_ct komutunu .tl_2011_08_trac olarak değiştirin.
Nicklas Avén

2
@meer BTW, template_postgis_20'yi gelecek veritabanları için bir şablondan başka bir şey olarak kullanmak önerilmez. PostGIS 2.0'a sahip olduğunuzdan, PostgreSQL 9.1'iniz varsa, yeni bir db oluşturabilir ve "CREATE EXTENSION POSTGIS;"
Nicklas Avén

1
Evet, birkaç dakika önce tamir ettiğimi düşündüğüm başka bir yazım hatası oldu. Bunun için üzgünüm. Ayrıca bunun yerine ST_Intersects sürümünü de deneyin, bu çok daha hızlı olmalı.
Nicklas Avén

1
@Teer Her noktanın etkilenmemesinin nedeni, rastgele noktaların bir dikdörtgen içine yerleştirilmiş olmasıdır ve haritanın tam bir dikdörtgen olmadığını tahmin ediyorum. Sonucu nasıl göreceğimi göstermek için yazı üzerinde bir düzenleme yapacağım.
Nicklas Avén

1
@Uffe Kousgaard, Evet, sanırım bu şekilde koyabilirsiniz. Her seferinde bir çokgen alır ve kenarlarından bir ağaç oluşturarak hazırlar. Daha sonra hazırlanan tüm poligonla (indeksin üst üste gelen kutucuklarla gizlice girdiği şekilde sıraladığını) tüm noktaları kontrol eder.
Nicklas Avén

4

Muhtemelen en kolay yol PostGIS'tir. İnternette csv / txt point verilerinin PostGIS'e nasıl aktarılacağı konusunda bazı dersler bulunmaktadır. link1

PostGIS'de çokgenli nokta aramalarının performansından emin değilim; ArcGIS'ten daha hızlı olması gerekir. PostGIS'in kullandığı GIST uzaysal endeksi oldukça hızlı. Link2 Link3

MongoDB coğrafi endeksini de test edebilirsiniz . Ancak bu başlamak için daha az zaman gerektirir. MongoDB'nin çok hızlı olabileceğine inanıyorum. Poligondaki nokta aramalarıyla test etmedim, bu yüzden emin olamadım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.