如何在查询结果中添加整数唯一 id - __efficiently__?

Posted

技术标签:

【中文标题】如何在查询结果中添加整数唯一 id - __efficiently__?【英文标题】:How to add an integer unique id to query results - __efficiently__? 【发布时间】:2017-03-23 11:19:19 【问题描述】:

给定一个查询,select * from ...(可能是 CTAS 语句的一部分)

目标是添加一个额外的列ID,其中ID 是一个唯一整数。

select ... as ID,* from ...

附言

ID 不必是连续的(可能存在间隙) ID 可以是任意的(不必表示结果集中的特定顺序)

row_number逻辑上解决了问题-

select row_number() over () as ID,* from ...

问题是,至少目前,全局row_number(没有partition by)是使用单个reducer(hive)/task(spark)实现的。

【问题讨论】:

从 Hive 2.2 开始,您可以生成 UUID 而不是序列 - issues.apache.org/jira/browse/HIVE-12721 而且由于 Hive UUID 函数只是调用 java.util.UUID.randomUUID().toString() 你应该能够在任何 Hive 版本中使用 reflect 做类似的事情 > github.com/apache/hive/blob/master/ql/src/java/org/apache/… 去过那里,做到了:-)。 UUID 是 36 个字节。 INT 的 4 个或 BIGINT 的 8 个。您在存储和您执行的任何操作中为它付费 - WHERE、GROUP BY、JOIN、ORDER BY 等。 36 个字节为 STRING,但只有 16 个字节为 BINARY(尽管转换为 Hive BINARY 需要 UDF)。你已经得到了你所支付的,即对于一个非常大的数据集,32 位随机值的“单一性”是值得怀疑的。与穷人 CRC32 与繁琐的加密 MD5 或 SHA1 一样的困境...... 【参考方案1】:

蜂巢

set mapred.reduce.tasks=1000;
set hivevar:buckets=10000;

hivevar:buckets 相对于 reducer 的数量 (mapred.reduce.tasks) 应该足够高,因此行将在 reducer 之间均匀分布。


select  1 + x + (row_number() over (partition by x) - 1) * $hivevar:buckets  as id
       ,t.*

from   (select  t.*
               ,abs(hash(rand())) % $hivevar:buckets as x      

        from    t
        ) t

spark-sql

select  1 + x + (row_number() over (partition by x) - 1) * 10000  as id
       ,t.*

from   (select  t.*
               ,abs(hash(rand())) % 10000 as x      

        from    t
        ) t

适用于 hive 和 spark-sql

rand() 用于生成良好的分布。 如果您的查询中已经有一个具有良好分布的列/列组合(可能是唯一的,不是必须的),您可以改用它,例如-

select    1 + (abs(hash(col1,col)) % 10000) 
        + (row_number() over (partition by abs(hash(col1,col)) % 10000) - 1) * 10000  as id
       ,t.*

from    t

【讨论】:

旁注:为什么要散列一个随机值?由于散列是确定性的,这不会改变碰撞的概率...... 如果您有已知分布良好的列,您可以使用它,但要注意使用可能会出现偏差的值。【参考方案2】:

如果您使用的是 Spark-sql,最好的办法是使用内置函数

monotonically_increasing_id

在单独的列中生成唯一的随机 id。 正如您所说,您不需要它是连续的,因此理想情况下这应该足以满足您的要求。

【讨论】:

【参考方案3】:

查看 Manoj Kumar 的解决方案:https://github.com/manojkumarvohra/hive-hilo

创建了一个有状态的 UDF,它维护一个 HI/LO 计数器 增加序列。 HI 值在 zookeeper 中保持为分布式原子长。 HI 值每 n 个 LO 递增并获取(默认为 200) 迭代。 UDF 支持单个字符串参数,即序列名称 用于维护 zookeeper 中的 zNode。

用法:

FunctionName( sequenceName, lowvalue[optional], seedvalue[optional])

【讨论】:

【参考方案4】:

查看这个全球唯一 ID 服务https://github.com/spinaki/distributed-unique-id 它也有一个 docker 镜像,你可以快速测试。

【讨论】:

以上是关于如何在查询结果中添加整数唯一 id - __efficiently__?的主要内容,如果未能解决你的问题,请参考以下文章

将 _id 从 ObjectId 更改为正常的唯一自动增量整数

Mongoose 在结果的 _id 字段中返回“new ObjectId”

查询数据库获取第一个唯一值

Mongoose.js 除了 _id & __v 默认来自查询结果

Mongoose.js 除了 _id & __v 默认来自查询结果

求助啊,tp下,mongodb如何查询后只返回某个字段值