Hadoop编程基于MR程序实现倒排索引示例

相信接触过搜索引擎开发的同学对倒排索引并不陌生,谷歌、百度等搜索引擎都是用的倒排索引,关于倒排索引的有关知识,这里就不再深入讲解,有兴趣的同学到网上了解一下。这篇博文就带着大家一起学习下如何利用Hadoop的MR程序来实现倒排索引的功能。

一、数据准备

1、输入文件数据

这里我们准备三个输入文件,分别如下所示

a.txt

hello tom
hello jerry
hello tom 

b.txt

hello jerry
hello jerry
tom jerry 

c.txt

hello jerry
hello tom 

2、最终输出文件数据

最终输出文件的结果为:

[plain] view plain copy
hello  c.txt-->2 b.txt-->2 a.txt-->3
jerry  c.txt-->1 b.txt-->3 a.txt-->1
tom c.txt-->1 b.txt-->1 a.txt-->2  

二、倒排索引过程分析

根据输入文件数据和最终的输出文件结果可知,此程序需要利用两个MR实现,具体流程可总结归纳如下:

-------------第一步Mapper的输出结果格式如下:--------------------
context.wirte("hello->a.txt", "1")
context.wirte("hello->a.txt", "1")
context.wirte("hello->a.txt", "1")
context.wirte("hello->b.txt", "1")
context.wirte("hello->b.txt", "1")
context.wirte("hello->c.txt", "1")
context.wirte("hello->c.txt", "1")
-------------第一步Reducer的得到的输入数据格式如下:-------------
<"hello->a.txt", {1,1,1}>
<"hello->b.txt", {1,1}>
<"hello->c.txt", {1,1}>
-------------第一步Reducer的输出数据格式如下---------------------
context.write("hello->a.txt", "3")
context.write("hello->b.txt", "2")
context.write("hello->c.txt", "2")
-------------第二步Mapper得到的输入数据格式如下:-----------------
context.write("hello->a.txt", "3")
context.write("hello->b.txt", "2")
context.write("hello->c.txt", "2")
-------------第二步Mapper输出的数据格式如下:--------------------
context.write("hello", "a.txt->3")
context.write("hello", "b.txt->2")
context.write("hello", "c.txt->2")
-------------第二步Reducer得到的输入数据格式如下:-----------------
<"hello", {"a.txt->3", "b.txt->2", "c.txt->2"}>
-------------第二步Reducer输出的数据格式如下:-----------------
context.write("hello", "a.txt->3 b.txt->2 c.txt->2")
最终结果为:
hello  a.txt->3 b.txt->2 c.txt->2 

三、程序开发

3.1、第一步MR程序与输入输出

package com.lyz.hdfs.mr.ii;
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/**
 * 倒排索引第一步Map Reduce程序,此处程序将所有的Map/Reduce/Runner程序放在一个类中
 * @author liuyazhuang
 *
 */
public class InverseIndexStepOne {
  /**
   * 完成倒排索引第一步的mapper程序
   * @author liuyazhuang
   *
   */
  public static class StepOneMapper extends Mapper<LongWritable, Text, Text, LongWritable>{
    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, LongWritable>.Context context)
        throws IOException, InterruptedException {
      //获取一行数据
      String line = value.toString();
      //切分出每个单词
      String[] fields = StringUtils.split(line, " ");
      //获取数据的切片信息
      FileSplit fileSplit = (FileSplit) context.getInputSplit();
      //根据切片信息获取文件名称
      String fileName = fileSplit.getPath().getName();
      for(String field : fields){
        context.write(new Text(field + "-->" + fileName), new LongWritable(1));
      }
    }
  }
  /**
   * 完成倒排索引第一步的Reducer程序
   * 最终输出结果为:
   * hello-->a.txt  3
    hello-->b.txt  2
    hello-->c.txt  2
    jerry-->a.txt  1
    jerry-->b.txt  3
    jerry-->c.txt  1
    tom-->a.txt 2
    tom-->b.txt 1
    tom-->c.txt 1
   * @author liuyazhuang
   *
   */
  public static class StepOneReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
    @Override
    protected void reduce(Text key, Iterable<LongWritable> values,
        Reducer<Text, LongWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
      long counter = 0;
      for(LongWritable value : values){
        counter += value.get();
      }
      context.write(key, new LongWritable(counter));
    }
  }
  //运行第一步的MR程序
  public static void main(String[] args) throws Exception{
    Configuration conf = new Configuration();
    Job job = Job.getInstance(conf);
    job.setJarByClass(InverseIndexStepOne.class);
    job.setMapperClass(StepOneMapper.class);
    job.setReducerClass(StepOneReducer.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(LongWritable.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(LongWritable.class);
    FileInputFormat.addInputPath(job, new Path("D:/hadoop_data/ii"));
    FileOutputFormat.setOutputPath(job, new Path("D:/hadoop_data/ii/result"));
    job.waitForCompletion(true);
  }
} 

3.1.1 输入数据

a.txt

hello tom
hello jerry
hello tom 

b.txt

hello jerry
hello jerry
tom jerry 

c.txt

hello jerry
hello tom 

3.1.2

输出结果:

hello-->a.txt  3
hello-->b.txt  2
hello-->c.txt  2
jerry-->a.txt  1
jerry-->b.txt  3
jerry-->c.txt  1
tom-->a.txt 2
tom-->b.txt 1
tom-->c.txt 1 

3.2 第二步MR程序与输入输出

package com.lyz.hdfs.mr.ii;
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/**
 * 倒排索引第二步Map Reduce程序,此处程序将所有的Map/Reduce/Runner程序放在一个类中
 * @author liuyazhuang
 *
 */
public class InverseIndexStepTwo {
  /**
   * 完成倒排索引第二步的mapper程序
   *
   * 从第一步MR程序中得到的输入信息为:
   * hello-->a.txt  3
    hello-->b.txt  2
    hello-->c.txt  2
    jerry-->a.txt  1
    jerry-->b.txt  3
    jerry-->c.txt  1
    tom-->a.txt 2
    tom-->b.txt 1
    tom-->c.txt 1
   * @author liuyazhuang
   *
   */
  public static class StepTwoMapper extends Mapper<LongWritable, Text, Text, Text>{
    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
        throws IOException, InterruptedException {
      String line = value.toString();
      String[] fields = StringUtils.split(line, "\t");
      String[] wordAndFileName = StringUtils.split(fields[0], "-->");
      String word = wordAndFileName[0];
      String fileName = wordAndFileName[1];
      long counter = Long.parseLong(fields[1]);
      context.write(new Text(word), new Text(fileName + "-->" + counter));
    }
  }
  /**
   * 完成倒排索引第二步的Reducer程序
   * 得到的输入信息格式为:
   * <"hello", {"a.txt->3", "b.txt->2", "c.txt->2"}>,
   * 最终输出结果如下:
   * hello  c.txt-->2 b.txt-->2 a.txt-->3
    jerry  c.txt-->1 b.txt-->3 a.txt-->1
    tom c.txt-->1 b.txt-->1 a.txt-->2
   * @author liuyazhuang
   *
   */
  public static class StepTwoReducer extends Reducer<Text, Text, Text, Text>{
    @Override
    protected void reduce(Text key, Iterable<Text> values, Reducer<Text, Text, Text, Text>.Context context)
        throws IOException, InterruptedException {
      String result = "";
      for(Text value : values){
        result += value + " ";
      }
      context.write(key, new Text(result));
    }
  }
  //运行第一步的MR程序
  public static void main(String[] args) throws Exception{
    Configuration conf = new Configuration();
    Job job = Job.getInstance(conf);
    job.setJarByClass(InverseIndexStepTwo.class);
    job.setMapperClass(StepTwoMapper.class);
    job.setReducerClass(StepTwoReducer.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(Text.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(Text.class);
    FileInputFormat.addInputPath(job, new Path("D:/hadoop_data/ii/result/part-r-00000"));
    FileOutputFormat.setOutputPath(job, new Path("D:/hadoop_data/ii/result/final"));
    job.waitForCompletion(true);
  }
} 

3.2.1 输入数据

hello-->a.txt  3
hello-->b.txt  2
hello-->c.txt  2
jerry-->a.txt  1
jerry-->b.txt  3
jerry-->c.txt  1
tom-->a.txt 2
tom-->b.txt 1
tom-->c.txt 1 

3.2.2 输出结果

hello  c.txt-->2 b.txt-->2 a.txt-->3
jerry  c.txt-->1 b.txt-->3 a.txt-->1
tom c.txt-->1 b.txt-->1 a.txt-->2  

总结

以上就是本文关于Hadoop编程基于MR程序实现倒排索引示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:Hadoop对文本文件的快速全局排序实现方法及分析、hadoop重新格式化HDFS步骤解析、浅谈七种常见的Hadoop和Spark项目案例等,有什么问题可以直接留言,小编会及时回复大家的。感谢朋友们对本站的支持!

(0)

相关推荐

  • docker 搭建hadoop以及hbase集群详解

    要用docker搭建集群,首先需要构造集群所需的docker镜像.构建镜像的一种方式是,利用一个已有的镜像比如简单的linux系统,运行一个容器,在容器中手动的安装集群所需要的软件并进行配置,然后commit容器到新的镜像.另一种方式是,使用Dockerfile来自动化的构造镜像. 下面采用第二种. 1. 创建带ssh服务的ubuntu14.04系统镜像 使用ubuntu14系统来安装hadoop和hbase,由于hadoop集群机器之间通过ssh通信,所以需要在ubuntu14系统中安装ssh

  • Hadoop上Data Locality的详解

    Hadoop上Data Locality的详解 Hadoop上的Data Locality是指数据与Mapper任务运行时数据的距离接近程度(Data Locality in Hadoop refers to the"proximity" of the data with respect to the Mapper tasks working on the data.) 1. why data locality is imporant? 当数据集存储在HDFS中时,它被划分为块并存储在

  • hadoop动态增加和删除节点方法介绍

    上一篇文章中我们介绍了Hadoop编程基于MR程序实现倒排索引示例的有关内容,这里我们看看如何在Hadoop中动态地增加和删除节点(DataNode). 假设集群操作系统均为:CentOS 6.7 x64 Hadoop版本为:2.6.3 一.动态增加DataNode 1.准备新的DataNode节点机器,配置SSH互信,可以直接复制已有DataNode中.ssh目录中的authorized_keys和id_rsa 2.复制Hadoop运行目录.hdfs目录及tmp目录至新的DataNode 3.

  • Hadoop 中 HBase Shell命令的详解

    Hadoop 中 HBase Shell命令的详解 HBase包含可以与HBase进行通信的Shell. HBase使用Hadoop文件系统来存储数据.所有这些任务发生在HDFS.下面给出的是一些由 常用的HBase Shell命令. 数据操纵语言 命令 说明 命令表达式 create 创建一个表 create '表名称', '列名称1','列名称2','列名称N' put  添加记录 put '表名称', '行名称', '列名称:', '值' get  查看记录 get '表名称', '行名称

  • VMware虚拟机下hadoop1.x的安装方法

    这是Hadoop学习全程记录第1篇,在这篇里我将介绍一下如何在Linux下安装Hadoop1.x. 先说明一下我的开发环境: 虚拟机:VMware8.0: 操作系统:CentOS6.4: 版本:jdk1.8:hadoop1.2.1 ①下载hadoop1.2.1,网盘:链接: https://pan.baidu.com/s/1sl5DMIp 密码: 5p67 下载jdk1.8,网盘:链接: https://pan.baidu.com/s/1boN1gh5 密码: t36h 将 jdk-8u144-

  • 浅谈七种常见的Hadoop和Spark项目案例

    有一句古老的格言是这样说的,如果你向某人提供你的全部支持和金融支持去做一些不同的和创新的事情,他们最终却会做别人正在做的事情.如比较火爆的Hadoop.Spark和Storm,每个人都认为他们正在做一些与这些新的大数据技术相关的事情,但它不需要很长的时间遇到相同的模式.具体的实施可能有所不同,但根据我的经验,它们是最常见的七种项目. 项目一:数据整合 称之为"企业级数据中心"或"数据湖",这个想法是你有不同的数据源,你想对它们进行数据分析.这类项目包括从所有来源获得

  • ASP.NET实现Hadoop增删改查的示例代码

    本文介绍了ASP.NET实现Hadoop增删改查的示例代码,分享给大家,具体如下: packages.config <?xml version="1.0" encoding="utf-8"?> <packages> <package id="Microsoft.AspNet.WebApi.Client" version="4.0.20505.0" targetFramework="net

  • hadoop格式化HDFS出现错误解决办法

    hadoop格式化HDFS出现错误解决办法 报错信息: host:java.net.UnknownHostException: centos-wang: centos-wang: unknown error 在执行hadoop namenode -format命令时,出现未知的主机名. 问题原因: 出现这种问题的原因是Hadoop在格式化HDFS的时候,通过hostname命令获取到的主机名与/etc/hosts文件中进行映射的时候,没有找到. 解决方案: 1.修改/etc/hosts内容 2.

  • Hadoop对文本文件的快速全局排序实现方法及分析

    一.背景 Hadoop中实现了用于全局排序的InputSampler类和TotalOrderPartitioner类,调用示例是org.apache.hadoop.examples.Sort. 但是当我们以Text文件作为输入时,结果并非按Text中的string列排序,而且输出结果是SequenceFile. 原因: 1) hadoop在处理Text文件时,key是行号LongWritable类型,InputSampler抽样的是key,TotalOrderPartitioner也是用key去

  • Hadoop编程基于MR程序实现倒排索引示例

    相信接触过搜索引擎开发的同学对倒排索引并不陌生,谷歌.百度等搜索引擎都是用的倒排索引,关于倒排索引的有关知识,这里就不再深入讲解,有兴趣的同学到网上了解一下.这篇博文就带着大家一起学习下如何利用Hadoop的MR程序来实现倒排索引的功能. 一.数据准备 1.输入文件数据 这里我们准备三个输入文件,分别如下所示 a.txt hello tom hello jerry hello tom b.txt hello jerry hello jerry tom jerry c.txt hello jerr

  • Python网络编程基于多线程实现多用户全双工聊天功能示例

    本文实例讲述了Python网络编程基于多线程实现多用户全双工聊天功能.分享给大家供大家参考,具体如下: 在前面一篇<Python网络编程使用select实现socket全双工异步通信功能>中,我们实现了1对1的异步通信,在文章结尾,给出了多对多通信的思路. 既然说了,咱就动手试一试,本次用的是多线程来实现,正好练练手- 首先讲一下思路: 我们将服务器做为中转站来处理信息,一方面与客户端互动,另一方面进行消息转发. 大体思路确定下来后,需要确定一些通信规则: 1. 客户端与服务器建立连接后,需要

  • Java编程使用卡片布局管理器示例【基于swing组件】

    本文实例讲述了Java编程使用卡片布局管理器.分享给大家供大家参考,具体如下: 运行效果: 完整示例代码: package com.han; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JB

  • Android编程基于自定义view实现公章效果示例【附源码下载】

    本文实例讲述了Android编程基于自定义view实现公章效果.分享给大家供大家参考,具体如下: 上次去一个公司面试,面试官问了一个题,怎么用android的自定义view实现一个公章的效果,据说这是华为之前的面试题,我想了下,要是公章的效果,最外层是一个圆,里面是一个五角星,但是这文字怎么画呢,比较难搞,后来回来看了下java的api,发现人家的Path里面本来就提供了这么一个方法: public void addArc(RectF oval, float startAngle, float

  • Android编程基于自定义View实现绚丽的圆形进度条功能示例

    本文实例讲述了Android编程基于自定义View实现绚丽的圆形进度条功能.分享给大家供大家参考,具体如下: 本文包含两个组件,首先上效果图: 1.ProgressBarView1(支持拖动): 2.ProgressBarView2(不同进度值显示不同颜色,不支持拖拽):   代码不多,注释也比较详细,全部贴上了: (一)ProgressBarView1: /** * 自定义绚丽的ProgressBar. */ public class ProgressBarView1 extends View

  • 使用Python的Flask框架构建大型Web应用程序的结构示例

    虽然小型web应用程序用单个脚本可以很方便,但这种方法却不能很好地扩展.随着应用变得复杂,在单个大的源文件中处理会变得问题重重. 与大多数其他web框架不同,Flask对大型项目没有特定的组织方式:应用程序的结构完全交给开发人员自己决定.在这一章,提出一个可能的方式来组织管理一个大型应用程序的包和模块.这种结构将用于书中其余的示例中. 1.项目结构 示例 基本多文件Flask应用结构 |-flasky |-app/ |-templates/ |-static/ |-main/ |-__init_

  • Android编程基于Contacts读取联系人的方法(附demo源码)

    本文实例讲述了Android编程基于Contacts读取联系人的方法.分享给大家供大家参考,具体如下: Android Contacts简介: 这里介绍安卓通讯录数据库.包括Android使用Contacts访问SQLite的基本知识,并了解Android SQLite和Contacts的更多信息.谷歌改变了从版本1到版本2的Contacts数据库.下面加以简单介绍. Contacts 读取代码: package com.homer.phone; import java.util.ArrayLi

  • Android编程基于自定义控件实现时钟功能的方法

    本文实例讲述了Android编程基于自定义控件实现时钟功能的方法.分享给大家供大家参考,具体如下: 在学习安卓群英传自定义控件章节的时候,有一个例子是绘制时钟,在实现了书上的例子后就想看这个时钟能不能动起来. 这里选择延迟一秒发送消息重绘view来实现的动画,对外提供了开启时钟,关闭时钟的方法,当activity执行onResume方法的时候,执行startClock()方法,当移除view或activity执行onStop方法的时候可以执行stopClock()方法. 首先根据view的宽高来

  • python编程控制Android手机操作技巧示例

    目录 你应该拥有的东西 安装 开始 轻敲 截图 高级点击 TemplateMatching 滑动 打电话给某人 从手机下载文件到电脑 手机录屏 打开手机 发送 Whatsapp 消息 几天前我在考虑使用 python 从 whatsapp 发送消息.和你们一样,我开始潜伏在互联网上寻找一些解决方案并找到了关于twilio. 一开始,是一个不错的解决方案,但它不是免费的,我必须购买一个 twilio 电话号码.此外,我无法在互联网上找到任何可用的 whatsapp API.所以我放弃了使用 twi

  • Python编程实现凯撒密码加密示例

    目录 一.什么是凯撒密码 二.python实现凯撒加密 一.什么是凯撒密码 "在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密.恺撒变换.变换加密,是一种最简单且最广为人知的加密技术.它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文.例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推.这个加密方法是以罗马共和时期恺撒的名字命名的,当年恺撒曾用此方法与其将军们进行联系." 关于凯撒密码的详细

随机推荐