我有一个csv文件列表,每个文件都有一堆类别名称作为标题列。每行都是具有布尔值(0,1)的用户列表,无论它们是否属于该类别。每个csv文件都没有相同的标题类别集。
我想在所有具有以下输出的文件中创建复合csv:
我想解决这个问题的方法是为每个单元格创建一个user_id的元组和一个唯一的category_id,其值为'1'。然后为每个用户减少所有这些列以获得最终输出。
如何创建元组开头?我可以对所有类别进行全局查找吗?
示例数据:
File 1
user_id,cat1,cat2,cat3
21321,,,1,
21322,1,1,1,
21323,1,,,
文件2
user_id,cat4,cat5
21321,1,,,
21323,,1,,
输出
user_id,cat1,cat2,cat3,cat4,cat5
21321,,1,1,,,
21322,1,1,1,,,
21323,1,1,,,,
答案 0 :(得分:0)
问题的标题可能具有误导性,因为它传达了某种实现选择,因为不需要全局查找来解决手头的问题。
在大数据中,指导大多数解决方案的基本原则是:分而治之。在这种情况下,输入的CSV文件可以分为(用户,类别)元组。 包含任意数量类别的任意数量的CSV文件都可以转换为这种简单格式。生成的CSV结果是上一步的并集,提取了所有类别的nr,以及一些数据转换,以获得所需的格式。
在代码中,此算法如下所示:
import org.apache.spark.SparkContext._
val file1 = """user_id,cat1,cat2,cat3|21321,,,1|21322,1,1,1|21323,1,,""".split("\\|")
val file2 = """user_id,cat4,cat5|21321,1,|21323,,1""".split("\\|")
val csv1 = sparkContext.parallelize(file1)
val csv2 = sparkContext.parallelize(file2)
import org.apache.spark.rdd.RDD
def toTuples(csv:RDD[String]):RDD[(String, String)] = {
val headerLine = csv.first
val header = headerLine.split(",")
val data = csv.filter(_ != headerLine).map(line => line.split(","))
data.flatMap{elem =>
val merged = elem.zip(header)
val id = elem.head
merged.tail.collect{case (v,cat) if v == "1" => (id, cat)}
}
}
val data1 = toTuples(csv1)
val data2 = toTuples(csv2)
val union = data1.union(data2)
val categories = union.map{case (id, cat) => cat}.distinct.collect.sorted //sorted category names
val categoriesByUser = union.groupByKey.mapValues(v=>v.toSet)
val numericCategoriesByUser = categoriesByUser.mapValues{catSet => categories.map(cat=> if (catSet(cat)) "1" else "")}
val asCsv = numericCategoriesByUser.collect.map{case (id, cats)=> id + "," + cats.mkString(",")}
结果:
21321,,,1,1,
21322,1,1,1,,
21323,1,,,,1
(生成标题很简单,留给读者练习)
答案 1 :(得分:-1)
如果您需要的只是结果值,则不需要将此作为两步过程。 可能的设计: 1 /解析你的csv。你没有提到你的数据是否在分布式FS上,所以我认为不是。 2 /将(K,V)对输入可变并行化(利用Spark)映射。 伪代码:
val directory = ..
mutable.ParHashMap map = new mutable.ParHashMap()
while (files[i] != null)
{
val file = directory.spark.textFile("/myfile...")
val cols = file.map(_.split(","))
map.put(col[0], col[i++])
}
然后你可以通过地图上的迭代器访问你的(K / V)元组。