使用Spark多次写入hadoop分布式文件系统

使用Spark多次写入hadoop分布式文件系统,hadoop,hdfs,apache-spark,partition,rdd,Hadoop,Hdfs,Apache Spark,Partition,Rdd,我创建了一个spark作业,每天从我的hdfs读取文本文件,并从文本文件的每一行提取唯一的键。每个文本文件中大约有50000个键。然后,相同的数据通过提取的密钥进行过滤并保存到hdfs 我想在我的hdfs中创建一个目录,其结构如下:hdfs://.../date/key 包含已筛选数据的。问题是写入hdfs需要非常长的时间,因为有太多的键 现在的写法是: val inputData = sparkContext.textFile(""hdfs://...", 2) val keys = extr

我创建了一个spark作业,每天从我的hdfs读取文本文件,并从文本文件的每一行提取唯一的键。每个文本文件中大约有50000个键。然后,相同的数据通过提取的密钥进行过滤并保存到hdfs

我想在我的hdfs中创建一个目录,其结构如下:hdfs://.../date/key 包含已筛选数据的。问题是写入hdfs需要非常长的时间,因为有太多的键

现在的写法是:

val inputData = sparkContext.textFile(""hdfs://...", 2)
val keys = extractKey(inputData) //keys is an array of approx 50000 unique strings
val cleanedData = cleanData(inputData) //cleaned data is an RDD of strings
keys.map(key => {
    val filteredData = cleanedData.filter(line => line.contains(key))
    filteredData.repartition(1).saveAsTextFile("hdfs://.../date/key")
})
有没有办法让这更快?我曾考虑过将数据重新划分为提取的密钥数,但之后无法保存为该格式hdfs://.../date/key. 我也尝试过groupByKey,但无法保存这些值,因为它们不是RDD

非常感谢您的帮助:)

def writeLines(迭代器:迭代器[(字符串,字符串)])={
val writers=new mutalbe.HashMap[String,BufferedWriter]/(key,writer)map
试一试{
while(iterator.hasNext){
val item=iterator.next()
val键=项目。\u 1
val行=项目。\u 2
val writer=writers.get(键)匹配{
案例部分(编写器)=>编写器
案例无=>
val路径=参数(1)+键
val outputStream=FileSystem.get(新配置()).create(新路径)
writer=新的BufferedWriter(outputStream)
}
writer.writeLine(行)
}最后{
writers.values.foreach(.\u close())
}
}
val inputData=sc.textFile()
val keyValue=inputData.map(行=>(键,行))
val partitions=keyValue.partitionBy(新的MyPartition(10))
分区。foreachPartition(写线)
类MyPartitioner(partitions:Int)扩展了Partitioner{
覆盖def numPartitions:Int=partitions
覆盖def getPartition(键:Any):Int={
//确保同一分区中具有相同键的行
(key.toString.hashCode和Integer.MAX_值)%numPartitions
}
}

我认为方法应该与类似。分区号与目录号无关。要实现它,您可能需要使用自定义版本覆盖generateFileNameForKeyValue以保存到不同的目录


关于可伸缩性,这不是spark的问题,而是hdfs的问题。但无论您如何实现,只要需求没有改变,这都是不可避免的。但我认为hdfs可能适合50000个文件处理程序。您只为输入指定了2个分区,为输出指定了1个分区。这样做的一个效果是服务器限制这些操作的并行性。为什么需要这些


与其计算50000个过滤过的RDD(速度也很慢),不如直接按键分组好吗?我知道您希望将它们输出到不同的目录中,但这确实造成了这里的瓶颈。是否有另一种方法来构建它,只让您读取(键、值)结果?

这个问题是重复的。我正在寻找一种解决方案,它使用saveAsTextFile而不是saveAsHadoopFile,并将它们保存到单独的目录中,而不是使用不同名称的不同文件。我已经实现了您链接到的解决方案。但我特别想知道是否有更快的方法来创建多个目录s、 另外,如果我有50000个密钥,并且我需要创建50000个分区来将每个密钥映射到,那么链接到的解决方案仍然很慢。嗯,在spark意义上,您不需要50000个分区(但在dir意义上是的)。由于打开了太多的文件句柄,该解决方案在密钥数量上可能无法很好地扩展。我想您可以将其设计为关闭并打开到某个限制。50000是很多目录,如果不稍微慢一点,就看不到任何方法可以做到这一点。