我想使用 Postgres 和 PostGIS 编写查询。我也将 Rails 与rgeo
,rgeo-activerecord
和一起使用activerecord-postgis-adapter
,但 Rails 的东西并不重要。
表结构:
measurement
- int id
- int anchor_id
- Point groundtruth
- data (not important for the query)
示例数据:
id | anchor_id | groundtruth | data
-----------------------------------
1 | 1 | POINT(1 4) | ...
2 | 3 | POINT(1 4) | ...
3 | 2 | POINT(1 4) | ...
4 | 3 | POINT(1 4) | ...
-----------------------------------
5 | 2 | POINT(3 2) | ...
6 | 4 | POINT(3 2) | ...
-----------------------------------
7 | 1 | POINT(4 3) | ...
8 | 1 | POINT(4 3) | ...
9 | 1 | POINT(4 3) | ...
10 | 5 | POINT(4 3) | ...
11 | 3 | POINT(4 3) | ...
该表是某种手动创建view
的,用于更快的查找(具有数百万行)。否则我们必须加入 8 个表,它会变得更慢。但这不是问题的一部分。
简单版:
参数:
- 观点
p
- 整数
d
查询应该做什么:
1.查询查找所有groundtruth
具有distance < d
from Point的 Pointsp
SQL 非常简单:WHERE st_distance(groundtruth, p) < d
2.现在我们有了一个带有s的groundtruth
点列表。anchor_id
如上表所示,可能有多个相同的 groundtruth-anchor_id 元组。例如:anchor_id=3
和groundtruth=POINT(1 4)
。
3.接下来我想通过随机选择其中一个来消除相同的元组(!)。为什么不直接拿第一呢?因为data
列不同。
在 SQL 中选择一个随机行:SELECT ... ORDER BY RANDOM() LIMIT 1
我对这一切的问题是:我可以想象一个使用 SQLLOOP
和大量子查询的解决方案,但肯定有一个解决方案使用GROUP BY
或其他一些方法可以使它更快。
完整版本:
与上述基本相同,不同之处在于:输入参数变化:
- 很多积分
p1
...p312456345
- 还是一个
d
如果简单查询有效,则可以使用LOOP
in SQL 来完成。但也许有更好(更快)的解决方案,因为数据库真的很大!
解决方案
WITH ps AS (SELECT unnest(p_array) AS p)
SELECT DISTINCT ON (anchor_id, groundtruth)
*
FROM measurement m, ps
WHERE EXISTS (
SELECT 1
FROM ps
WHERE st_distance(m.groundtruth, ps.p) < d
)
ORDER BY anchor_id, groundtruth, random();
感谢欧文·布兰德施泰特!