在SpatiaLite中找到具有点位置的两个表之间的最近邻居?


10

我今天开始与SpatiaLite玩,已经偶然发现了一个问题。

对于tableOne中存储的每个点位置,我想从tableTwo中选择一个最近的(线性距离)点。

到目前为止,我想出了一个使用VIEW的笨拙解决方案:

CREATE VIEW testview AS 
SELECT 
A.id , 
B.myValue, 
Distance(A.Geometry, B.Geometry) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE distance < 10000
ORDER BY A.Id, distance;

然后:

SELECT * FROM testview
WHERE distance = (SELECT MIN(distance) FROM testview AS t WHERE t.id = testview.id)

似乎能胜任。

两个问题:

有没有一种方法可以执行这种查询而无需创建VIEW?

还有其他方法可以优化此查询以获得更好的性能吗?在现实世界中,tableOne将具有成百上千的记录,而tableTwo将具有130万。


我可以为您提供一种速度快几个数量级的方法,但是它需要您使用postgresql 9的knngist索引而不是
spacespaceite

实际上比GRASS,ArcGIS,QGIS,SQLServer和几乎任何其他空间db / Desktop GIS都快(尽管还没有尝试使用Oracle最近邻功能)。请让我知道是否可以选择。
Ragi Yaser Burhum 2011年

@Ragi:我知道PostGIS将是解决此类问题的更有效方法。但是,此练习的最终目标是制作小型便携式应用程序,在这种情况下,SpatiaLite是赢家。
radek 2011年

您的便携式应用程序的开发平台是什么?
艾伦·阿黛尔

@Allan:同时在这两个平台上工作:Windows Server 2008和Ubuntu。
radek 2011年

Answers:


5

我刚刚测试了此SQL,它的工作原理是:

SELECT g1.OGC_FID As id1, g2.OGC_FID As id2, MIN(ST_Distance(g1.GEOMETRY,g2.GEOMETRY)) AS DIST
FROM table_01 As g1, table_02 As g2   
WHERE g1.OGC_FID <> g2.OGC_FID
AND ST_Contains(ST_Expand(g1.geometry,50),g2.geometry)
GROUP BY id1
ORDER BY id1

如您在这里所读 “执行最近邻居查询的天真的方法是按照距查询几何体的距离对候选表进行排序,然后以最小的距离进行记录”。

最好的祝福,

安德里亚


我正在尝试使用此查询,但是得到了意外的结果-我得到的是结果表,但具有可以看到的行ID的不是最近的邻居。我试图在多线字符串层中找到与另一层中的每个点最近的线。我是spatiaLite的新手。有什么建议么?另外,我最终希望以100万以上的积分运行
kflaw 2015年

我也不确定我是否理解此声明的目的:WHERE g1.OGC_FID <> g2.OGC_FID
kflaw

另外,在我的结果中,我得到零距离。我玩过这条线:AND ST_Contains(ST_Expand(g1.geometry,50),g2.geometry)并删除了它,尽管我得到一个ID仍然没有获得距离值
kflaw

6

如果您不想计算所有点组合之间的距离,可以在一张桌子上使用一个空间索引:

SELECT 
  A.id , 
  B.myValue, 
  MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE A.ROWID IN (
  SELECT ROWID
  FROM SpatialIndex WHERE
    f_table_name = 'A' 
    AND search_frame = BuildCircleMbr(ST_X(B.Geometry), ST_Y(B.Geometry), 10000))
GROUP BY A.id, B.myValue

我尝试使用您发布的解决方案,因为我需要使用空间索引,但是它不返回任何值?对于该行f_table_name = 'A',我需要用实际的表名(表一)替换“ A”吗?我已经尝试过其中一种方法,但仍然不返回任何内容,为什么会这样
kflaw

你是正确的f_table_name = 'A'应该是 f_table_name = 'tableOne'。请注意,此请求假定spacespaceite> 4.x(使用SpatialIndex虚拟表)。您是否尝试过search_frame针对您的用例进行调整?在上面的示例中,假定点的最大距离为10000米。
塞缪尔

我确实尝试了搜索框的值,我认为这意味着在10000米以内对我有用。我实际上不知道哪个版本的spacespaceite,我通过qgis创建了数据库,并在qgis中使用了gui。让我看看我是否能弄清楚
kflaw

它是4.1.1版本,而sqlite版本是3.7.17,那么它应该可以工作吗?我想知道怎么了,我会再测试一下
kflaw

3

从版本4.4.0开始,SpatiaLite支持用于最近邻居问题的KNN虚拟表索引。这是一个查询,用于查找线串表中与点表中每个点最近的线。

SELECT k.* FROM knn k, points p
WHERE f_table_name = 'linestrings' 
AND ref_geometry = p.geometry
AND max_items = 1;

2

您可以像这样简化查询。

SELECT 
   A.id , 
   B.myValue, 
   MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
GROUP BY A.id, B.myValue

对于更通用的解决方案,可能值得尝试转换此PostGIS最近邻居功能:http : //blog.mackerron.com/2011/03/postgis-nearest-neighbour/


不幸的是,代码导致:SQL error: "misuse of aggregate: MIN()"
radek 2011年

至于PostGIS ,BostonGIS网站上也有一些示例,但是到目前为止,我还没有成功将它们翻译成SpatiaLite:/
radek 2011年
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.