bigquery的farm_fingerprint不是随机分布的吗?

时间:2017-12-04 09:59:30

标签: google-bigquery

当我获取有序集的散列(即数字用户ID)时,它们的MD5散列的结果分布大致均匀分布:即。如果我将散列分成n个分位数,则低编号的用户ID(10001)同样可能在散列的分位数中找到高编号的用户ID(99999)。另一方面,如果我使用farm_fingerprint执行此操作,则生成的哈希桶似乎不会均匀分布:低编号桶具有更多低编号的用户ID。 documentation没有立即提及哈希的分布属性,我无法在其他参考文献中找到它。

我意识到统一分配用户ID的更好方法是为每个用户ID分配一个随机数,如上所述here;我的问题是关于所提到的FARM_FINGERPRINT哈希的分布属性。

下面是一个示例查询,说明了分位数的相对偏差:

    SELECT
      avg(n_low) as avg_n_low,
      avg(n_med) as avg_n_med,
      avg(n_high) as avg_n_high
    FROM (
      SELECT bucket_id,
        SUM(CASE WHEN label = 'low' THEN 1 ELSE 0 END) as n_low,
        SUM(CASE WHEN label = 'med' THEN 1 ELSE 0 END) as n_med,
        SUM(CASE WHEN label = 'high' THEN 1 ELSE 0 END) as n_high
      FROM (
        SELECT
          x,
          label,
          ntile(1000) OVER (ORDER by h) as bucket_id 
        FROM (
          SELECT x,
          CASE
            WHEN x BETWEEN 00001 and 20000 THEN 'low' 
            WHEN x BETWEEN 20001 and 40000 THEN 'med'
            WHEN x BETWEEN 40001 and 60000 THEN 'high' 
          END as label,
          --FARM_FINGERPRINT(CAST(x AS STRING)) h
          MD5(CAST(x AS STRING)) h
          FROM UNNEST((SELECT GENERATE_ARRAY(1,60000,10) xs)) AS x
        )
      )
      GROUP BY 1
    )
    WHERE
      bucket_id < 100
      --bucket_id > 900

我有2000&#39;低&#39;,&#39; med&#39;和&#39;高&#39;用户分为100个桶。可以看出,使用FARM_FINGERPRINT产生的桶平均值的方差高于MD5,即。对于桶,FARM_FINGERPRINT似乎有更高的avg_n_low&lt; 100比MD5和更高的avg_n_high用于桶> 900.即。通过散列分配给存储桶的分布不像MD5那样统一。

我知道这在某种程度上是主观的,如果我遗漏了某些内容或者可以提供更多细节,请告诉我。

2 个答案:

答案 0 :(得分:1)

您能帮助我们重现这个问题吗?

我看到一个非常规律​​的分布 - 至少在执行指纹结果的AVG(ABS())时:

SELECT CEIL(x/10000000000), AVG(ABS(h)), COUNT(*)
FROM (
  SELECT x, FARM_FINGERPRINT(CAST(x AS STRING)) h
  FROM UNNEST((SELECT GENERATE_ARRAY(1,100000000000,100000) xs)) AS x
)
GROUP BY 1 
ORDER BY 2

enter image description here

与问题的范围相同:

SELECT CEIL(x/10000), AVG(ABS(h)), COUNT(*)
FROM (
  SELECT x, FARM_FINGERPRINT(CAST(x AS STRING)) h
  FROM UNNEST((SELECT GENERATE_ARRAY(10001,100000) xs)) AS x
)
GROUP BY 1 
ORDER BY 2

enter image description here

答案 1 :(得分:0)

指纹函数与密码哈希函数不在同一类中。他们没有试图产生接近随机/不可预测的输出。换句话说,值是否可逆并不重要。指纹功能的要求是为每个唯一输入简单地产生确定性的唯一哈希值(避免冲突)。 由于要求较为简单,因此它们应比加密哈希更快,并且对于生成大量数据的代理密钥(特别是在MMP平台上)非常有用。请注意,如果您的自然键包含敏感数据,则可能不希望使用farm_fingerprint。 如果您真的需要生成一个序列,尤其是一个密集排列的序列,则可以使用序列表(我必须这样做才能将ID馈送到只能使用32位整数的下游系统)。 通用示例(请注意,这是配置单元sql,bigquery分析函数可能有所不同):

create table entity_seq_xref
(  natural_key string
  ,sequence_id integer
);
insert into entity_seq_xref
select natural_key
    ,coalesce(last_sequence_id,0) + row_number() over (partition by 1) as sequence_id
from (select s.natural_key
            ,x.sequence_id
            ,max(x.sequence_id) over (partition by 1) as last_sequence_id
      from source_entity s
      left join entity_seq_xref x
          on x.natural_key = s.natural_key
) m
where x.sequence_id is null
;