写在前面: 博主是一名大数据的初学者,昵称来源于《爱丽丝梦游仙境》中的Alice和自己的昵称。作为一名互联网小白,写博客一方面是为了记录自己的学习历程,一方面是希望能够帮助到很多和自己一样处于起步阶段的萌新。由于水平有限,博客中难免会有一些错误,有纰漏之处恳请各位大佬不吝赐教!个人小站:http://alices.ibilibili.xyz/ , 博客主页:https://alice.blog.csdn.net/
尽管当前水平可能不及各位大佬,但我还是希望自己能够做得更好,因为一天的生活就是一生的缩影。我希望在最美的年华,做最好的自己

在正式开始之前,我们先来看看一个倒排索引的例子。
        

        
        而具体什么是倒排索引?这里引用一下维基百科上的定义:

倒排索引(英语:Inverted index),也常被称为反向索引置入档案反向档案,是一种索引方法,被用来存储全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。
有两种不同的反向索引形式:

  • 一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表。
  • 一个单词的水平反向索引(或者完全反向索引)又包含每个单词在一个文档中的位置。

后者的形式提供了更多的兼容性(比如短语搜索),但是需要更多的时间和空间来创建。

倒排索引在搜索引擎中比较常见,百度,谷歌等大型互联网搜索引擎提供商均在搜索引擎业务中构建了倒序索引。本篇文章,就用一个简单的demo教大家如何使用Hadoop实现倒序索引。

需求

现在有3个文件,分别为 log_a.txt ,log_b.txt 和 log_c.txt,每个文件的内容如下所示:

log_a.txt
hello java
hello hadoop
hello javalog_b.txt
hello hadoop
hello hadoop
java hadooplog_c.txt
hello hadoop
hello java

要求经过 Hadoop 的处理后,输出如下信息:

hadoop  log_c.txt-->1 log_b.txt-->3 log_a.txt-->1
hello   log_c.txt-->2 log_b.txt-->2 log_a.txt-->3
java    log_c.txt-->1 log_b.txt-->1 log_a.txt-->2

需求分析

为了实现这种效果,我们可以很自然想到用MapReduce去处理。但是考虑到只用一个MapReduce处理,代码会写的比较冗长,可读性不强,对于新手小白不是很友好。于是本篇文章,作者介绍的就是如何通过两个MapReduce来实现“倒排索引”的功能!

主要思路如下:

倒排索引第一步的Mapper类
我们输出如下结果:
context.wirte(“hadoop->log_a.txt”, “1”)
context.wirte(“hadoop->log_b.txt”, “1”)
context.wirte(“hadoop->log_c.txt”, “1”)

倒排索引第一步的Reducer
最终输出结果为:
hello --> log_a.txt 3
hello --> log_b.txt 2
hello --> log_c.txt 2

倒排索引第二步的mapper
hello --> log_a.txt 3
hello–>log_b.txt 2
hello–>log_c.txt 2

倒排索引第二步的Reducer
hello         log_c.txt–>2         log_b.txt–>2         log_a.txt–>3
hadoop         log_c.txt–>1         log_b.txt–>3         log_a.txt–>1
java         log_c.txt–>1         log_b.txt–>1         log_a.txt–>2

好了,现在需求明确了,现在我们可以写代码了。

这是倒排索引第一步的Mapper:InverseIndexStepOneMapper

package io.alice;import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;import java.io.IOException;/*** @Author: Alice菌* @Date: 2020/10/4 20:38* @Description:* 读取文件的格式:* log_a.txt* hello java* hello hadoop* hello java**  倒排索引第一步的Mapper类,*  输出结果如下:*  context.wirte("hadoop->log_a.txt", "1")*  context.wirte("hadoop->log_b.txt", "1")*  context.wirte("hadoop->log_c.txt", "1")*/
public class InverseIndexStepOneMapper extends Mapper<LongWritable, Text,Text,LongWritable> {@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {if (value != null){// 获取一行的数据String line = value.toString();// 按照空格拆分每个单词String[] words = line.split(" ");if (words.length > 0){// 获取数据的切片信息,并根据切片信息获取到文件的名称FileSplit fileSplit = (FileSplit)context.getInputSplit();String fileName = fileSplit.getPath().getName();for (String word : words) {context.write(new Text(word + "-->" + fileName),new LongWritable(1));}}}}
}

倒排索引第一步的Reducer,InverseIndexStepOneReducer

package io.alice;import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;/*** @Author: Alice菌* @Date: 2020/10/4 20:47* @description: 完成倒排索引第一步的Reducer程序*       最终输出结果为:*        hello-->log_a.txt    3*      hello-->log_b.txt    2*      hello-->log_c.txt    2*      hadoop-->log_a.txt   1*      hadoop-->log_b.txt   3*      hadoop-->log_c.txt   1*      java-->log_a.txt 2*      java-->log_b.txt 1*      java-->log_c.txt 1*/
public class InverseIndexStepOneReducer extends Reducer<Text, LongWritable,Text,LongWritable> {@Overrideprotected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {if (values != null){// 初始化一个变量 sum ,保存每个单词在每个文件中出现的次数long sum = 0;for (LongWritable value : values) {sum += value.get();}context.write(key,new LongWritable(sum));}}
}

这是倒排索引第二步的Mapper:InverseIndexStepTwoMapper

package io.alice;import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;/*** @Author: Alice菌* @Date: 2020/10/4 21:03* @Description: 完成倒排索引第二步的mapper程序** *      hello-->log_a.txt    3*          hello-->log_b.txt    2*          hello-->log_c.txt    2*          hadoop-->log_a.txt   1*          hadoop-->log_b.txt   3*          hadoop-->log_c.txt   1*          java-->log_a.txt 2*          java-->log_b.txt 1*          java-->log_c.txt 1**  输出的信息为:*    context.write("hadoop", "log_a.txt->1")*  context.write("hadoop", "log_b.txt->3")*  context.write("hadoop", "log_c.txt->1")**  context.write("hello", "log_a.txt->3")*  context.write("hello", "log_b.txt->2")*  context.write("hello", "log_c.txt->2")**  context.write("java", "log_a.txt->2")*  context.write("java", "log_b.txt->1")*  context.write("java", "log_c.txt->1")*/
public class InverseIndexStepTwoMapper extends Mapper<LongWritable, Text,Text,Text> {@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {if (value != null){String line = value.toString();// 将第一步的Reduce输出结果按照 \t 拆分String[] fields = line.split("\t");// 将拆分后的结果数组的第一个元素再按照 --> 分隔String[] wordAndFileName = fields[0].split("-->");// 获取到单词String word = wordAndFileName[0];// 获取到文件名String fileName = wordAndFileName[1];// 获取到单词数量long count = Long.parseLong(fields[1]);context.write(new Text(word),new Text(fileName + "-->" + count));}}
}

倒排索引第二步的Reducer,InverseIndexStepTwoReducer

package io.alice;import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;/*** @Author: Alice菌* @Date: 2020/10/4 21:21* @Description: 完成倒排索引第二步的Reducer程序* 得到的输入信息格式为:* <"hello", {"log_a.txt->3", "log_b.txt->2", "log_c.txt->2"}>*   * 最终输出结果如下:*     *  hello   log_c.txt-->2 log_b.txt-->2 log_a.txt-->3*         hadoop  log_c.txt-->1 log_b.txt-->3 log_a.txt-->1*         java    log_c.txt-->1 log_b.txt-->1 log_a.txt-->2*/
public class InverseIndexStepTwoReducer extends Reducer<Text,Text,Text,Text> {@Overrideprotected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {if (values != null){String result = "";for (Text value : values) {result = result.concat(value.toString()).concat(" ");}context.write(key,new Text(result));}}
}

倒排索引的执行类:InverseIndexRunner

这里需要格外的注意,因为我们平时接触到的MapReduce程度大多都是由一个Job完成的,本次案例在执行类中如何实现多个Job依次执行,大家可以借鉴学习!

package io.alice;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import java.io.IOException;/**io.alice.InverseIndexRunner* @Author: Alice菌* @Date: 2020/10/4 21:39* @Description:  倒排索引的执行类*/
public class InverseIndexRunner extends Configured implements Tool {public static void main(String[] args) throws Exception {ToolRunner.run(new Configuration(),new InverseIndexRunner(),args);}public int run(String[] args) throws Exception {if (!runStepOneMapReduce(args)) {return 1;}return runStepTwoMapReduce(args) ? 0:1;}private static boolean runStepOneMapReduce(String[] args) throws Exception {Job job = getJob();job.setJarByClass(InverseIndexRunner.class);job.setMapperClass(InverseIndexStepOneMapper.class);job.setReducerClass(InverseIndexStepOneReducer.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(LongWritable.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(LongWritable.class);FileInputFormat.setInputPaths(job, new Path(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));return job.waitForCompletion(true);}private static boolean runStepTwoMapReduce(String []args) throws Exception {Job job = getJob();job.setJarByClass(InverseIndexRunner.class);job.setMapperClass(InverseIndexStepTwoMapper.class);job.setReducerClass(InverseIndexStepTwoReducer.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(Text.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(Text.class);FileInputFormat.setInputPaths(job,new Path(args[1] + "/part-r-00000"));FileOutputFormat.setOutputPath(job,new Path(args[2]));return job.waitForCompletion(true);}private static Job getJob() throws IOException {Configuration conf = new Configuration();return Job.getInstance(conf);}}

测试执行

我们将项目打成jar包上传至linux


        然后将数据源所需要的文件上传至HDFS

        然后执行命令:

hadoop jar /home/hadoop/alice_data-1.0-SNAPSHOT.jar io.alice.InverseIndexRunner /data/input /data/oneoutput /data/twooutput

程序就开始 奔跑 起来~

待到程序运行完毕,我们可以查看程序正确运行后的结果


        看到最后的效果跟我们题目需求所想要的完全一致时,就说明我们的思路是没错滴~

小结

我们每向他人学习到一项新的技能,一定要主动去思考别人解决问题的出发点,只有学会思考,才能举一反三,融会贯通!

本篇文章就到这里,更多精彩文章及福利,敬请关注博主原创公众号【猿人菌】!

扫码关注

关注即可获取高质量思维导图,互联网一线大厂面经,大数据珍藏精品书籍...期待您的关注!

你有想过,如何用Hadoop实现【倒排索引】?相关推荐

  1. 零售业如何用Hadoop开启大数据之门?

    文章讲的是零售业如何用Hadoop开启大数据之门,在过去几年,全球零售商一直试图利用大数据创造价值.由于其大数据分析基础架构的限制,许多工作被一再推迟.Hadoop为这些零售商打开了新的大门,它可以解 ...

  2. 如何用hadoop自带的包计算pi值

    一.计算pi的值的原理 通过hadoop计算pi值确实是一件很酷的事情,我想你可能会有疑问,(Hadoop不是一个分布式计算的处理数据的吗?)当然,计算它能处理大量数据,我们可以通过这种方式来计算pi ...

  3. 图片底下配的文字叫什么_PPT排版狂想篇 | 如何用一张图片搞定30种排版

    大家好,我是噜噜,今天是第三次见面啦 开门见山,今天我们来噜一下PPT的排版.如何只用一张图片素材,噜它个30种版式 图源 | www.pexels.com 一般在噜一份PPT之前,PPTer会考虑以 ...

  4. 我想知道如何用风扇自制水空调?

    <p>你好,现在很多家庭因为不想花那么多钱买空调,所以都会选择自己制作水空调.1.水空调的原理很简单,就是将地下水抽上来后流过蒸发器.所需要的部件也就根据这个原理即可.2.泵功率的大小决定 ...

  5. jenkins 手动执行_想知道如何用Jenkins自动执行Python脚本输出测试报告?

    前言在用python做自动化测试时,我们写好代码,然后需要执行才能得到测试报告,这时我们可以通过 Jenkins 来进一步完成自动化工作.借助Jenkins,我们可以结合 Git/SVN 自动拉取代码 ...

  6. hadoop学习-倒排索引

    倒排索引是文档搜索系统中常用的数据结构.它主要用来存储某个词组在一个或多个文档中的位置映射.通常情况下,倒排索引由词组以及相关的文档列表组成.如下表所示. 表1: 单词      文档列表 单词1 文 ...

  7. Hadoop之MapReduce理论篇01

    2019独角兽企业重金招聘Python工程师标准>>> 1. Writable序列化 序列化就是把内存中的对象,转换成字节序列 (或其他数据传输协议) 以便于存储 (持久化) 和网络 ...

  8. 最新Hive/Hadoop高频面试点小集合

    点击上方蓝色字体,选择"设为星标" 回复"资源"获取更多资源 Hive部分: 1.Hive的两张表关联,使用MapReduce怎么实现? 如果其中有一张表为小表 ...

  9. 2020年11月 工信部考试——Hadoop(数据应用技术)中级认证3

    系统提纲 281.掌握常用 hdfs 操作命令,执行并查看结果. 283. 在 Linux 系统中创建一个目录 work,并在该目录下创建文件 file.txt, 写入"I have a d ...

  10. 【大数据面试题】(一)Hadoop 相关面试题总结

    1.MapTask并行机度是由什么决定的? 由切片数量决定的. 2.MR是干什么的? MR将用户编写的业务逻辑代码和自带的默认组件结合起来组成一个完整的分布式应用程序放到hadoop集群上运行. 3. ...

最新文章

  1. vue 2.6 插槽v-slot用法记录
  2. Git提示Please move or remove them before you switch branches.
  3. 为您的下一个基于Spring的应用程序考虑使用spring-boot的原因!
  4. 在weblogic12c中启动工程报错缺失BeanFactoryAware
  5. MATLAB中的曲线拟合
  6. pytorch 与 numpy 的相互转换
  7. shell应用之cobbler批量部署
  8. linux中可以使用-af含义,关于Windows中的linux:AF_UNIX
  9. Hexo文章中图片点击实现全屏查看
  10. 最牛逼的java代码_分享史上java最牛逼,最简短的代码
  11. Latex写创新作业
  12. 鸿蒙os手机有哪些,华为正式发布鸿蒙手机操作系统 鸿蒙操作系统是什么?鸿蒙适用机型首曝光...
  13. 适用于顺序磁盘访问的1分钟法则
  14. 再添新认证!云和恩墨 zCloud 与华为 FusionCube 完成兼容性测试
  15. matplotlib.pyplot 库(二)
  16. C语言回音消除算法,一种语音识别场景中回音消除的方法
  17. 微信小程序开发类似微博回复功能自带云开发数据库(无限回复)
  18. 图解ReentrantLock底层公平锁和非公平锁实现原理
  19. X-editable 文档 中文版
  20. 安徽财经大学434国际商务专业基础考研历年真题库资料

热门文章

  1. 计算机linux认证-1,Linux认证:Linux点评Debian5个五功能
  2. 计算机网络中协议分层的目的是什么意思,网络协议分层的作用是什么
  3. 北漂人的独白,是否有所共鸣
  4. 使用MOno Cecil 的相关开源项目
  5. 类和对象4:类、类对象、实例对象
  6. 在android客户端加载html源代码总结
  7. 卢菲菲记忆课程(一、了解记忆认识大脑)
  8. 数据库sql对象名无效问题
  9. t5_Sophisticated Algorithmic Strategies(MeanReversion+APO+StdDev_TrendFollowing+APO)_StatArb统计套利_PnL
  10. greenplum,teradata,presto,clickhouse四种分布式数据库的对比