我有两个包含时间信息的RDD。 RDD分为不同的分区。 一个是
形式16:00:00
16:00:18
16:00:25
16:01:01
16:01:34
16:02:12
16:02:42
...
另一个包含tuple2形式的时间跨度
<16:00:00, 16:00:59>
<16:01:00, 16:01:59>
<16:02:00, 16:02:59>
...
我需要聚合第一个和第二个RDD,通过根据第二个中的值聚合第一个RDD的值,以获得类似
的内容<<16:00:00, 16:00:59>, [16:00:00,16:00:18,16:00:25]>
<<16:01:00, 16:01:59>, [16:01:01,16:01:34]>
<<16:02:00, 16:02:59>, [16:02:12,16:02:42]>
...
或者,或者,像
这样的东西<<16:00:00, 16:00:59>, 16:00:00>
<<16:00:00, 16:00:59>, 16:00:18>
<<16:00:00, 16:00:59>, 16:00:25>
<<16:01:00, 16:01:59>, 16:01:01>
<<16:01:00, 16:01:59>, 16:01:34>
<<16:02:00, 16:02:59>, 16:02:12>
<<16:02:00, 16:02:59>, 16:02:42>
...
我试图使用整个范围的火花转换函数,但我很难找到一个适用于这种不同性质的RDD的函数。我知道我可能会选择cartesian
产品,然后进行过滤,但我会更喜欢&#34;更好的&#34;解。我尝试了zipPartition
,这可能有用,但我可能在分区中存在不一致,例如16:00:00
可能最终位于不存在相应聚合值(元组<16:00:00, 16:00:59>
)的分区中。
哪种方法可以解决这个问题?
PS:我使用的是Java,但也欢迎使用Scala解决方案。 感谢
答案 0 :(得分:1)
我已经简化了以下内容以使用整数,但我相信同样可以做到这一点。虽然示例是在Scala中,但我怀疑它也可以用Java完成。
如果范围是常规的,我会转动&#34;值&#34;将RDD转换为range,value
,然后进行简单的连接。
val values = Seq(1, 5, 10, 14, 20)
val valuesRdd = sc.parallelize(values, 2)
valuesRdd.map(x => (((x/10)*10, ((x/10)*10)+9), x)).collect
但是如果范围不规则那么:
如果您不介意使用DataFrames,那么可以选择使用用户定义函数根据给定范围内的V in创建列并加入。< / p>
case class Range(low : Int, high :Int)
val ranges = Seq( Range(0,9), Range(10,19), Range(20,29));
val rangesDf = sc.parallelize(ranges, 2).toDF
case class Value(value : Int)
val values = Seq(Value(1), Value(5), Value(10), Value(14), Value(20))
val valuesDf = sc.parallelize(values, 2).toDF
val inRange = udf{(v: Int, low: Int, high : Int) => v >= low && v<= high}
rangesDf.join(valuesDf, inRange(valuesDf("value"), rangesDf("low"), rangesDf("high"))).show
下一个选项是爆炸输出范围并加入爆炸版本:
val explodedRange = rangesRdd.map(x => (x, List.range(x._1, x._2 + 1))).flatMap( { case (range, lst) => lst.map { x => (x, range)} })
val valuesRdd = sc.parallelize(values, 2).map(x => (x,true))
valuesRdd.join(explodedRange).map(x => (x._2._2, x._1)).collect