在mapreduce中,每个化简任务将其输出写入名为part-r-nnnnn的文件,其中nnnnn是与化简任务关联的分区ID。难道的map / reduce合并这些文件?如果是,怎么办?
Answers:
您可以通过调用以下方法来委托reduce输出文件的整个合并,而不必自己进行文件合并:
hadoop fs -getmerge /output/dir/on/hdfs/ /desired/local/output/file.txt
注意这将在本地合并HDFS文件。在运行之前,请确保您有足够的磁盘空间
getMerge
对文件进行简单的串联,使用SequenceFile之类的文件将不会给出合理的输出。
不,Hadoop无法合并这些文件。您获得的文件数量与减少任务的数量相同。
如果您需要将其作为下一份工作的输入,则不必担心会有单独的文件。只需将整个目录指定为下一个作业的输入即可。
如果您确实需要集群外部的数据,那么通常在从集群中提取数据时在接收端将它们合并。
即是这样的:
hadoop fs -cat /some/where/on/hdfs/job-output/part-r-* > TheCombinedResultOfTheJob.txt
这就是您可以用来在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);
}
对于仅文本文件,HDFS作为源文件和目标文件,请使用以下命令:
hadoop fs -cat /input_hdfs_dir/* | hadoop fs -put - /output_hdfs_file
这将串联所有文件,input_hdfs_dir
并将输出写回到HDFS output_hdfs_file
。请记住,尽管没有创建任何临时文件,但所有数据都将被带回到本地系统,然后再次上传到hdfs,这是使用UNIX pe进行的。
此外,这不适用于非文本文件,例如Avro,ORC等。
对于二进制文件,您可以执行以下操作(如果目录中映射了Hive表):
insert overwrite table tbl select * from tbl
根据您的配置,这还可能创建多个文件。要创建单个文件,请使用明确将reducer的数量设置为1mapreduce.job.reduces=1
或将hive属性设置为hive.merge.mapredfiles=true
。
part-r-nnnnn文件是在两者之间由“ r”指定的还原阶段之后生成的。现在的事实是,如果您运行一个减速器,您将有一个输出文件,例如part-r-00000。如果减速器的数量为2,那么您将拥有part-r-00000和part-r-00001,依此类推。看一下,如果hadoop框架已设计为可在Commodity Machines上运行,则输出文件太大而无法放入机器内存中,则该文件将被拆分。根据MRv1,逻辑上只能使用20个减速器。您可能有更多但需要在配置文件mapred-site.xml中自定义的内容。谈论你的问题;您可以使用getmerge或通过将以下语句嵌入驱动程序代码来将reducer的数量设置为1
job.setNumReduceTasks(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测试了该程序。文件仍然保持不变。因此,可以很清楚地得到一个输出文件而不是两个或更多文件,但输出文件的大小一定不能超过主内存的大小,即输出文件必须适合商用机器的内存,否则可能输出文件拆分出现问题。谢谢!!
。映射/缩小合并这些文件吗?
不。它不会合并。
您可以使用IdentityReducer实现您的目标。
不执行归约,将所有输入值直接写入输出。
public void reduce(K key,
Iterator<V> values,
OutputCollector<K,V> output,
Reporter reporter)
throws IOException
直接将所有键和值写入输出。
看一下相关的SE帖子: