我有一个值列表作为一个数据源,第二个数据集包含与值绑定的范围。
Dataset 1:
3
4
6
20
25
38
Dataset 2:
1|3|A
4|10|B
11|20|C
21|30|D
31|31|E
32|38|F
39|40|G
Result:
3,A
4,B
6,B
20,C
25,D
38,F
我想创建某种类型的“JOIN”,将数据集1中的值与数据集2中的字符联系起来。
答案 0 :(得分:3)
主要问题是MapReduce连接的方式要求密钥完全匹配,并且它在paritioner中随机存储(默认情况下)。使用Java MapReduce可能有很多棘手的方法。我能想到的最简单的两个是下面的。不确定哪个更快......这取决于数据的性质。
使用交叉产品:
C = CROSS A, B;
D = FILTER C BY $1 >= $2 AND $1 <= $3;
这可能很慢!但它完成了工作!
炸掉范围,然后进行连接
B2 = FOREACH B GENERATE FLATTEN(explode_range_udf($1, $2, $3));
C = JOIN A by $1, B2 by $1;
这是你编写一个名为explode_range_udf
的udf的地方,它接受三个值并返回一包元组,其中包含范围中的每个可能元素。例如:
explode_range_udf(1,3,A) -> {(1,A),(2,A),(3,A)}
FLATTEN
根据包中的每个项目创建记录。
答案 1 :(得分:2)
如果Donald Miner的任何一个建议对你来说足够快,我就会这样做,但为了加快速度,如果DataSet 2只有250K-500K条目,那么你应该能够把整个东西放到内存中。因此,您可以:编写一个将DataSet 2存储到内存中的udf(有关如何将hdfs文件存储到DistributedCache中,请参阅getCacheFiles
。然后编写一个EvalFunc
,其中包含一个DataSet A项,二进制搜索它在DataSet 2中的位置,并返回您想要的答案。
ANSWER = FOREACH DATASET1 GENERATE myBinarySearchUdf(number)
as myResult:Tuple(originalNumber:int, dataSet2Id:chararray);