在mapreduce中,每个reduce任务将其输出写入名为 part-r-nnnnn 的文件,其中 nnnnn 是与reduce任务关联的分区ID。 map / reduce 是否会合并这些文件?如果是,怎么样?
答案 0 :(得分:117)
您可以通过调用以下命令来委托reduce输出文件的整个合并,而不是自己合并文件:
hadoop fs -getmerge /output/dir/on/hdfs/ /desired/local/output/file.txt
注意这在本地组合了HDFS文件。确保在运行
之前有足够的磁盘空间答案 1 :(得分:27)
不,这些文件不会被Hadoop合并。您获得的文件数与reduce任务数相同。
如果你需要它作为下一个工作的输入,那么不要担心有单独的文件。只需将整个目录指定为下一个作业的输入。
如果确实需要群集外的数据,那么我通常会在从群集中提取数据时在接收端合并它们。
即。像这样的东西:
hadoop fs -cat /some/where/on/hdfs/job-output/part-r-* > TheCombinedResultOfTheJob.txt
答案 2 :(得分:8)
这是您可以用来合并HDFS文件的功能
public boolean getMergeInHdfs(String src, String dest) throws IllegalArgumentException, IOException {
FileSystem fs = FileSystem.get(config);
Path srcPath = new Path(src);
Path dstPath = new Path(dest);
// Check if the path already exists
if (!(fs.exists(srcPath))) {
logger.info("Path " + src + " does not exists!");
return false;
}
if (!(fs.exists(dstPath))) {
logger.info("Path " + dest + " does not exists!");
return false;
}
return FileUtil.copyMerge(fs, srcPath, fs, dstPath, false, config, null);
}
答案 3 :(得分:7)
仅对于文本文件和HDFS作为源和目标,请使用以下命令:
hadoop fs -cat /input_hdfs_dir/* | hadoop fs -put - /output_hdfs_file
这将连接input_hdfs_dir
中的所有文件,并将输出写回output_hdfs_file
的HDFS。请记住,所有数据都将被带回本地系统,然后再次上传到hdfs,尽管没有创建临时文件,而且使用UNIX pe即可实现这一点。
此外,这不适用于非文本文件,如Avro,ORC等。
对于二进制文件,您可以执行以下操作(如果您在目录上映射了Hive表):
insert overwrite table tbl select * from tbl
根据您的配置,这可能还会创建多个文件。要创建单个文件,请使用mapreduce.job.reduces=1
显式将reducers数设置为1,或将hive属性设置为hive.merge.mapredfiles=true
。
答案 4 :(得分:4)
part-r-nnnnn文件是在“r”指定的reduce阶段之后生成的。现在的事实是,如果你有一个减速器运行,你将有一个输出文件,如part-r-00000。如果减速器的数量是2,那么你将得到part-r-00000和part-r-00001,依此类推。看,如果输出文件太大而无法放入机器内存中,因为hadoop框架设计为在商品机器上运行,那么文件将被拆分。根据MRv1,您可以使用20个减速器来限制逻辑。您可能需要在配置文件 mapred-site.xml 中自定义更多但相同的需求。 谈论你的问题;您可以使用getmerge,也可以通过将以下语句嵌入到驱动程序代码中来将reducers的数量设置为1
job.setNumReduceTasks(1);
希望这能回答你的问题。
答案 5 :(得分:3)
您可以运行其他map / reduce任务,其中map和reduce不会更改数据,分区程序会将所有数据分配给单个reducer。
答案 6 :(得分:1)
除了我之前的回答,我还有一个答案,我几分钟前就试过了。 您可以使用 CustomOutputFormat ,它看起来像下面给出的代码
public class VictorOutputFormat extends FileOutputFormat<StudentKey,PassValue> {
@Override
public RecordWriter<StudentKey,PassValue> getRecordWriter(
TaskAttemptContext tac) throws IOException, InterruptedException {
//step 1: GET THE CURRENT PATH
Path currPath=FileOutputFormat.getOutputPath(tac);
//Create the full path
Path fullPath=new Path(currPath,"Aniruddha.txt");
//create the file in the file system
FileSystem fs=currPath.getFileSystem(tac.getConfiguration());
FSDataOutputStream fileOut=fs.create(fullPath,tac);
return new VictorRecordWriter(fileOut);
}
}
只是,看看最后一行的第四行。我使用自己的名字作为输出文件名,我用15个reducer测试了程序。文件仍然保持不变。因此,可以获得单个输出文件而不是两个或更多文件,但是非常清楚输出文件的大小不得超过主存储器的大小,即输出文件必须适合商品机器的内存,否则可能存在输出文件拆分出现问题。 谢谢!
答案 7 :(得分:0)
为什么不使用像这样的猪脚本来合并分区文件:
stuff = load "/path/to/dir/*"
store stuff into "/path/to/mergedir"
答案 8 :(得分:0)
如果文件有标题,你可以通过这样做摆脱它:
hadoop fs -cat /path/to/hdfs/job-output/part-* | grep -v "header" > output.csv
然后手动为output.csv
添加标题答案 9 :(得分:0)
。 map / reduce是否合并这些文件?
没有。它没有合并。
您可以使用IdentityReducer来实现目标。
不执行缩减,将所有输入值直接写入输出。
public void reduce(K key,
Iterator<V> values,
OutputCollector<K,V> output,
Reporter reporter)
throws IOException
将所有键和值直接写入输出。
查看相关的SE帖子: