我正在hadoop集群上构建字典,需要为每个令牌生成 numeric id。我该怎么办?
答案 0 :(得分:2)
你有两个问题。首先,您要确保为每个令牌分配一个id。为此,您应该按令牌对记录进行排序和分组,并在reducer中进行分配。一旦确定每个令牌只调用一次reducer方法,就可以使用上下文中的分区号和reducer维护的唯一数字id(每个分区一个实例) - 只需使用初始化为1的实例变量在setup方法中,并在reduce方法中递增。
答案 1 :(得分:0)
为避免同步,排序和分组不属于您的业务逻辑,您可以使用一些技巧,这会更快。
最简单的方法是在Reducer中生成UUID,每个键UUID UUID.randomUUID()一个,但这些不是数字。
如果你想要连续的数字id序列并且输出足够小以便一个reducer处理,那么通过org.apache.hadoop.mapreduce.Job.setNumReduceTasks(int tasks)强制一个reducer用于作业,因此所有的键将被定向到一个Reducer。
如果Mapper的输出对于单个Reducer来说仍然太大而你不关心id的序列连续性或你的字典可以被分区,那么你可以使用分区器的一些技巧(see )。我们的想法是,您可以将密钥逻辑分区为已知长度的N个范围(例如,范围1可以有1密钥,以1开头,范围4可以有500个以3500000开头的ID等)。逻辑:
如果您对范围没有任何业务知识,您可以花一些时间在键上做一个明确的并计算范围和长度。有了这个,你可以在结果集中得到连续的id序列。
如果您不想花时间做不同的键,那么目标是为每个具有不同数字的Reducer启动ID(Reducer 1生成仅以1(1,10,124523,1341243)开头的ID,Reducer 2与2(2,23,234234532)等)。 为此,计算密钥的第一个字节的mod 10,并强制10个Reducers,直接零到1的相同分区(主要原因是没有2个数字的整数以0开头,它可能导致与id冲突从其他分区),因此分区0的输出为空。比在reducer端添加(连接2个字符串!!!)计数器到(键mod 10的第一个字节),其中0变为1.每个reducer都有一个从1到无穷大的计数器,可以从a初始化包含用于该分区的最后一个ID的文件。
实施例。
key = "abc", ascii of 'a' is 97, 97 % 10 = 7 and id for that key is '7' + '1' = '71',
for "asd" it will be '7' + '244' = '7244',
for "bbv" is '8' + '1' = '81',
for "bgh" is '8' + '2' = '82',
for "ddv", 'd' is ascii 100, 100 % 100 = 0 , convert to 1, '1' + '1' = '11',
for "edv" is 101 % 100 = 1, '1' + '2234' = '12234'.
因为所有键都以不同的数字开头,所以它们从不重叠,因此不需要在多个Reducers之间进行同步。它通过mod结果和计数器的字符串连接来保证,因此不会溢出到下一个前缀/前导数字。 另一个优点是您不需要执行任何预分类,这不是您业务逻辑的一部分。 当Reducer关闭时,它可以将id生成中使用的最后一个计数器写入文件,该计数器可以在下一次运行中使用,并通过字典的分区提供id的连续性。
要将分区数从10增加到100,请使用mod 100并将单个数字结果合并为2位数(再次我们浪费10个减速器的输出)。 Ex 10%100 = 10,1%100 = 1转换为10,102%100 = 2转换为20,将'0'添加为字符串或乘以10.目标是让所有前缀具有相同的位数,在这种情况下2。
使用聪明的逻辑,我们可以避免浪费跳过的分区(在mod 100的情况下为0或1,2,9。)
警告:此逻辑容易受到数据偏斜的影响。
我希望它有所帮助, 欢呼声。
答案 2 :(得分:0)
我们使用的另一个选项是为任务分配ID块,为此您需要一种机制来管理事务。我们使用AWS的 SimpleDB 来跟踪已使用或未使用过的交易和ID。
在作业开始时,我们将整个ID块锁定在Simple DB上(只有一个属性更改为“已锁定”),然后每个任务调用简单数据库来“检出”它使用的ID块
如果任务失败,它永远不会“解锁”该块,并且永远不会更新上次使用的ID,因此失败的任务不会消耗这些ID。最后,当我们解锁整个ID块时,我们解锁任何失败的任务。
我们将通过从简单数据库导入/导出ID块来改进此过程,因此我们不必更新外部资源。相反,我们可以从与数据一起存储的文件中读取可用的ID,将它们写入简单的数据库,使用简单的DB来协调将块分配给各个任务(映射器,缩减器),然后将它们写回成功的结果。 / p>
一旦我们做出改进,我们可能会公开提供代码,所以如果有人对这种方法感兴趣,请随时与我联系,如果我们完成了,我会用代码更新这篇文章