一、背景
一本英文书籍包含成千上万个单词或者短语,现在我们需要在大量的单词中,找出相同字母组成的所有anagrams(字谜)。
二、数据
部分数据展示
三、思路分析
1、在 Map 阶段,对每个word(单词)按字母进行排序生成sortedWord,然后输出key/value键值对(sortedWord,word)。
2、在 Reduce 阶段,统计出每组相同字母组成的所有anagrams(字谜)。
四、代码实现
1.在 Map 阶段,对每个word(单词)按字母进行排序生成sortedWord,然后输出key/value键值对(sortedWord,word)。
public static class AnagramMapper extends Mapper< Object, Text, Text, Text>
{
//定义两个输出对象
private Text sortedText = new Text();
private Text originalText = new Text();
public void map(Object key,Text value,Context context) throws IOException, InterruptedException
{
String word = value.toString();
//单词转化成数组
char[] wordChar = word.toCharArray();
//对字符数组按字母排序
Arrays.sort(wordChar);
//字符数组转化为字符串
String sortedWord = new String(wordChar);
//设置输出key和输出value
sortedText.set(sortedWord);
originalText.set(word);
//输出map
context.write(sortedText, originalText);
}
}
2.在 Reduce 阶段,统计出每组相同字母组成的所有anagrams(字谜)。
public static class AnagramReducer extends Reducer<Text,Text,Text,Text>
{
//定义两个输出对象
private Text outputValue = new Text();
private Text outputKey = new Text();
public void reduce(Text anagramKey,Iterable <Text> anagramValues,Context context) throws IOException, InterruptedException
{
String output = "";
//对相同字母组成的单词,使用~拼接
for(Text i : anagramValues)
{
if(!output.equals(""))
{
output = output + "~";
}
output = output + i.toString();
}
StringTokenizer outputTokenizer = new StringTokenizer(output,"~");
//输出大于2的结果
if(outputTokenizer.countTokens()>=2)
{
output = output.replace("~", ",");
//设置key值
outputKey.set(anagramKey.toString());
//设置value值
outputValue.set(output);
//输出reduce
context.write(outputKey, outputValue);
}
}
}
3.主代码,run()函数
public class Anagram extends Configured implements Tool
{
public static void main(String[] args) throws Exception
{
String[] args0 = {
"hdfs://pc1:9000/home/hadoop/anagram/anagram.txt",
"hdfs://pc1:9000/home/hadoop/anagram/out/"
};
int end = ToolRunner.run(new Configuration(),new Anagram(),args0);
System.exit(end);
}
public int run(String[] args) throws IOException, ClassNotFoundException, InterruptedException
{
//读取配置文件
Configuration conf = new Configuration();
//定义输出路径的对象mypath
Path mypath = new Path(args[1]);
//读取hdfs文件系统
FileSystem hdfs = mypath.getFileSystem(conf);
//如果输出路径存在删除它
if(hdfs.isDirectory(mypath))
{
hdfs.delete(mypath);
}
//构建新的job对象
Job job = new Job(conf,"testAnagram");
//设置主类
job.setJarByClass(Anagram.class);
//Mapper
job.setMapperClass(AnagramMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
//Reducer
job.setReducerClass(AnagramReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
//输入路径和输出路径
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//提交任务
return job.waitForCompletion(true)?0:1;
}
}
4.在myeclipse上运行程序
5.将项目编译和打包为anagram.jar,使用客户端将 anagram.jar上传至hadoop的/home/hadoop/app/hadoop目录下。
将/home/hadoop/anagram/out目录移除
[hadoop@pc1 hadoop]$ bin/hdfs dfs -rm /home/hadoop/anagram/out
6.通过命令行执行程序
[hadoop@pc1 hadoop]$ bin/hadoop jar Anagram.jar com.pc1.hadoop.work.Anagram home/hadoop/anagram.txt home/hadoop/anagram/out/
7.查看结果
[hadoop@pc1 hadoop]$ bin/hdfs dfs -ls /home/hadoop/anagram/out/
[hadoop@pc1 hadoop]$ bin/hdfs dfs -cat /home/hadoop/anagram/out/part-r-00000
部分结果