我有大量的文件夹(10.000个文件夹),其中包含.gz文件,并尝试按文件夹执行某些操作,例如:将每个文件分成较小的部分。
为此,我决定:
foldersRDD.foreach(folderName =>
....
sc.textFile(folderName)
....
它在本地工作但在集群上导致NullPointerException(我想,每个执行器节点的SparkContext都为null,我们根本不能在节点的函数代码中使用它)。
我如何以确保 1-folder-per-single-worker 执行模式的方式重做此示例或以其他方式避免/最小化任何繁重的操作,如洗牌?
答案 0 :(得分:1)
您可以将解决方案与命令wholeTextFiles()
完全结合使用。这只是一个技巧,但它可能对你有用。
根据official spark documentation,命令wholeTextFiles()
允许您读取包含多个小文本文件的目录,并将每个文件作为filename/content
对返回。这与textFile()
形成对比,后者将在每个文件中每行返回一条记录。
您可以从原始文件夹路径数组开始创建一组键/值 RDD-s,每个RDD-s代表{{1}中整个文件夹的名称和内容数据格式。
考虑以下开始场景:
filename/content
假设您有一个数组的字符串,其中包含每个文件夹的名称
Folder 1 (location > hdfs:\\Folder1)
- File01 (location > hdfs:\\Folder1\File01) > Hello this is the content of file 01
- File02 (location > hdfs:\\Folder1\File02) > Hello this is the content of file 02
Folder 2 (location > hdfs:\\Folder1)
- File03 (location > hdfs:\\Folder2\File03) > Hello this is the content of file 03
- File04 (location > hdfs:\\Folder2\File04) > Hello this is the content of file 04
下一步是为每个文件夹创建一个RDD。每个RDD将以DirArray[0]: "hdfs:\\Folder1"
DirArray[1]: "hdfs:\\Folder2"
格式表示整个文件名列表及其内容。为此,您可以遍历 path 数组并为每个元素调用命令filename/content
。它将包含以下内容:
wholeTextFiles()
每个结果RDD看起来如下所示:
For each element in DirArray > wholeTextFiles("hdfs:\\FolderN")
此时,将有两种选择:
a)将每个RDD存储在类似数组的结构中,稍后计算其元素
b)计算每个RDD生成时的元素(在前面中为每个部分)。
重要的是要注意,这种方法仅建议用于一组小文件,主要是因为新创建的RDD-s的每一行都包含它所代表的文件的全部内容。
答案 1 :(得分:0)
在您的示例中,foreach
中的代码被序列化并转移给工作者。你是对的,他们没有sparkContext。
我的建议:使用foldersList
而不是RDD,并祈祷您的RDD是在数据所在的同一工作人员上创建的。在理想的情况下,你有小文件(在许多节点上没有被hdfs划分)并且每个工作者都有足够的内存 - 就没有改组。在实际案例中,yarn会降低您的成本 - 这是他的工作,而不是您的工作。
P.S。可能会有一些技巧和其他更有经验的人可以更好地回答你。我只是建议信任hadoop magic引擎盖,并花时间在算法的实际实现上。祝你好运!