我将在更大的文件中执行以下操作。现在,我有一个带有以下值的示例输入文件。
1000,SMITH,JERRY
1001,JOHN,TIA
1002,TWAIN,MARK
1003,HARDY,DENNIS
1004,CHILD,JACK
1005,CHILD,NORTON
1006,DAVIS,JENNY
1007,DAVIS,KAREN
1008,MIKE,JOHN
1009,DENNIS,SHERIN
现在我正在做的是运行mapreduce作业来加密每个记录的姓氏并写回输出。我使用映射器分区号作为键,修改后的文本作为值。
所以mapper的输出将是,
0 1000,Mj4oJyk=,,JERRY
0 1001,KzwpPQ,TIA
0 1002,NSQgOi8,MARK
0 1003,KTIzNzg,DENNIS
0 1004,IjsoPyU,JACK
0 1005,IjsoPyU,NORTON
0 1006,JTI3OjI,JENNY
0 1007,JTI3OjI,KAREN
0 1008,LDoqNg,JOHN
0 1009,JTYvPSgg,SHERIN
我不想要进行任何排序。我也使用reducer,因为如果文件较大,会有多个映射器,如果没有reducer,则会写入多个输出文件。所以我使用单个reduce来合并来自所有映射器的值并写入单个文件。 现在,reducer的输入值按照相反的顺序和mapper的顺序排列。它就像以下一样,
1009,JTYvPSgg,SHERIN
1008,LDoqNg==,JOHN
1007,JTI3OjI=,KAREN
1006,JTI3OjI=,JENNY
1005,IjsoPyU=,NORTON
1004,IjsoPyU=,JACK
1003,KTIzNzg=,DENNIS
1002,NSQgOi8=,MARK
1001,KzwpPQ==,TIA
1000,Mj4oJyk=,JERRY
为什么要撤销订单?以及如何从mapper维护相同的顺序?任何建议都会有所帮助
编辑1:
驱动程序代码是,
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJobName("encrypt");
job.setJarByClass(TestDriver.class);
job.setMapperClass(TestMap.class);
job.setNumReduceTasks(1);
job.setReducerClass(TestReduce.class);
job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(hdfsInputPath));
FileOutputFormat.setOutputPath(job, new Path(hdfsOutputPath));
System.exit(job.waitForCompletion(true) ? 0 : 1);
映射器代码是,
inputValues = value.toString().split(",");
stringBuilder = new StringBuilder();
TaskID taskId = context.getTaskAttemptID().getTaskID();
int partition = taskId.getId();
// the mask(inputvalue) method is called to encrypt input values and write to stringbuilder in appropriate format
mask(inputvalues);
context.write(new IntWritable(partition), new Text(stringBuilder.toString()));
reducer代码是,
for(Text value : values) {
context.write(new Text(value), null);
}
答案 0 :(得分:0)
MapReduce的基本思想是完成任务的顺序无关紧要。 所以你不能(也不需要)控制
的顺序唯一可以控制的是值在减速器中可用的迭代器中的顺序。
为此,您可以使用Object key
来维护值的顺序。
LongWritable部分(或键)是文件中行的位置(不是行号,而是文件开头的位置)。
您可以使用该部分来跟踪第一行。
然后您的映射器代码将更改为
protected void map(Object key, Text value, Mapper<Object, Text, LongWritable, Text>.Context context)
throws IOException, InterruptedException {
inputValues = value.toString().split(",");
stringBuilder = new StringBuilder();
mask(inputValues);
// the mask(inputvalue) method is called to encrypt input values and write to stringbuilder in appropriate format
context.write(new LongWritable(((LongWritable) key).get()), value);
}
注意:您可以在代码中将所有IntWritable
更改为LongWritable
,但要小心。
答案 1 :(得分:0)
inputValues = value.toString().split(",");
stringBuilder = new StringBuilder();
TaskID taskId = context.getTaskAttemptID().getTaskID();
//preserve the number value for sorting
IntWritable idNumber = new IntWritable(Integer.parseInt(inputValue[0])
// the mask(inputvalue) method is called to encrypt input values and write to stringbuilder in appropriate format
mask(inputvalues);
context.write(idNumber, new Text(stringBuilder.toString()));
我做了一些假设,因为你没有mapper的完整代码。由于inputValues
输出,我假设toString()
是一个字符串数组。数组的第一个值应该是输入的数值,但现在它是一个字符串。您必须将该号码转换回IntWritable
以匹配您的映射器发出的IntWritable,Text
。 hadoop框架将按密钥排序,密钥类型为IntWritable
,它将按升序排序。您提供的代码是使用任务ID和阅读API https://hadoop.apache.org/docs/r2.4.1/api/org/apache/hadoop/mapred/TaskAttemptID.html#getTaskID()目前还不清楚这是否会根据您的需要为您的值提供订单。要控制输出的顺序,我建议使用字符串数组的第一个值并转换为IntWritable。我不知道这是否违反了你掩盖inputValues
的意图。
修改的
跟进您的评论。您可以简单地将partition
乘以-1
,这将导致hadoop框架颠倒顺序。
int partition = -1*taskId.getId();