BigQuery - 在数组内部生成时重复的随机数

Posted

技术标签:

【中文标题】BigQuery - 在数组内部生成时重复的随机数【英文标题】:BigQuery - Random numbers repeating when generated inside arrays 【发布时间】:2020-12-03 00:37:24 【问题描述】:

我做了一个 BigQuery 查询,其中涉及为每一行生成一个随机数数组。我使用随机数来决定要从源表中存在的数组中包含哪些元素。

我很难让随机数数组在每一行上都不重复。我找到了一种解决方法,但这是预期的行为吗?我将在下面发布两种“方法”(一种效果理想,一种效果不佳)。请注意,如果您不使用数组,这两种方法都可以正常工作,而只是生成一个随机数。

方法 1(不良结果):

SELECT
    (
        SELECT
            ARRAY(
                SELECT AS STRUCT
                    RAND() AS random
                FROM UNNEST(GENERATE_ARRAY(0, 10, 1)) AS _time
            ) AS random_for_times
    )
FROM UNNEST(GENERATE_ARRAY(0, 10, 1))

方法二(效果不错):

SELECT
    (
        SELECT
            ARRAY(
                SELECT AS STRUCT
                    RAND() AS random
                FROM UNNEST(GENERATE_ARRAY(0, 10, 1)) AS _time
            ) AS random_for_times
        FROM (SELECT NULL FROM UNNEST([0]))
    )
FROM UNNEST(GENERATE_ARRAY(0, 10, 1))

示例结果 - 方法 1(不良):

Row 1
0.5431173080158003
0.5585452983410205
...
Row 2   
0.5431173080158003
0.5585452983410205
...

示例结果 - 方法 2(良好):

Row 1
0.49639706531271377
0.1604380522058521
...
Row 2   
0.7971869432989377
0.9815667330115473
...

编辑:在 Yun Zhang 关于子查询的理论之后,请参阅下面的一些类似的替代示例。您的解决方案对我发布的问题很有用,但请注意,在某些情况下我仍然觉得莫名其妙。另外,尽管我同意您可能对与问题相关的子查询是正确的:子查询(尤其是没有 FROM 子句的子查询)不应该更少可能会重复使用其结果而不是选择“正常”值?人们有时会谈论子查询的性能问题,因为它们应该为每一行计算一次,即使结果可能相同。

您是否同意这似乎是一个错误?

下面的例子表明,即使创建一个随机数组也不一定是问题——即使执行一个恰好有一个不相关数组的子选择也会导致 RAND() 出现问题。通过消除子选择、仅从子选择中选择随机值或在数组中包含一个随行变化的值,问题就消失了。奇怪!!!

不好

SELECT
    (SELECT AS STRUCT RAND() AS r, ARRAY(SELECT 1) AS a)
FROM UNNEST(GENERATE_ARRAY(0, 5, 1)) AS u

修复 #1 - 没有子选择

SELECT
    STRUCT(RAND() AS r, ARRAY(SELECT 1) AS a)
FROM UNNEST(GENERATE_ARRAY(0, 5, 1)) AS u

FIX #2 - 仅选择 r

SELECT
    (SELECT AS STRUCT RAND() AS r, ARRAY(SELECT 1) AS a).r
FROM UNNEST(GENERATE_ARRAY(0, 5, 1)) AS u

修复 #3 - 数组包含“u”

SELECT
    (SELECT AS STRUCT RAND() AS r, ARRAY(SELECT u) AS a).r
FROM UNNEST(GENERATE_ARRAY(0, 5, 1)) AS u

【问题讨论】:

【参考方案1】:

不明白为什么第一个查询不起作用,但我有一个更简单的版本适合你:

SELECT (
          SELECT array_agg(RAND()) AS random
          FROM UNNEST(GENERATE_ARRAY(0, 10, 1)) AS _time
       ) AS random_for_times
FROM UNNEST(GENERATE_ARRAY(0, 10, 1))

更新:我后来意识到问题出在ARRAY(subquery),只要你能避免在你的情况下使用它(就像我上面的查询一样),你应该没问题。

【讨论】:

感谢@Yun Zhang。我在上面发布了一些额外的细节作为编辑。我认为您对子查询的看法可能是正确的,但我发现了一些新的有趣案例,如上所述。 我同意你的观点,你提出的新案例很奇怪(或者更正式地说,不一致)。

以上是关于BigQuery - 在数组内部生成时重复的随机数的主要内容,如果未能解决你的问题,请参考以下文章

在画布中随机生成对象,不重复或重叠

值列表的 BigQUery 重复日期数组

生成不重复的随机数

在 Bigquery 中使用结构数组删除重复项并选择不同的值

不重复随机数列生成算法

JS生成不重复的随机数组的简单实例