在Hive中生成唯一标识符

13

我一直在尝试为每个表格行生成唯一的id(30多亿行)。

  • 显然,使用顺序号码不起作用,因为Hadoop是并行的。
  • 内置的UDFs rand() 和 hash(rand(),unixtime()) 似乎会产生冲突。

必须有一种简单的方法来生成行id,我想知道是否有人有解决方案。

  • 我的下一步就是创建一个Java MapReduce任务,使用安全随机数+主机IP+当前时间作为种子来生成真正的哈希字符串。但在这之前,我想问问这里是否有解决方案 ;)

你考虑过使用UUIDs吗? - Mike Park
8个回答

22
使用反射 UDF 生成 UUID。
reflect("java.util.UUID", "randomUUID")

更新(2019)

长期以来,在 Hive 中获得唯一值的最佳选择是 UUID。从 Hive 4.0 开始,Hive 提供了一个 surrogate key UDF,您可以使用它来生成唯一值,这将比 UUID 字符串具有更高的性能。文档仍然有点简略,但这里有一个例子:

create table customer (
  id bigint default surrogate_key(),
  name string, 
  city string, 
  primary key (id) disable novalidate
);

如果想让Hive为您生成ID,请在插入语句中使用列列表,不要提及代理键列:

-- staging_table would have two string columns.
insert into customer (name, city) select * from staging_table;

这个函数在hiveserver2中被列入黑名单。是否有解决方法或者其他替代方法? - Vinay Kumar
根据反射UDF的文档,您可以编写自己的自定义UDF包装器来返回randomUUID的值。反射只是一个帮助程序,可以避免您在每次调用一些常见的Java方法时都需要这样做。@VinayKumar - tswann

8

不确定这是否有帮助,但让我们看看...

考虑本地MapReduce类比:假设您的输入数据集基于文本,那么对于每行,输入Mapper的键(因此唯一ID)将是文件名加上其字节偏移量。

当您将数据加载到Hive中时,如果可以创建一个额外的“列”来保存此信息,则可以免费获得行ID。它在语义上没有意义,但您提到的方法也是如此。


有人可以提供一个示例吗?我是一名.NET开发者,想要实现我的自定义映射函数。 - user145610

6

除了jtravaglini提供的答案,自从0.8.0版本以来,Hive内置了两个虚拟列可用于生成唯一标识符:

INPUT__FILE__NAME, BLOCK__OFFSET__INSIDE__FILE

使用如下:

select
concat(INPUT__FILE__NAME, ':', BLOCK__OFFSET__INSIDE__FILE) as rowkey,  
...  
;  
...  
OK  
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:0
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:57
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:114
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:171
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:228
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:285
hdfs://<nodename>:8020/user/dhdpadmn/training/training_data/nyse/daily/NYSE_daily2.txt:342  
...

或者你可以使用MD5或类似的方式进行匿名处理,这里是一个MD5 UDF的链接:https://gist.github.com/dataminelab/1050002
(请注意函数类名应为initcap 'Md5')

select
Md5(concat(INPUT__FILE__NAME, ':', BLOCK__OFFSET__INSIDE__FILE)) as rowkey,
...

2
注意:虚拟列使用双下划线:INPUT__FILE__NAME BLOCK__OFFSET__INSIDE__FILE - bcollins
1
注意!对于 Parquet 文件格式,上述解决方案返回了多个具有相同 row_id 的行,尽管数据是不同的。 - Gyanendra Dwivedi

3
使用ROW_NUMBER函数生成单调递增的整数ID。
select ROW_NUMBER() OVER () AS id from t1;

请查看这个链接,里面涉及到如何在IT技术中获取特定值的行号。

2

reflect("java.util.UUID", "randomUUID")

反射 "java.util.UUID" 类的 "randomUUID" 方法。

我不能投票支持其他答案。我需要一个纯二进制版本,所以我使用了以下代码:

unhex(regexp_replace(reflect('java.util.UUID','randomUUID'), '-', ''))


1
如果您想使用多个映射器并处理大型数据集,请尝试使用此UDF:https://github.com/manojkumarvohra/hive-hilo
它利用zookeeper作为中央存储库来维护序列状态和生成唯一递增的数字值。

1
编写一个自定义 Mapper,为每个 Map 任务保留计数器,并为行创建行 ID,该行 ID 是 JobID()(从 MR API 获取)和计数器当前值的串联。在检查下一行之前,增加计数器的值。

1
根据工作性质和运行频率的不同,使用连续编号可能是一个合理的替代方案。您可以按照this other SO question中描述的方式实现一个rank() UDF。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接