【问题标题】:How to Catch ST_MAKEPOLYGON Error in BigQuery如何在 BigQuery 中捕获 ST_MAKEPOLYGON 错误
【发布时间】:2019-01-25 08:00:59
【问题描述】:

我在 BigQuery 中使用 ST_MAKEPOLYGON 函数如下:

  with data AS (
  SELECT
    61680 AS id, 139.74862575531006 AS lon,
    35.674973127377314 AS lat union all
  SELECT
    61680,
    139.75087881088257,
    35.673909836018375 union all
  SELECT
    61680,
    139.747037887573,
    35.6765767531247 union all
  SELECT
    61680,
    139.75308895111,
    35.6813525780394 union all
  SELECT
    61680,
    139.747509956359,
    35.6798884869144 union all
  SELECT
    61680,
    139.754590988159,
    35.6799930657428 union all
  SELECT
    61680,
    139.754977226257,
    35.6762281415729 union all
  SELECT
    61680,
    139.750170707702,
    35.6815268728124 union all
  SELECT
    61680,
    139.755363464355,
    35.6782500673754
    )
SELECT
  ST_makepolygon(ST_MAKELINE(ARRAY_AGG(st_geogpoint(lon,
          lat)))) AS valid
FROM
  `w_nagakawa.geo_test`
GROUP BY
  id

我得到如下错误:

Error: ST_MakePolygon failed: Invalid polygon loop: Edge 3 has duplicate vertex with edge 10

ST_MAKEPOLYGON 中的地理参数没问题,而且所有经纬度似乎都不一样。

我想知道它为什么会发生,并想知道一些解决这个问题的想法。

谢谢。

【问题讨论】:

  • 您能否提供错误声明并阐明“捕获此错误”的确切含义
  • 错误:ST_MakePolygon 失败:多边形循环无效:边 3 与边 10 有重复的顶点
  • 我的意思是产生该错误的多边形示例,并解释“捕获此错误”的确切含义

标签: google-bigquery gis postgis


【解决方案1】:

第一个问题先……

我想知道为什么会这样……

将 ST_MAKEPOLYGON 与线串输入一起使用(通过 ST_MAKELINE)需要正确组装线,这样您的数据就不会发生交叉(因为线是使用 [随机] 出现顺序中的点构建的)

相反,您需要像下面 blue 中的线 - 所有地理点都经过排序以形成非自交叉线

注意:线串必须闭合:即第一个和最后一个顶点必须相同。如果第一个和最后一个顶点不同,则该函数构造从第一个顶点到最后一个顶点的最终边。

使用“proper_line”构建多边形将完美地工作并产生以下结果

现在第二个问题……

…想知道解决这个问题的一些想法

因此,显然,我们需要以某种方式正确排序地理点
这可以手动完成(玩这个选项很有趣)或可以通过编程完成
以下是如何在 BigQuery(标准 SQL)中执行此操作的想法以及实施细节

因此,我们希望通过以下步骤为每个点分配适当的序列号:

第 1 步 – 让我们确定所有点(红色 针脚)的质心(下图中的绿色针脚)

我们可以使用以下语句:

SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`

第 2 步 - 然后,对于每个点,我们应该计算质心到点的线与穿过质心的水平线之间的角度
我们正在使用锚点(图像上的蓝色圆圈)

WITH stats AS (
  SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`
)
SELECT point, centroid, anchor,
  ACOS(ST_DISTANCE(centroid, anchor) / ST_DISTANCE(centroid, point)) angle
FROM (
  SELECT centroid, 
    ST_GEOGPOINT(lon, lat) point, 
    ST_GEOGPOINT(lon, ST_Y(centroid)) anchor
  FROM `data`, stats
)

第 3 步 - 现在我们要将这些角度转换为反映各个点象限的正确序列

SELECT point, centroid, anchor,
  CASE 
    WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) > ST_Y(centroid) THEN 3.14 - angle
    WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 3.14 + angle
    WHEN ST_X(point) < ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 6.28 - angle
    ELSE angle
  END sequence
FROM (.. previous subquery here …)

第 4 步 - 现在,我们终于可以使用序列列对点进行正确排序了 下面的最终查询:

WITH `data` AS (
    SELECT 61680 AS id, 139.74862575531006 AS lon, 35.674973127377314 AS lat UNION ALL SELECT 61680, 139.75087881088257, 35.673909836018375 UNION ALL SELECT 61680, 139.747037887573, 35.6765767531247 UNION ALL SELECT 61680, 139.75308895111, 35.6813525780394 UNION ALL SELECT 61680, 139.747509956359, 35.6798884869144 UNION ALL SELECT 61680, 139.754590988159, 35.6799930657428 UNION ALL SELECT 61680, 139.754977226257, 35.6762281415729 UNION ALL SELECT 61680, 139.750170707702, 35.6815268728124 UNION ALL SELECT 61680, 139.755363464355, 35.6782500673754
), stats AS (
  SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`
) 
SELECT ST_MAKEPOLYGON(ST_MAKELINE(ARRAY_AGG(point ORDER BY sequence))) AS polygon
FROM (
  SELECT point, 
    CASE 
      WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) > ST_Y(centroid) THEN 3.14 - angle
      WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 3.14 + angle
      WHEN ST_X(point) < ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 6.28 - angle
      ELSE angle
    END sequence
  FROM (
    SELECT point, centroid, 
      ACOS(ST_DISTANCE(centroid, anchor) / ST_DISTANCE(centroid, point)) angle
    FROM (
      SELECT centroid, 
        ST_GEOGPOINT(lon, lat) point, 
        ST_GEOGPOINT(lon, ST_Y(centroid)) anchor
      FROM `data`, stats
    )
  )
)

最终结果是:

注意:这个想法/解决方案 - 仍然可以仅限于像你这样的一些明显案例 - 我没有机会探索和/或测试它的通用案例

【讨论】:

  • 很好的解释!谢谢你。我希望 BigQuery 为第 3 步提供 st_angle 函数...
  • 嗨,米哈伊尔,这是一篇精彩的文章,感谢您以如此有用的方式分享您的深厚知识。我想知道如何在同一张地图上绘制多边形的质心和多边形本身。顺便说一句,您使用的可视化工具非常好,我能得到它吗?
  • @ronencozen - 这是 Goliath - BigQuery 的 IDE - Potens.io Suite 的一部分,可在 Marketplace 获取。该套件中的另一个工具是 Magnus - Workflow Automator。支持所有 BigQuery、Cloud Storage 和大多数 Google API 以及多个简单的实用程序类型任务,如 BigQuery 任务、导出到存储任务、循环任务等等,以及高级调度、触发等。试试吧!披露:我是这些工具的创造者和 Potens 团队的领导者。 (以及 BigQuery Mate)
【解决方案2】:

您的多边形格式错误(可能点的顺序错误)。我试图用你提供的点和顺序来可视化多边形,它显示了一个边缘网格。因此,我以对多边形有意义的方式对点进行了排序。之后,查询工作。我测试的顺序如下(它们是相同的点,只是以不同的方式排序):

 with data AS (
  SELECT
    61680 AS id, 139.75087881088257 AS lon,
    35.673909836018375 AS lat union all
  SELECT
    61680,
    139.74862575531006,
    35.674973127377314 union all
  SELECT
    61680,
    139.747037887573,
    35.6765767531247 union all
  SELECT
    61680,
    139.747509956359,
    35.6798884869144 union all
  SELECT
    61680,
    139.750170707702,
    35.6815268728124 union all
  SELECT
    61680,
    139.75308895111,
    35.6813525780394 union all
  SELECT
    61680,
    139.754590988159,
    35.6799930657428 union all
  SELECT
    61680,
    139.755363464355,
    35.6782500673754 union all
  SELECT
    61680,
    139.754977226257,
    35.6762281415729
    )
SELECT
  ST_makepolygon(ST_MAKELINE(ARRAY_AGG(st_geogpoint(lon,
          lat)))) AS valid
FROM
  data
GROUP BY
  id

这是因为 BigQuery 在加载或生成多边形之前对其进行验证。

【讨论】:

  • 请注意,SQL 或 BigQuery 不保证 UNION ALL 运算符中的行顺序,因此可能会发生变化。最好只用显式 ARRAY 点替换 ARRAY_AGG,或者使用 ARRAY_AGG(... ORDER BY) 来保证聚合顺序
【解决方案3】:

以下是 BigQuery 标准 SQL

感谢了不起的 BigQuery 团队,引入了 ST_CONVEXHULL,解决此类问题变得超级简单

#standardSQL
WITH `data` AS (SELECT 61680 AS id, 139.74862575531006 AS lon, 35.674973127377314 AS lat UNION ALL SELECT 61680, 139.75087881088257, 35.673909836018375 UNION ALL SELECT 61680, 139.747037887573, 35.6765767531247 UNION ALL SELECT 61680, 139.75308895111, 35.6813525780394 UNION ALL SELECT 61680, 139.747509956359, 35.6798884869144 UNION ALL SELECT 61680, 139.754590988159, 35.6799930657428 UNION ALL SELECT 61680, 139.754977226257, 35.6762281415729 UNION ALL SELECT 61680, 139.750170707702, 35.6815268728124 UNION ALL SELECT 61680, 139.755363464355, 35.6782500673754)
SELECT ST_CONVEXHULL(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) AS valid
FROM `data`

结果如下所示

【讨论】:

    猜你喜欢
    • 2014-06-14
    • 2018-12-08
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-11-08
    • 2010-11-21
    • 2019-03-27
    • 2012-02-11
    相关资源
    最近更新 更多