2億ポイントのPoint in Polygon分析の最速のソリューションを探しています[終了]


35

次の形式の2億の観測値を含むCSVがあります。

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)。そのため、観測ごとにポリゴンのポイント操作を2回行う必要があります。一致が非常に正確であることが重要です。

ソフトウェアを習得する時間を含め、これを行う最も速い方法は何ですか?48GBのメモリを搭載したコンピューターにアクセスできます-これが関連する制約になる場合があります。

いくつかのスレッドは、PostGISまたはSpatialiteの使用を推奨しています(Spatialiteは使いやすいようですが、PostGISと同じくらい効率的ですか?)。これらが最良のオプションである場合、空間インデックス(RTree?)を設定することが必須ですか?もしそうなら、どのようにそれを行うのでしょうか(例:国勢調査シェープファイルの使用)サンプルコード(またはサンプルコードへのポインター)を含む推奨事項に非常に感謝します。

このサイトを見つける前の最初の試みは、ArcGISを使用して、米国国勢調査ブロックのデータのサブサンプル(100,000ポイント)の空間結合(x1 / y1のみ)を行うことでした。プロセスを強制終了するまでに5時間以上かかりました。40時間未満の計算時間でデータセット全体に実装できるソリューションを期待しています。

以前に尋ねられた質問をおApびします-私は答えを一読しましたが、どのように推奨事項を実装するのか疑問に思っています。私はSQL、Python、Cを使用したことがなく、ArcGISを使用したことが一度もありません-私は完全な初心者です。


3
40時間は、1秒あたりほぼ2800ポイントのポリゴン操作に相当します。私の考えでは不可能だと思うだけです。どのソフトウェア(ArcGIS、PostGIS、Spatialiteなど)が最も高速かはわかりませんが、空間インデックスは間違いなく必要です。
Uffe Kousgaard

1
ポリゴンが複雑にならない場合は問題ないはずです。(PostGISの)インデックスからのゲインは、ポリゴンの大きさに依存します。ポリゴンが小さい(境界ボックスが小さい)ほど、インデックスが役立ちます。おそらくそれは可能です。
ニックラスアヴェン

ポリゴンあたり最大600ポイントの1249ポリゴン。
Uffe Kousgaard

3
@Uffe Kousgaard、はい、それは絶対に可能です。あなたは私に試してみました。以下に答えてください。
ニックラスアベン

挑戦に立ち上がってくれた名誉!一部のベンチテストでは、SpatialLiteは実際にはPostGISよりも高速に実行されますが、RTreeの設定方法に注意する必要があります。また、ArcGISは、「内部」から実行すると遅くなりますが、「スタンドアロン」ArcPyモジュール「外部」で実行すると速くなることもよくわかりました。
MappaGnosis

回答:


27

私のテストでは、ST_DWithinはST_Intersectsよりも高速でした。特に、準備されたジオメトリアルゴリズムがこのような場合に作動することになっているため、これは驚くべきことです。ここで示したよりもかなり高速になる可能性があると思います。


さらにテストを行ったところ、2つのことが速度をほぼ10倍にしました。最初に、新しいコンピューターで試しましたが、SATA3 ssd -disksを除いて、かなり普通のラップトップでした。

次に、古いラップトップでは62秒ではなく18秒かかりました。次に、ポイントテーブルのインデックスは不要であると書いたとき、私はまったく間違っていたことがわかりました。そのインデックスを配置すると、ST_Intersectsは期待どおりに動作し、非常に高速になりました。ポイントテーブルのポイント数を100万ポイントとクエリに増やしました。

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秒で完了します。これは、1秒あたり約17000000テストになります。または、毎秒すべてのポリゴンに対してほぼ14000ポイントをテストします。

このテストから、テストする400000000ポイントは、負荷を複数のコアに分散する際に問題なく約8時間かかります。PostGISが私を感動させることは決してありません:-)


まず、結果を視覚化するために、結果のテーブルにポイントジオメトリを追加し、たとえばQGISで開いて、imported_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が可能かどうかを確認するために、いくつかのテストを行いました。

最初に私が理解できないこと。行ごとに2つのポイントがあります。常に両方のポイントが同じポリゴンにありますか?次に、いずれかのポイントで計算を行うだけで十分です。2つの異なるポリゴンに配置できる場合は、1つのポイント行を2つのポリゴンに接続する方法が必要です。

テストからは実行可能と思われますが、負荷を複数のCPUコアに分散させるための創造的なソリューションが必要になる場合があります。

デュアルコアのCentrino CPU(約2.2 GHzと思う)、2 GB RAMを搭載した4歳のラップトップでテストしました。48個のBG RAMがある場合は、CPUパワーもはるかに大きいと思います。

私がしたことは、次のように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を接続するテーブルです。

その速度で、約34時間で200ミルポイントを処理できます。したがって、ポイントの1つをチェックするだけで十分であれば、私の古いラップトップは1つのコアでそれを行うことができます。

ただし、両方のポイントを確認する必要がある場合は、難しいかもしれません。

その後、dbに対して複数のセッションを開始して異なるクエリを実行することにより、手動で負荷を複数のコアに分散できます。

私の例では、50000ポイントと2つのCPUコアを試しました。

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

実行と同時に1つの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秒かかりましたので、おそらく同時にディスクの書き込みに依存している最初の例よりも少し遅くなります。しかし、bithコアは同時に動作しているため、36秒以上かかることはありませんでした。

テーブルt1とt2を結合するには

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

約0.5秒使用します。

したがって、新しいハードウェアを使用し、多くのコアに負荷を分散することにより、実際の環境がテストケースよりも遅くなる場合でも、これは絶対に可能になります。

この例はLinux(Ubuntu)からのものであることに注意してください。Windowsの使用もまた別の話です。しかし、私は他のすべての日常的なアプリケーションを実行しているので、ラップトップは以前からかなり負荷がかかっています。したがって、pgadmin以外を開かずに、Windowsの場合を非常にうまくシミュレートできます。


1
.tl_2011_08_tracの名前をimported_ctに変更したのは、記述しやすいためです。したがって、クエリのimported_ctを.tl_2011_08_tracに変更するだけで、うまくいくはずです。
ニックラスアベン

2
@meer BTW、template_postgis_20を将来のデータベースのテンプレート以外として使用することは推奨されません。PostGIS 2.0を使用しているように見えるため、PostgreSQL 9.1も使用している場合は、新しいデータベースを作成して「CREATE EXTENSION POSTGIS;」を実行するだけです。
ニックラスアヴェン

1
はい、それは別のタイプミスで、数分前に修正したと思います。ごめんなさい また、代わりにST_Intersectsバージョンを試してください。これは非常に高速です。
ニックラスアベン

1
@meerすべてのポイントが影響を受けるわけではない理由は、ランダムなポイントが長方形に配置されているため、マップが長方形ではないことです。投稿を編集して、結果の表示方法を示します。
ニックラスアベン

1
@Uffe Kousgaard、はい、あなたはそのようにそれを置くことができると思います。一度に1つのポリゴンを取り、エッジのツリーを構築して準備します。次に、その準備されたポリゴンに対して、すべてのポイント(インデックスがbboxのオーバーラップにより魅力的なものとしてソートされている)をチェックします。
ニックラスアベン

4

おそらく最も簡単な方法はPostGISを使用することです。csv / txtポイントデータをPostGISにインポートする方法については、インターネット上にいくつかのチュートリアルがあります。Link1

PostGISでのポイントインポリゴン検索のパフォーマンスについてはわかりません。ArcGISよりも高速である必要があります。PostGISが使用するGIST空間インデックスは非常に高速です。Link2 Link3

MongoDB地理空間インデックスをテストすることもできます。しかし、これを始めるにはもう少し時間が必要です。MongoDBは非常に高速であると信じています。ポイントインポリゴン検索ではテストしていませんので、確認できません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.