写在前面: 博主是一名大数据的初学者,昵称来源于《爱丽丝梦游仙境》中的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. 第13天学习Java的笔记(类定义)
  2. superslide 学习笔记
  3. 47、Windows驱动程序模型笔记(五),内存管理
  4. 数据结构题及c语言版实验报告排序,数据结构二叉排序树实验报告
  5. Linux系统下通过命令行对mysql数据进行备份和还原
  6. 零百1.8秒的电动车竟然是威马... | 云逛成都车展
  7. 今天要查一下,如果没有密保手机的号码在使用,怎么更换qq的密保手机
  8. Unity3D Shader系列之深度纹理
  9. Java数据结构与算法——哈希表
  10. 设计模式之装饰者模式
  11. IBM Platform LSF在IC行业内的使用
  12. MTTF,MTBF,MTTF
  13. 微型计算机指的是重量轻,计算机与信息技术概述(答案)
  14. 狗狗40题~ (Volume C)
  15. alpine linux 简介
  16. 说说Java代理模式
  17. 大型电商架构亿级流量电商详情页系统--实战 服务降级
  18. 桌面计算机硬盘打不开怎么办,电脑硬盘打不开提示格式化怎么办
  19. iOS开发-技术知识盘点总结(二)
  20. [C++ Error] uxtheme.h(176): E2146 Need an identifier to declare

热门文章

  1. html5分镜头脚本范例,分镜头脚本范本
  2. 在 Intel NUC8i7HVK 上安装CentOS7
  3. DGL笔记1——用DGL表示图
  4. 三千弱水,总有一瓢知我冷暖
  5. java 项目的部署方案
  6. 计算机个人市场调查实验报告,市场调查实验报告(一).doc
  7. android 来电播放铃声,android 播放来电铃声
  8. 在电脑上收听广播——龙卷风网络收音机试用
  9. delphi清除ie缓存的方法
  10. 转:教人找电影的攻略