MapReduce实战:查找相同字母组成的单词
1、项目需求
一本英文书籍包含成千上万个单词,现在我们需要在大量的单词中,找出相同字母组成的所有单词
2、数据集
下面是一本英文书籍截取的一部分单词内容(书籍内容是随意写的,主要目的是实现这种需求)

3、分析
1、先看如下图

在上图中,cat、act是相同字母组成的单词,tar、rat也是相同字母组成的单词,bar只有一个,它不显示,因为没有和它是相同字母组成单词
2、基于以上分析,我们通过以下几步完成
1、在Map阶段,对每个word(单词)按字母进行排序生成sortedWord,然后输出key/value键值对(sortedWord,word)。
2、在Reduce阶段,统计出每组相同字母组成的所有单词
3、示意流程
1、以下面几个单词为例,找出相同字母组成的单词。
cat
tar
bar
act
rat
2、经过map阶段处理后,如下
key value
act cat
art tar
abr bar
act act
art rat
在这一阶段中,对每个单词按字母进行排序生成sortedWord,并将其作为key,然后输出key/value键值对(sortedWord,word):
3、经过框架处理后,如下(这一步框架自动帮我们实现)
act,[act, cat]
art,[cat, rat]
abr,[bar]
在一阶段,根据key(sortedWord)进行分组
4、经过reduce阶段处理,如下
key value
act act,cat
art rat,tar
在一阶段,拼接一组中的所有单词,然后输出;需要说明一点,(abr,[bar])这个被过滤掉了,因为这一组中就它一个
4、实现
上面已经分析完毕,下面我们就着手实现它。这里需要编写三块代码内容:
1、map 函数、
2、reduce函数
3、一些用来运行作业的代码。
1、map 函数
下面我们来编写 Mapper 类,实现 map() 函数
/* * 排序、分组 */
public static class AnagramMapper extends Mapper<LongWritable, Text, Text, Text>{ public void map(LongWritable key, Text value,Context context) throws IOException , InterruptedException { // 将Text转换成String String text = value.toString(); // 将String转换成字符数组,为排序作准备 char[] textCharArr = text.toCharArray(); // 使用 Arrays对数组进行排序 Arrays.sort(textCharArr); // 排序后的字符串 String sortedText = new String(textCharArr); context.write(new Text(sortedText), value); }
}
这个 Mapper 类是一个泛型类型,它有四个形参类型,分别指定 map 函数的输入键、输入值、输出键和输出值的类型。 就本示例来说,输入键是一个长整数偏移量(LongWritable),输入值是一行文本(Text), 其次输出键、输出值也是文本类型(Text)的。
map() 方法的输入是一个键(key)和一个值(value),我们首先将 Text 类型的 value 转换成 Java 的 String 类型, 之后将其转换成字符数组,通过Arrays.sort方法对该字符数组进行排序,然后将排序后的单词作为key,源单词作为value输出。map() 方法还提供了 Context 实例用于将输出内容进行写入。 在这种情况下,我们将key、value封装成Text对象,并将它们进行写入。
2、reduce函数
下面我们来编写 Reducer类,实现reduce函数
/*
* 统计相同字母组成的单词
*/
public static class AnagramReduce extends Reducer<Text, Text, Text, Text>{
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
// 值
StringBuilder value = new StringBuilder();
// 计数
int count = 0;
// 拼接单词
for(Text text : values){
// 分割符,
if(value.length() > 0){
value.append(",");
}
value.append(text);
// 计数
count++;
}
// 因为我们要统计相同字母组成的单词,所以相同字母组成的单词个数大于等于2才会输出
if(count > 1){
context.write(key, new Text(value.toString()));
}
}
}
同样,reduce 函数也有四个形式参数类型用于指定输入和输出类型。reduce 函数的输入类型必须匹配 map 函数的输出类型:即 Text 类型和Text类型。 在这种情况下,reduce 函数的输出类型也是 Text 和 Text 类型。在 map 的输出结果中,所有相同key的键值对被分配到同一个reduce执行,通过迭代来拼接所有单词,并将一组中只有一个单词的过滤掉
3、一些用来运行作业的代码
public int run(String[] arg0) throws Exception {
// 加载配置
Configuration conf = new Configuration();
// 输出目录,如果存在就删除
Path path = new Path(arg0[1]);
FileSystem fileSystem = path.getFileSystem(conf);
if(fileSystem.isDirectory(path)){
fileSystem.delete(path, true);
}
// 创建job对象
Job job = new Job(conf,"anagram");
job.setJarByClass(Anagram.class);
// 指定输入、输出目录
FileInputFormat.addInputPath(job, new Path(arg0[0]));
FileOutputFormat.setOutputPath(job, new Path(arg0[1]));
// 指定mapper、reduce
job.setMapperClass(AnagramMapper.class);
job.setReducerClass(AnagramReduce.class);
// 指定mapper、reduce的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
// 提交作业
return job.waitForCompletion(true) ? 0: 1;
}
public static void main(String[] args) throws Exception {
String[] arg0 = {
"hdfs://ljc:9000/buaa/anagram",
"hdfs://ljc:9000/buaa/anagram/out"
};
// 执行mapperreduce
int status = ToolRunner.run(new Configuration(), new Anagram(), arg0);
System.exit(status);
}
Configuration 类读取 Hadoop 的配置文件,如 site-core.xml、mapred-site.xml、hdfs-site.xml 等。
Job 对象指定作业执行规范,我们可以用它来控制整个作业的运行。我们在 Hadoop 集群上运行这个作业时,要把代码打包成一个JAR文件(Hadoop在集群上发布这个文件)。 不必明确指定 JAR 文件的名称,在 Job 对象的 setJarByClass 方法中传递一个类即可,Hadoop 利用这个类来查找包含它的 JAR 文件,进而找到相关的 JAR 文件;构造 Job 对象之后,需要指定输入和输出数据的路径
以下特别说明:
1、调用 FileInputFormat 类的静态方法 addInputPath() 来定义输入数据的路径,这个路径可以是单个的文件、一个目录(此时,将目录下所有文件当作输入)或符合特定文件模式的一系列文件。由函数名可知,可以多次调用 addInputPath() 来实现多路径的输入。
2、调用 FileOutputFormat 类中的静态方法 setOutputPath() 来指定输出路径(只能有一个输出路径)。这个方法指定的是 reduce 函数输出文件的写入目录。 在运行作业前该目录是不应该存在的,否则 Hadoop 会报错并拒绝运行作业。这种预防措施的目的是防止数据丢失(长时间运行的作业如果结果被意外覆盖,肯定是件可怕的事情)。
3、通过 setMapperClass() 和 setReducerClass() 指定 map 类型和reduce 类型。
4、通过setOutputKeyClass() 和 setOutputValueClass() 控制 map 和 reduce 函数的输出类型,正如本例所示,这两个输出类型一般都是相同的。如果不同,则通过 setMapOutputKeyClass()和setMapOutputValueClass()来设置 map 函数的输出类型。
5、输入的类型通过 InputFormat 类来控制,我们的例子中没有设置,因为使用的是默认的 TextInputFormat(文本输入格式)。
6、Job 中的 waitForCompletion() 方法提交作业并等待执行完成。该方法中的布尔参数是个详细标识,所以作业会把进度写到控制台。 waitForCompletion() 方法返回一个布尔值,表示执行的成(true)败(false),这个布尔值被转换成程序的退出代码 0 或者 1。
5、结果

6、其他问题
3、代码及数据
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【刘超★ljc】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
MapReduce实战:查找相同字母组成的单词的更多相关文章
- MapReduce实战项目:查找相同字母组成的字谜
实战项目:查找相同字母组成的字谜 项目需求:一本英文书籍中包含有成千上万个单词或者短语,现在我们要从中找出相同字母组成的所有单词. 数据集和期望结果举例: 思路分析: 1)在Map阶段,对每个word ...
- hadoop实战项目:查找相同字母组成的字谜
前面我们学习了MapReduce编程思想和编程示例,那么本节课程同学们一起操练操练,动手完成下面的项目. 项目需求 一本英文书籍包含成千上万个单词或者短语,现在我们需要在大量的单词中,找出相同字母组成 ...
- 【原创】python倒排索引之查找包含某主题或单词的文件
什么是倒排索引? 倒排索引(英语:Inverted index),也常被称为反向索引.置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射.它是文 ...
- [No00003E]26个字母暗藏的单词秘密
个字母暗藏的单词秘密 人们普通认为:英语是拼音文字,因而与象形无关.但是,实际上,即使作为拼音文字,其字母的来源也与象形有关.根据笔者十多年的研究结果,英语中的二十六个字母每个字母都有其象形意义,而且 ...
- 三道习题(1、将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别。 #输入格式:按字典序由小到大输入若干个单词,每个单词占一行,以end结束输入。)
#coding=gbk ''' 1.将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别. #输入格式:按字典序由小到大输入若干 ...
- 《OD大数据实战》MapReduce实战
一.github使用手册 1. 我也用github(2)——关联本地工程到github 2. Git错误non-fast-forward后的冲突解决 3. Git中从远程的分支获取最新的版本到本地 4 ...
- MapReduce实战:统计不同工作年限的薪资水平
1.薪资数据集 我们要写一个薪资统计程序,统计数据来自于互联网招聘hadoop岗位的招聘网站,这些数据是按照记录方式存储的,因此非常适合使用 MapReduce 程序来统计. 2.数据格式 我们使用的 ...
- mapreduce实战:统计美国各个气象站30年来的平均气温项目分析
气象数据集 我们要写一个气象数据挖掘的程序.气象数据是通过分布在美国各地区的很多气象传感器每隔一小时进行收集,这些数据是半结构化数据且是按照记录方式存储的,因此非常适合使用 MapReduce 程序来 ...
- MapReduce实战--倒排索引
本文地址:http://www.cnblogs.com/archimedes/p/mapreduce-inverted-index.html,转载请注明源地址. 1.倒排索引简介 倒排索引(Inver ...
随机推荐
- Spring MVC源码分析(续)——请求处理
转自:http://blog.csdn.net/shi1122/article/details/8041017 (转移位置了,时光隧道:http://www.jmatrix.org/spring/50 ...
- Contest20140711 loop 数论
loop|loop.in|loop.out 题目描述: 有N个点. 现在重复这样的操作: 随机找一个出度为0的点p1,随机找一个入度为0的点p2,连一条有向边从p1指向p2.直到没有出度为0的点. 统 ...
- Nodejs 集成到IIS
http://www.hanselman.com/blog/WebMatrixAndNodejsTheEasiestWayToGetStartedWithNodeOnWindows.aspx http ...
- 当今流行的 React.js 适用于怎样的 Web App?
外村 和仁(株式会社 ピクセルグリッド) React.js是什么? React.js是Facebook开发的框架. http://facebook.github.io/react/ 官网上的描述是「 ...
- ckeditor与ckfinder简单整合使用
Ckeditor与ckfinder简单整合使用 功能:主要用来发送图文的email,图片上传到本地服务器,但是email的图片地址要写上该服务器的远程地址(图片地址:例如:http://www.bai ...
- windows提权操作以及系统开机关机重启代码(用到了LookupPrivilegeValue和AdjustTokenPrivileges调整进程的Token权限)
对于UAC提权操作,一般在编译期间,如果程序有需求要提权,会在编译器里设置,vs2010比较简单,在工程属性里可以直接设置,vs2005稍微有点儿麻烦,参考这篇文章: http://www.seany ...
- git cherry-pick 从其他分支检出指定的commit到当前分支
http://think-like-a-git.net/sections/rebase-from-the-ground-up/cherry-picking-explained.html Git's o ...
- Android MonkeyRunner自动拨打电话
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice import time device = MonkeyRunner.wa ...
- haproxy实现mysql slave负载均衡
简单画一个图: 一.服务器规划 192.168.116.132 (master) -->写操作 192.168.116.129 (slave1) -->读操作 192.168.116. ...
- unity3d Realistic eye shading 真实的眼睛渲染
先放上效果 人皮都做了,当然要来研究下眼睛,眼睛要比人体皮肤简单一些(实时模拟人皮在此) 一看是不是很复杂 这是眼睛的解构,但是,我们只需要模拟出虹膜巩膜和角膜就能达到相当真实的眼睛 巩膜就是白眼球 ...