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() 函数

  1. /*
  2.  
  3. * 排序、分组
  4.  
  5. */
  6. public static class AnagramMapper extends Mapper<LongWritable, Text, Text, Text>{
  7.  
  8. public void map(LongWritable key, Text value,Context context) throws IOException , InterruptedException {
  9.  
  10. // 将Text转换成String
  11.  
  12. String text = value.toString();
  13.  
  14. // 将String转换成字符数组,为排序作准备
  15.  
  16. char[] textCharArr = text.toCharArray();
  17.  
  18. // 使用 Arrays对数组进行排序
  19.  
  20. Arrays.sort(textCharArr);
  21.  
  22. // 排序后的字符串
  23.  
  24. String sortedText = new String(textCharArr);
  25.  
  26. context.write(new Text(sortedText), value);
  27.  
  28. }
  29. }

这个 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函数

  1. /*
  2.  
  3. * 统计相同字母组成的单词
  4.  
  5. */
  6.  
  7. public static class AnagramReduce extends Reducer<Text, Text, Text, Text>{
  8.  
  9. public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
  10.  
  11. // 值
  12.  
  13. StringBuilder value = new StringBuilder();
  14.  
  15. // 计数
  16.  
  17. int count = 0;
  18.  
  19. // 拼接单词
  20.  
  21. for(Text text : values){
  22.  
  23. // 分割符,
  24.  
  25. if(value.length() > 0){
  26.  
  27. value.append(",");
  28.  
  29. }
  30.  
  31. value.append(text);
  32.  
  33. // 计数
  34.  
  35. count++;
  36.  
  37. }
  38.  
  39. // 因为我们要统计相同字母组成的单词,所以相同字母组成的单词个数大于等于2才会输出
  40.  
  41. if(count > 1){
  42.  
  43. context.write(key, new Text(value.toString()));
  44.  
  45. }
  46.  
  47. }
  48.  
  49. }

同样,reduce 函数也有四个形式参数类型用于指定输入和输出类型。reduce 函数的输入类型必须匹配 map 函数的输出类型:即 Text 类型和Text类型。 在这种情况下,reduce 函数的输出类型也是 Text 和 Text 类型。在 map 的输出结果中,所有相同key的键值对被分配到同一个reduce执行,通过迭代来拼接所有单词,并将一组中只有一个单词的过滤掉

    3、一些用来运行作业的代码

  1. public int run(String[] arg0) throws Exception {
  2.  
  3. // 加载配置
  4.  
  5. Configuration conf = new Configuration();
  6.  
  7. // 输出目录,如果存在就删除
  8.  
  9. Path path = new Path(arg0[1]);
  10.  
  11. FileSystem fileSystem = path.getFileSystem(conf);
  12.  
  13. if(fileSystem.isDirectory(path)){
  14.  
  15. fileSystem.delete(path, true);
  16.  
  17. }
  18.  
  19. // 创建job对象
  20.  
  21. Job job = new Job(conf,"anagram");
  22.  
  23. job.setJarByClass(Anagram.class);
  24.  
  25. // 指定输入、输出目录
  26.  
  27. FileInputFormat.addInputPath(job, new Path(arg0[0]));
  28.  
  29. FileOutputFormat.setOutputPath(job, new Path(arg0[1]));
  30.  
  31. // 指定mapper、reduce
  32.  
  33. job.setMapperClass(AnagramMapper.class);
  34.  
  35. job.setReducerClass(AnagramReduce.class);
  36.  
  37. // 指定mapper、reduce的输出类型
  38.  
  39. job.setOutputKeyClass(Text.class);
  40.  
  41. job.setOutputValueClass(Text.class);
  42.  
  43. // 提交作业
  44.  
  45. return job.waitForCompletion(true) ? 0: 1;
  46.  
  47. }
  1. public static void main(String[] args) throws Exception {
  2.  
  3. String[] arg0 = {
  4.  
  5. "hdfs://ljc:9000/buaa/anagram",
  6.  
  7. "hdfs://ljc:9000/buaa/anagram/out"
  8.  
  9. };
  10.  
  11. // 执行mapperreduce
  12.  
  13. int status = ToolRunner.run(new Configuration(), new Anagram(), arg0);
  14.  
  15. System.exit(status);
  16. }

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、其他问题

1、hadoop环境配置

2、基于Eclipse的hadoop开发环境配置

3、代码及数据

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【刘超★ljc】。

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

MapReduce实战:查找相同字母组成的单词的更多相关文章

  1. MapReduce实战项目:查找相同字母组成的字谜

    实战项目:查找相同字母组成的字谜 项目需求:一本英文书籍中包含有成千上万个单词或者短语,现在我们要从中找出相同字母组成的所有单词. 数据集和期望结果举例: 思路分析: 1)在Map阶段,对每个word ...

  2. hadoop实战项目:查找相同字母组成的字谜

    前面我们学习了MapReduce编程思想和编程示例,那么本节课程同学们一起操练操练,动手完成下面的项目. 项目需求 一本英文书籍包含成千上万个单词或者短语,现在我们需要在大量的单词中,找出相同字母组成 ...

  3. 【原创】python倒排索引之查找包含某主题或单词的文件

    什么是倒排索引? 倒排索引(英语:Inverted index),也常被称为反向索引.置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射.它是文 ...

  4. [No00003E]26个字母暗藏的单词秘密

    个字母暗藏的单词秘密 人们普通认为:英语是拼音文字,因而与象形无关.但是,实际上,即使作为拼音文字,其字母的来源也与象形有关.根据笔者十多年的研究结果,英语中的二十六个字母每个字母都有其象形意义,而且 ...

  5. 三道习题(1、将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别。 #输入格式:按字典序由小到大输入若干个单词,每个单词占一行,以end结束输入。)

    #coding=gbk ''' 1.将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别. #输入格式:按字典序由小到大输入若干 ...

  6. 《OD大数据实战》MapReduce实战

    一.github使用手册 1. 我也用github(2)——关联本地工程到github 2. Git错误non-fast-forward后的冲突解决 3. Git中从远程的分支获取最新的版本到本地 4 ...

  7. MapReduce实战:统计不同工作年限的薪资水平

    1.薪资数据集 我们要写一个薪资统计程序,统计数据来自于互联网招聘hadoop岗位的招聘网站,这些数据是按照记录方式存储的,因此非常适合使用 MapReduce 程序来统计. 2.数据格式 我们使用的 ...

  8. mapreduce实战:统计美国各个气象站30年来的平均气温项目分析

    气象数据集 我们要写一个气象数据挖掘的程序.气象数据是通过分布在美国各地区的很多气象传感器每隔一小时进行收集,这些数据是半结构化数据且是按照记录方式存储的,因此非常适合使用 MapReduce 程序来 ...

  9. MapReduce实战--倒排索引

    本文地址:http://www.cnblogs.com/archimedes/p/mapreduce-inverted-index.html,转载请注明源地址. 1.倒排索引简介 倒排索引(Inver ...

随机推荐

  1. ubuntu下openGL的配置方法

    This is a simple tutorial to show a new linux user (such as myself) how to setup freeglut and OpenGl ...

  2. C语言学习总结(四) 剩余内容

    第六章.剩余内容 (预处理指令,宏定义,条件编译,文件操作) 预处理指令 简单的来说就是在程序编译之前需要做的事情 1.宏定义 概念: 是一个替换代码的预处理指令,可以在编译之前进行代码替换(宏展开, ...

  3. const变量与define定义常量的区别

    一.概念性区别 const 变量就是在普通变量前边加上一个关键字const,它赋值的唯一机会就是“定义时”,此变量不能被程序修改,存储在rodata区. define定义的是常量,不是变量,所以编译器 ...

  4. C语言 rand()函数的用法

    rand()(产生随机数) 相关函数 srand() 表头文件 #include<stdlib.h> 定义函数 int rand()(void) 函数说明 rand()会返回一随机数值,范 ...

  5. netsat -ano 查看已占用的端口以及tomcat出现端口被占或者启动失败问题

    A.在DOS命令下:输入netstat -ano——回车,可以查看已占用的端口,记下端口的PID,然后打开任务管理器,点查看,选择列,勾选PID确定,找到对应的PID,结束进程,如果结束不了或者结束后 ...

  6. C读写配置文件

    在项目开发中,经常需要读取应用配置文件的初始化参数,用于应用在启动前进行一些初始化配置.比如:Eclipse,参数项包含主题.字体大小.颜色.Jdk安装位置.自动提示等.Eclispe配置的文件格式是 ...

  7. Milk Patterns

    poj3261:http://poj.org/problem?id=3261 题意:给定一个字符串,求至少出现k 次的最长重复子串,这k 个子串可以重叠. 题解:还是用后缀数组,求H和后缀数组,然后二 ...

  8. php生成的中文文件名会变成乱码,应该这样解决

    现在php有很多类库,会生成文件,比如生成zip文件,生成二维码等等.这些类库用起来很爽,但是一旦生成带有中文的文件名,极有可能出现乱码. 问题:生成的中文文件名会变成乱码 解决:使用函数:iconv ...

  9. SQL2000和SQL2005和SQL2008同时安装问题

    原文:SQL2000和SQL2005和SQL2008同时安装问题 SQL2000和SQL2005和SQL2008同时安装问题 1,因为SQL2000安装过程中无法修改实例名称,故安装过程中必须先安装S ...

  10. Hibernate+jxl+excel导入数据库

    在将excel中的10w行数据导入数据库中时,总发生内存溢出,一开始使用的Spring+Hibernate;不知如何使用批处理,后来只是用Hibernate,10W行数据几分钟完成, 代码如下: pu ...