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

article/2025/9/24 4:04:10

写在前面: 博主是一名大数据的初学者,昵称来源于《爱丽丝梦游仙境》中的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

        程序就开始 奔跑 起来~
在这里插入图片描述

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

在这里插入图片描述
        看到最后的效果跟我们题目需求所想要的完全一致时,就说明我们的思路是没错滴~
        

在这里插入图片描述

小结

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

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

扫码关注

在这里插入图片描述

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

http://chatgpt.dhexx.cn/article/BTtgCmqA.shtml

相关文章

2021年终总结:鲜花怒马少年时,一日看尽长安花

Author:AXYZdong 自动化专业 工科男 有一点思考,有一点想法,有一点理性! 定个小小目标,努力成为习惯!在最美的年华遇见更好的自己! CSDN@AXYZdong,CSDN首发,AXYZdong原创 唯一博客更新的地址为: 👉 AXYZdong的博客 👈 B站主页为:AXYZdong的个人主页 往期总结: …

面试官:兄弟,说说基本类型和包装类型的区别吧

六年前&#xff0c;我从苏州回到洛阳&#xff0c;抱着一幅“海归”的心态&#xff0c;投了不少简历&#xff0c;也“约谈”了不少面试官&#xff0c;但仅有两三个令我感到满意。其中有一位叫老马&#xff0c;至今还活在我的手机通讯录里。他当时扔了一个面试题把我砸懵了&#…

【一些好听的英文歌曲】

原文地址&#xff1a;【一些好听的英文歌曲】 作者&#xff1a;姑娘我笑着活 1、Bubbly--Colbie Caillat&#xff08;你听过一遍就会非常喜欢的歌&#xff09;&#xff1b; 2、Burning--Maria Arredondo&#xff1b; 3、Happy--丽安娜 刘易斯&#xff1b; 4、Cry On My Shoulde…

彻底理解position与anchorPoint - 记忆丶腐朽年华

引言 相信初接触到CALayer的人都会遇到以下几个问题&#xff1a; 为什么修改anchorPoint会移动layer的位置&#xff1f; CALayer的position点是哪一点呢? anchorPoint与position有什么关系&#xff1f; 我也迷惑过&#xff0c;找过网上的教程&#xff0c;大部分都是复制粘…

每日一句英语珍句

2016/11/06 Our lives are brief, thats why its important to search for meaning. 人的一生如此短暂,因此,找到活着的意义至关重要。 ------《绝望主妇》 2016/11/06 Life is like a multiple choice question. Sometimes, the choices confuse you, …

2019年感:忆往昔考博岁月,看今朝花样年华

人生的际遇谁又能说清楚&#xff0c;就像师范类毕业的女神梦想着当一名老师&#xff0c;结果却阴差阳错穿上了警服&#xff1b;而本应该奔波北上广深的程序员&#xff0c;却成为了一名大学老师&#xff0c;两条平行线的男女&#xff0c;却结为了连理。再如&#xff0c;一心准备…

英语年华的空间

学习前预热&#xff1a; ———轻松学英语第一步&#xff1a;建立英语思维 为什么大家学英语学得这么累&#xff0c;最后依然对英语糊糊涂涂&#xff1f;原因只有一个——就是我们的学习能力太差了&#xff01;&#xff01;我们的老师太笨了&#xff01;&#xff01;&#xf…

Wireshark切割PCAP以及合并PCAP

1 Wireshark切割PCAP 有时候对PCAP包进行分析&#xff0c;会遇到内存不足打不开较大的PCAP&#xff0c;那么有两种方法解决这个问题&#xff0c;一个是写程序对PCAP进行过滤或者截取&#xff1b;另一个是使用Wireshark自带的函数进行PCAP切割&#xff0c;本篇选择使用Wireshar…

SplitCap切分pcap包

SplitCap下载 SplitCap 是一款免费工具&#xff0c;旨在根据 IP 地址、5 元组或 MAC 地址等标准将捕获文件&#xff08;PCAP 文件&#xff09;拆分为较小的文件。下载地址&#xff1a;SplitCap Windows下使用 下载完SplitCap后&#xff0c;可以在windows终端中直接使用&…

pcap文件的python解析实例

最近一直在分析数据包。 同时也一直想学python。 凑一块儿了...于是&#xff0c;便开工了。座椅爆炸&#xff01; 正文首先要说的是&#xff0c;我知道python有很多解析pcap文件的库&#xff0c;这里不使用它们的原因是为了理解pcap文件的格式细节。使用tcpdump你可以很容易抓…

CapAnalysis Pcap分析工具

CapAnalysis Pcap分析工具&#xff1a; CapAnalysis 对 PCAP 文件的数据集进行索引并以多种形式呈现它们的内容&#xff0c;从 TCP、UDP 或 ESP 流/流列表开始&#xff0c;传递到连接的地理表示。对于由一个或多个 PCAP 文件组成的每个数据集&#xff0c;CapAnalysis 收集数据…

wirehark数据分析与取证misc1.pcap

什么是wireshark&#xff1f; wiresharekwireshark--misc1.pcap数据包 wiresharek Wireshark&#xff08;前称Ethereal&#xff09;是一个网络封包分析软件。网络封包分析软件的功能是检索取网络封包&#xff0c;并同时显示出最详细的网络封包数据。Wireshark使用WinPCAP作为接…

.pcapng文件格式和.pcap文件格式

原网页 本文为机翻后人工修饰了一些&#xff0c;总结一句话就是 .pcapng是.pcap的升级版 pcap捕获文件格式自计算机网络早期以来一直是通用的包捕获格式。 几乎所有捕获工具都支持pcap格式。 虽然供应商多年来已经创建了新的格式&#xff0c;但大多数工具支持转换为pcap格式。 …

Java之Pcap文件解析(一:Pcap格式分析)

前言 需求 本系列文章主要完成以下功能&#xff1a; 1. 对Pcap文件进行解析&#xff0c;并从中提取TCP和UDP会话 2. 从TCP会话中提取出其数据负载信息 软件最终结果 [主界面] [File 菜单] [Help 的 About 菜单项&#xff0c;版权声明] [选择Pcap文件] [选择输…

wirehark数据分析与取证0051.pcap

什么是wireshark&#xff1f; wiresharekwireshark0051.pcap数据包数据包下载 请私信博主 wiresharek Wireshark&#xff08;前称Ethereal&#xff09;是一个网络封包分析软件。网络封包分析软件的功能是检索取网络封包&#xff0c;并同时显示出最详细的网络封包数据。Wiresha…

C++ 缺少winpcap头文件 pcap.h 解决方案

最近在做课设的时候看到一个代码用到了winpcap的一个头文件 pcap.h &#xff0c;为了能让代码跑起来也是找了很多资料&#xff0c;因此在这里汇总一下。 在官网下载开发包&#xff0c;我下载的是 WinPcap 4.1.2 Developer’s Pack 的版本&#xff0c;下载后解压缩&#xff0c;并…

PACP学习笔记一:使用 PCAP 编程

pcap代码流程 我们首先确定要嗅探哪个接口。在 Linux 中这可能是 eth0&#xff0c;在 BSD 中可能是 xl1&#xff0c;等等。我们可以在字符串中定义这个设备&#xff0c;或者我们可以让 pcap 为我们提供一个接口的名称来完成这项工作。初始化pcap。这其实是实际告诉pcap我们正在…

pcap(cap)包文件解析

https://blog.csdn.net/m0_37710388/article/details/89217421 pcap文件是常用的数据报存储格式&#xff0c;可以理解为就是一种文件格式&#xff0c;只不过里面的数据是按照特定格式存储的&#xff0c;所以我们想要解析里面的数据&#xff0c;也必须按照一定的格式。普通的记事…

pcap1

一、前言 本题方向为Misc——GFSJ0963&#xff0c;难度偏简单 来源地址&#xff1a;攻防世界&#xff08;https://adworld.xctf.org.cn/challenges/list&#xff09; 链接&#xff1a;https://pan.baidu.com/s/1VWT0rDY5P2qvOp_GMCZwkQ 提取码&#xff1a;lyyy 二、解题过程 思…

pcap文件解析

pcap文件解析 1. pcap简介&#xff1a; pcap文件是一种常用的数据报存储文件&#xff0c;这种文件可以保存我们所抓到的报文。它有这固定的存储格式&#xff0c;通过notepad中的插件Hex-Editor我们可以观察其中的16进制数据&#xff0c;从而来进行pcap文件的分析。 2. Pcap文…