空间分析最佳实践

本文档介绍了优化 BigQuery 中地理空间查询性能的最佳实践。您可以利用这些最佳实践来提高性能,并降低费用和延迟时间。

数据集可以包含大量的多边形、多边形图形和线条串,用于表示复杂地图项,例如道路、地块和洪灾区。每个形状可以包含数千个点。在 BigQuery 中的大多数空间运算(例如交叉和距离计算)中,底层算法通常会访问每个形状中的大多数点来生成结果。对于某些操作,算法会访问所有点。对于复杂的形状,访问每个点可能会增加空间操作的开销和时长。您可以使用本指南中介绍的策略和方法来优化这些常见的地理空间操作,从而提升性能并降低费用。

本文档假设您的 BigQuery 地理空间表按地理位置列进行分片

简化形状

最佳实践:使用“简化”和“对齐到网格”函数将原始数据集的简化版本存储为具体化视图。

许多包含大量点的复杂形状都可以简化,而不会大幅降低精度。单独或结合使用 BigQuery ST_SIMPLIFYST_SNAPTOGRID 函数可减少复杂形状中的点数。将这些函数与 BigQuery 具体化视图结合使用,以将原始数据集的简化版本存储为具体化视图,并根据基表自动保持最新状态。

在以下用例中,简化形状最有助于降低数据集的费用并提高其性能:

  • 您需要保持与真实形状高度相似。
  • 您必须执行高精度、高准确度的操作。
  • 您希望加快可视化速度,同时不会明显丢失形状细节。

以下代码示例展示了如何对包含名为 geomGEOGRAPHY 列的基础表使用 ST_SIMPLIFY 函数。该代码会简化形状并移除点,而不会使形状的任何边缘偏离给定公差 1.0 米以上。

CREATE MATERIALIZED VIEW project.dataset.base_mv
  CLUSTER BY geom
AS (
  SELECT
    * EXCEPT (geom),
    ST_SIMPLIFY(geom, 1.0) AS geom
  FROM base_table
)

以下代码示例展示了如何使用 ST_SNAPTOGRID 函数将点捕获到分辨率为 0.00001 度的网格:

CREATE MATERIALIZED VIEW project.dataset.base_mv
  CLUSTER BY geom
AS (
  SELECT
    * EXCEPT (geom),
    ST_SNAPTOGRID(geom, -5) AS geom
  FROM base_table
)

此函数中的 grid_size 参数用作指数,即 10e-5 = 0.00001。在最糟糕的情况下(发生在赤道),此分辨率相当于约 1 米。

创建这些视图后,请使用与查询基表相同的查询语义查询 base_mv 视图。您可以使用此方法快速确定需要更深入分析的一组形状,然后对基准表执行第二次更深入的分析。测试您的查询,了解哪些阈值值最适合您的数据。

对于衡量用例,请确定您的用例所需的准确度。使用 ST_SIMPLIFY 函数时,请将 threshold_meters 形参设置为所需的精度级别。如需测量城市一级或更大范围的距离,请将阈值设置为 10 米。在较小尺度(例如,测量建筑物与最近水域之间的距离)下,请考虑使用较小的阈值(不超过 1 米)。使用较小的阈值会导致从给定形状中移除的点更少。

从 Web 服务中传送地图图层时,您可以使用 bigquery-geotools 项目预计算不同缩放级别的实体化视图。该项目是 Geoserver 的驱动程序,可让您从 BigQuery 传送空间图层。此驱动程序会创建多个具有不同 ST_SIMPLIFY 阈值参数的具体化视图,以便在较高的缩放级别下提供较少的详细信息。

使用点和矩形

最佳实践:将形状缩减为一个点或矩形,以表示其位置。

您可以将形状缩减为单个点或矩形,从而提高查询性能。本部分的方法无法准确表示形状的细节和比例,而是会针对表示形状的位置进行优化。

您可以使用形状的地理中心点(其质心)来表示整个形状的位置。使用包含相应形状的矩形创建形状的范围,您可以使用该范围来表示形状的位置并保留其相对大小的相关信息。

当您需要衡量两个地点(例如两个城市)之间的距离时,使用点和矩形最有助于降低数据集的费用并提升其性能。

例如,假设您要将美国土地地块数据库加载到 BigQuery 表中,然后确定最近的水域。在这种情况下,结合使用 ST_CENTROID 函数和本文档简化形状部分中介绍的方法预计算地块重心,可以减少使用 ST_DISTANCEST_DWITHIN 函数时执行的比较次数。使用 ST_CENTROID 函数时,需要在计算中考虑地块重心。以这种方式预计算地块重心还可以减少性能的差异,因为不同的地块形状可能包含不同数量的点。

此方法的变体是使用 ST_BOUNDINGBOX 函数(而非 ST_CENTROID 函数)计算输入形状周围的矩形封套。虽然这种方法不如使用单个点高效,但可以减少出现某些极端情况的几率。由于 ST_BOUNDINGBOX 函数的输出始终仅包含需要考虑的四个点,因此此变体仍然可以提供良好且一致的性能。边界框结果的类型为 STRUCT,这意味着您需要手动计算距离,或使用本文档后面介绍的矢量索引方法

使用船体

最佳实践:使用轮廓优化形状的位置表示。

假设您要对形状进行缩减包装并计算缩减包装的边界,则该边界称为外壳。在凸包中,所得形状的所有角度都是凸的。与形状的范围一样,凸包会保留一些与底层形状的相对大小和比例相关的信息。不过,使用外壳的代价是需要在后续分析中存储和考虑更多点。

您可以使用 ST_CONVEXHULL 函数进行优化,以表示形状的位置。使用此函数可以提高准确性,但会降低性能。ST_CONVEXHULL 函数与 ST_EXTENT 函数类似,不同之处在于输出形状包含更多点,并且点数会因输入形状的复杂性而异。对于形状不复杂的小型数据集,性能优势可能微不足道;但对于形状较大且复杂的超大型数据集,ST_CONVEXHULL 函数可在成本、性能和准确性之间取得良好的平衡。

使用网格系统

最佳实践:使用地理空间网格系统来比较区域。

如果您的用例涉及汇总本地化区域内的数据,并比较这些区域的统计汇总数据,那么您可以利用标准化的网格系统来比较不同的区域,从而获益。

例如,零售商可能希望分析其商店所在地区或他们考虑开设新商店的地区在时间上的受众特征变化。或者,保险公司可能希望通过分析特定区域的现有自然灾害风险,更好地了解财产风险。

使用 S2 和 H3 等标准网格系统可以加快此类统计汇总和空间分析的速度。使用这些网格系统还可以简化分析的开发并提高开发效率。

例如,在美国,使用人口普查小区进行比较时,会出现大小不一致的问题,这意味着需要应用校正因子,才能在人口普查小区之间进行同类比较。此外,人口普查小区和其他行政区划会随时间而变化,因此需要付出努力来修正这些变化。使用网格系统进行空间分析可以解决此类问题。

使用向量搜索和向量索引

最佳实践:针对最近邻地理空间查询使用向量搜索和向量索引。

我们在 BigQuery 中引入了矢量搜索功能,以实现语义搜索、相似度检测和检索增强生成等机器学习用例。实现这些用例的关键是使用一种名为近似最近邻搜索的索引编制方法。您可以使用向量搜索,通过比较表示空间中点的向量来加快和简化最近邻地理空间查询。

您可以使用向量搜索按半径搜索地图项。首先,确定搜索范围。您可以在最近邻搜索的结果集中发现最佳半径。确定半径后,使用 ST_DWITHIN 函数识别附近的地图项。

例如,假设您要查找距离某个已知位置的特定基准建筑物最近的 10 座建筑物。您可以将每个建筑物的质心作为向量存储在新表中,为表编制索引,然后使用向量搜索进行搜索。

对于本例,您还可以在 BigQuery 中使用 Overture Maps 数据,创建一个单独的表,其中包含与感兴趣区域对应的建筑物形状和一个名为 geom_vector 的矢量。本例中的感兴趣区域是美国弗吉尼亚州诺福克市,由 FIPS 代码 51710 表示,如以下代码示例所示:

CREATE TABLE geo-solution-demos.vector_search.norfolk_buildings
AS (
  SELECT
    *,
    [
      ST_X(ST_CENTROID(building.geometry)),
      ST_Y(ST_CENTROID(building.geometry))] AS geom_vector
  FROM geo-solution-demos.overture_maps.building AS building
  INNER JOIN bigquery-public-data.geo_us_boundaries.counties AS county
    ON (st_intersects(county.county_geom, building.geometry))
  WHERE county.county_fips_code = '51710'
)

以下代码示例展示了如何在表上创建矢量索引:

CREATE
  vector index building_vector_index
ON
  `geo-solution-demos.vector_search.norfolk_buildings`(geom_vector)
  OPTIONS (index_type = 'IVF')

以下查询会确定距离特定基准建筑物(表示为 anchor_building_id)最近的 10 座建筑物:

declare anchor_building_id STRING;

SET anchor_building_id = '08b2af6202ce5fff02007d1778948bc4';

SELECT base.*
FROM
  VECTOR_SEARCH(
    TABLE `geo-solution-demos.vector_search.norfolk_buildings`,
    'geom_vector',
    (
      SELECT
        geom_vector
      FROM
        `geo-solution-demos.vector_search.norfolk_buildings`
      WHERE id = anchor_building_id
    ),
    top_k => 10,
    distance_type => 'EUCLIDEAN',
    options => '{"fraction_lists_to_search":0.1}')

当您在 BigQuery Geo Viz 中查看地理空间数据时,输出将是一组最靠近锚定建筑物的建筑物形状,如下图所示:

BigQuery Geo Viz 中可视化地理空间数据。

在 Google Cloud 控制台中运行此查询时,点击作业信息,然后验证向量索引使用模式是否已设为 FULLY_USED。这表示该查询正在利用您之前创建的 building_vector_index 矢量索引。

拆分大型形状

最佳实践:使用 ST_SUBDIVIDE 函数划分大型形状。

使用 ST_SUBDIVIDE 函数可将大型形状或长线字符串拆分成较小的形状

后续步骤