如何从 NESTED 字段中的 ARRAY 中删除 STRUCT

Posted

技术标签:

【中文标题】如何从 NESTED 字段中的 ARRAY 中删除 STRUCT【英文标题】:How to delete a STRUCT from an ARRAY in the NESTED field 【发布时间】:2020-12-24 13:13:16 【问题描述】:

有没有一种简单的方法可以从 BigQuery 中的嵌套重复字段中删除一个 STRUCT(BQ 表列类型:RECORD,模式:REPEATED)。

假设我有以下表格:

    愿望清单
name    toy.id  toy.priority
Alice   1       high
        2       medium
        3       low
Kazik   3       high
        1       medium
    玩具
id  name    available
1   car     0
2   doll    1
3   bike    1

我想从愿望清单中删除不可用的玩具 (toys.available==0)。在这种情况下,它是 toy.id==1。

因此,愿望清单将如下所示:

name    toy.id  toy.priority
Alice   2       medium
        3       low
Kazik   3       high

我知道如何选择它:

WITH `project.dataset.wishlist` AS
(
  SELECT 'Alice' name, [STRUCT<id INT64, priority STRING>(1, 'high'), (2, 'medium'), (3, 'low')] toy UNION ALL
  SELECT 'Kazik' name, [STRUCT<id INT64, priority STRING>(3, 'high'), (1, 'medium')]
), toys AS (
  SELECT 1 id, 'car' name, 0 available UNION ALL
  SELECT 2 id, 'doll' name, 1 available UNION ALL
  SELECT 3 id, 'bike' name, 1 available
)
SELECT wl.name, ARRAY_AGG(STRUCT(unnested_toy.id, unnested_toy.priority)) as toy
FROM `project.dataset.wishlist` wl, UNNEST (toy) as unnested_toy
LEFT JOIN toys t ON unnested_toy.id=t.id
WHERE t.available != 0
GROUP BY name

但是当 Toys.available==0 时,我不知道如何从愿望清单中删除结构

有非常相似的问题,例如How to delete/update nested data in bigquery 或How to Delete rows from Structure in bigquery,但在删除方面我不清楚答案,或者建议使用选择语句将整个愿望清单复制到新表中。我的“愿望清单”很大,“toys.availabililty”经常变化。复制在我看来效率很低。

您能否建议一个符合 BQ 最佳实践的解决方案?

谢谢!

【问题讨论】:

BigQuery 在处理频繁更改的数据时效率不高。它主要是为仅附加的数据表设计的。也许更合适的是 Bigtable。 问题中的查询完全符合您的要求 - 这里有什么问题?请澄清!!如果您的意思是物理删除源表中的这些结构 - 那么如果下次从愿望清单玩具中删除的内容将变得可用怎么办?!无论如何 - 请澄清你到底想要完成什么 @MikhailBerlyant 请不要过多地保留数据。知道如何删除某些结构会对我有很大帮助。这是因为在wishlist 的真实场景中,我有基于不同 ML 模型的预测。结构包含对样本所属的预测组/描述(位于toys 列表中)的引用。但是某些模型在某些条件下会刷新,因此某些 ID 的分配是无效的。因此,应事先从结构中删除某些 Id。它们是不正确的,会减慢查询速度,并且碳足迹非零 :) 谢谢 谢谢@SergeyGeron。我担心这将是结论,因为它确实是 BQ 设计原则之一。但是由于BQ中实现了行删除,我认为行内的STRUCT删除也是可能的。 【参考方案1】:

...由于在BQ中实现了行删除,我认为行内的STRUCT删除也是可能的。

您可以为此使用 UPDATE DML(不是 DELETE,因为它用于删除整行,而 UPDATE 可用于修改行)

update `project.dataset.wishlist` wl
set toy = ((
  select array_agg(struct(unnested_toy.id, unnested_toy.priority)) 
  from unnest(toy) as unnested_toy
  left join `project.dataset.toys` t on unnested_toy.id=t.id
  where t.available != 0
))
where true;   

【讨论】:

我想这就是我一直在寻找的答案,但请让我明天验证一下。谢谢! 当然。不急:o)【参考方案2】:

您可以UNNEST() 并重新聚合:

SELECT wl.name, 
       (SELECT ARRAY_AGG(t)
        FROM UNNEST(wl.toy) t JOIN
             toys
             ON toys.id = t.id
        WHERE toys.available <> 0
       ) as available_toys
FROM `project.dataset.wishlist` wl;

【讨论】:

感谢 Gordon,但这不是删除操作。在我的场景中,我想删除一些 STRUCT,因为在某些时候它们可能会出错。如果删除不可行,对我来说最合乎逻辑的解决方案可能是使用修改后的 STRUCTS 数组更新这些行。你怎么看? @Lukiz 。 . .我不明白你的评论。这不是“删除”任何东西。它正在返回一个新结果集,结果中只有可用的玩具。 是的,这是真的。但请阅读标题和问题本身。

以上是关于如何从 NESTED 字段中的 ARRAY 中删除 STRUCT的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch:如何修改 nested 字段的值

Elasticsearch:如何修改 nested 字段的值

ElasticSearh更新nested字段(Array数组)。怎么根据查询条件(query)复制一个(index)到新的Index how to update by query a nes

如何从 PHP 中的数组中删除重复值

从 Greenplum 中的 JSON 中删除 NULL 字段

如何从codeigniter中的foreach中删除键值?