寻找用于2亿个点的多边形分析中最快的解决方案[关闭]


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)。因此,我需要为每个观察做两次多边形点操作。比赛必须非常准确。

最快的方法是什么,包括花时间学习软件?我可以访问具有48GB内存的计算机,以防万一这可能是一个相关的限制。

有多个线程建议使用PostGIS或Spatialite(Spatialite看起来更易于使用-但它与PostGIS一样有效吗?)。如果这些是最佳选择,是否必须填充空间索引(RTree)?如果是这样,怎么做(例如使用人口普查道Shapefile)?对于包含示例代码(或示例代码的指针)的任何建议,我将不胜感激。

我的第一次尝试(在找到此站点之前)包括使用ArcGIS对美国人口普查数据块的数据(100,000点)的子样本进行空间连接(仅x1 / y1)。在我终止该过程之前,花了5个多小时。我希望可以在不到40小时的计算时间内对整个数据集实施的解决方案。

很抱歉提出之前提出的问题-我已经阅读了答案,但不知道如何实施建议。我从未使用过SQL,Python,C,并且以前只使用过一次ArcGIS-我是一个完整的初学者。


3
40小时等于每秒将近2800个多边形点操作。在我看来,这听起来似乎是不可能的。我不知道哪个软件(ArcGIS,PostGIS,Spatialite等)最快,但是毫无疑问需要一个空间索引。
Uffe Kousgaard'5

1
如果多边形不复杂,应该没问题。从索引中获取的收益(在PostGIS中)将取决于多边形的大小。较小的多边形(较小的边界框)将对索引有所帮助。可能是可能的。
尼克拉斯·阿芬(NicklasAvén)2012年

1249个多边形,每个多边形约有600个点。
Uffe Kousgaard'5

3
@Uffe Kousgaard,是的,绝对有可能。你让我尝试一下。硒回答如下。
尼克拉斯·阿芬(NicklasAvén)

勇于挑战!在某些基准测试中,SpatialLite实际上比PostGIS更快地执行,但是您必须小心设置RTree的方式。我还经常发现,从“内部”运行时,ArcGIS速度较慢,而从“独立” ArcPy模块“外部”运行时,ArcGIS速度较快。
MappaGnosis

Answers:


26

在我的测试中,ST_DWithin比ST_Intersects更快。这是令人惊讶的,特别是因为准备好的几何算法应该在这种情况下起作用。我认为这有可能比我在这里显示的要快得多。


我做了一些测试,发现两件事几乎使速度提高了一倍。首先,我尝试使用较新的计算机,但仍然是一台非常普通的笔记本电脑,也许除了SATA3 ssd -disks以外。

然后,下面的查询用了18秒,而不是旧笔记本电脑上的62秒。接下来,我发现在写点表上的索引不是必需的之前我是完全错误的。有了该索引,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个多边形,因此在72秒内完成了1249000000个测试。每秒约进行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是否可能。

首先,我不明白。每行有两个点。两个点始终都在同一多边形中吗?这样就可以对其中一个点进行计算了。如果它们可以位于两个不同的多边形中,则需要一种将一个点行连接到两个多边形的方法。

从测试来看,这似乎可行,但是您可能需要一些创造性的解决方案才能将负载分散到多个cpu内核上。

我在一台具有双核centrino cpu(我认为约为2.2GHz),2GB 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磨点。因此,如果只需检查其中一项就足够了,那么我的旧笔记本电脑就可以使用一个内核来做到这一点。

但是,如果您需要检查这两点,可能会更困难。

然后,您可以通过针对数据库启动多个会话并运行不同的查询,将负载手动分配给多个内核。

在我的示例中,使用50000点和两个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);

在一个数据库会话上同时运行:

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

在另一个数据库会话上。

这花了大约36秒,因此它可能比第一个示例慢一点,这可能取决于同时写入光盘。但是由于bith核心在同一时间工作,所以我花的时间不超过36秒。

要尝试合并表t1和t2:

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

用大约半秒钟。

因此,使用较新的硬件并在许多内核上分配负载,即使现实世界比测试案例要慢,这绝对应该是可能的。

可能值得注意的是该示例来自Linux(Ubuntu)。使用Windows将是另一回事。但是我还有所有其他日常应用程序正在运行,因此笔记本电脑以前的负载非常重。这样也许可以很好地模拟Windows情况,而无需打开pgadmin。


1
我只是将.tl_2011_08_trac重命名为important_ct,因为它更易于编写。因此,只需将查询中的imported_ct更改为.tl_2011_08_trac,您就可以正常进行。
NicklasAvén'12年

2
@meer BTW,不建议将template_postgis_20用作将来数据库的模板以外的其他东西。由于您似乎拥有PostGIS 2.0,因此如果您也拥有PostgreSQL 9.1,则只需创建一个新的数据库并运行“ CREATE EXTENSION POSTGIS;”即可。
NicklasAvén'12年

1
是的,这是我几分钟前解决的另一种错字。对于那个很抱歉。也可以尝试使用ST_Intersects版本,它应该快很多。
NicklasAvén'12年

1
@meer并非所有点都受到影响的原因是随机点放置在矩形中,我想地图并不完全是矩形。我将在帖子中进行编辑以显示如何查看结果。
尼克拉斯·阿芬(NicklasAvén)

1
@Uffe Kousgaard,是的,我想你可以这样说。一次需要一个多边形,并通过构建边缘树来进行准备。然后,它检查与准备好的多边形相对应的所有点(索引已通过重叠的bbox归类为有趣的点)。
尼克拉斯·阿芬(NicklasAvén)2012年

4

可能最简单的方法是使用PostGIS。互联网上有一些教程,介绍如何将csv / txt点数据导入PostGIS。链接1

我不确定PostGIS中多边形点搜索的性能;它应该比ArcGIS更快。PostGIS使用的GIST空间索引非常快。Link2 Link3

您还可以测试MongoDB地理空间索引。但这只需要更多时间就可以开始。我相信MongoDB可能真的很快。我尚未通过多边形点搜索对其进行测试,因此无法确定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.