在 bigquery 中使用 DBSCAN 进行聚类

Clustering using DBSCAN in bigquery

我有一个 Bigquery table,其中只有一列名为 'point'。它包含我想使用 BigQuery 中的 ST_CLUSTERDBSCAN 函数进行聚类的位置坐标。

我使用以下查询:

SELECT ST_CLUSTERDBSCAN(point, 2000, 200) OVER () AS cluster_num 
FROM mytable

我收到这个错误:

Resources exceeded during query execution: The query could not be executed in the allotted memory. Peak usage: 128% of limit. Top memory consumer(s): analytic OVER() clauses: 97% other/unattributed: 3%

据我了解,这是因为查询是内存密集型的。鉴于我的 table 包含数百万行,有什么方法可以使用集群我的数据?

BigQuery 中的大多数分析函数目前 运行 单个分片(机器)上的一个分区,因此分区大小在内存中被限制为大约 1GB 数据大小。在您的查询中,OVER () 表示没有分区 - 所有数据都在单个分区中 运行。

解决方案通常是以某种大粒度对数据进行分区。例如。如果数据具有某种空间层次结构,则可以按此列进行分区 - 例如做 OVER(PARTITION BY state)。当然,这意味着不会有跨州集群,所以结果并不完全相同,但如果有自然集群,这通常是合理的。

如果这种内在层次结构不可用,另一种选择是通过一个短的 geohash 进行分区(字母很少 - 尽可能多以避免资源超出错误),例如 OVER(PARTITION BY st_geohash(point, 2)). S2_CellIDFromPoint(ST_Centroid(geo, level)) 是一个不错的选择,请参阅 S2 cell sizes 选择单元格级别。

添加到 Michael 的回答中,我发现的问题之一是 S2 网格是规则的,与地面上不同的密度不匹配。因此,您往往会得到比您想要的小得多的分区,这只是因为您必须设置适合最密集区域的 S2 级别。 以英国为例,那里有不同比例的现成网格,我创建了一个 100 公里和 20 公里的混合网格,见下文。较小的正方形覆盖较大的城市。

另一种选择是使用 hex grid, which Carto have made available to BiqQuery via jslibs.h3.

还有许多其他选项,例如递归划分 space 类似于 KD 树构造,直到保证最大的剩余输入分区适合一个分片。

根据要执行的操作,还有一个额外的问题,即合并跨越 OVER 子句中使用的任何细分的集群。有解决方案,例如使用 ST_Union 和 ST_Intersects 并合并相邻的集群,但这超出了原始问题。最终,这就是为什么您要使分区尽可能大,但假设您要这样做,它会减少重组集群所需的工作量。