如何在使用wholeTextFiles()加载的同一RDD中的两个文件上执行连接

时间:2017-07-22 16:18:12

标签: scala apache-spark rdd

我对spark-scala相当新,所以请不要介意这是否是一个初学者问题。

我有一个目录测试,其中包含两个文件input1.txt和input2.txt。 现在,假设我使用

创建一个名为inputRDD的RDD
val inputRDD = sc.wholeTextFiles("/home/hduser/test")

将两个文件都包含在RDD(inputRDD)对中。

根据我的理解,inputRDD包含文件名作为键,内容作为值 像这样的东西

(input1.txt,contents of input1.txt)
(input2.txt,contents of input2.txt)

现在,假设我必须基于第一列以这种方式(在同一个RDD中)对这两个文件执行连接。

contents of input1.txt
----------------------
1 a
1 b
2 c
2 d

contents of input2.txt
----------------------
1 e
2 f
3 g

我该怎么做?

2 个答案:

答案 0 :(得分:0)

您需要首先拆分内容,然后执行reduceByKey格式化您的加入。如下所示:

val outputRDD = inputRDD.mapPartitions(iter => {
  iter.map(path_content => {
    // split string content
    val splittedStr = path_content._2.split(" ")
    // outputs (1, a) (1, b) (2, c)
    (splittedStr(0), splittedStr(1)) 
  })
}).reduceByKey(_ + _) // this outputs (1, abe)

答案 1 :(得分:0)

如果test目录中只有两个文件,并且文件名已知,那么您可以将两个文件的文本分成两个rdds并使用join,如下所示

val rdd1 = inputRDD.filter(tuple => tuple._1.contains("input1.txt"))
  .flatMap(tuple => tuple._2.split("\n"))
  .map(line => line.split(" "))
  .map(array => (array(0), array(1)))

val rdd2 = inputRDD.filter(tuple => tuple._1.contains("input2.txt"))
  .flatMap(tuple => tuple._2.split("\n"))
  .map(line => line.split(" "))
  .map(array => (array(0), array(1)))


rdd1.join(rdd2).foreach(println)

您应该输出

(2,(c,f))
(2,(d,f))
(1,(a,e))
(1,(b,e))

我希望这是你想要的

<强>更新

如果test目录中有两个名称未知的文件,则可以避免使用wholeTextFile api并使用textFile api将其作为单独的rdds和{{ 1}}他们如上所述。但为此你必须编写一个列出文件的函数。

join