Linux下MapReduce编程之倒排索引

一、实验内容

"倒排索引"是文档检索系统中最常用的数据结构,被广泛地应用于全文搜索引擎。它主要是用来存储某个单词(或词组)在一个文档或一组文档中的存储位置的映射,即提供了一种根据内容来查找文档的方式。由于不是根据文档来确定文档所包含的内容,而是进行相反的操作,因而称为倒排索引(Inverted Index)。
实例描述
通常情况下,倒排索引由一个单词(或词组)以及相关的文档列表组成,文档列表中的文档或者是标识文档的ID号,或者是指文档所在位置的URL,如图1所示。
在这里插入图片描述
图1 倒排索引结构

从图1可以看出,单词1出现在{文档1,文档4,文档13,……}中,单词2出现在{文档3,文档5,文档15,……}中,而单词3出现在{文档1,文档8,文档20,……}中。在实际应用中,还需要给每个文档添加一个权值,用来指出每个文档与搜索内容的相关度,如图2所示。

在这里插入图片描述
图2 添加权重的倒排索引

最常用的是使用词频作为权重,即记录单词在文档中出现的次数。以英文为例,如图3所示,索引文件中的"MapReduce"一行表示:“MapReduce"这个单词在文本T0中出现过1次,T1中出现过1次,T2中出现过2次。当搜索条件为"MapReduce”、“is”、"Simple"时,对应的集合为:{T0,T1,T2}∩{T0,T1}∩{T0,T1}={T0,T1},即文档T0和T1包含了所要索引的单词,而且只有T0是连续的。
在这里插入图片描述
图3 倒排索引示例
更复杂的权重还可能要记录单词在多少个文档中出现过,以实现TF-IDF(Term Frequency-Inverse Document Frequency)算法,或者考虑单词在文档中的位置信息(单词是否出现在标题中,反映了单词在文档中的重要性)等。
样例输入如下所示。
1)file1:

MapReduce is simple

2)file2:

MapReduce is powerful is simple

3)file3:

Hello MapReduce bye MapReduce

样例输出如下所示。

MapReduce file1.txt:1;file2.txt:1;file3.txt:2;
Is file1.txt:1;file2.txt:2;
Simple file1.txt:1;file2.txt:1;
Powerful file2.txt:1;
Hello file3.txt:1;
Bye file3.txt:1;

二、实验过程

请提供相应Java代码及程序运行界面截图证明。
1、打开hadoop和hdfs

cd /usr/local/hadoop
 ./sbin/start-dfs.sh
 cd ..
 cd hbase
 bin/start-hbase.sh

在这里插入图片描述
2、在伪分布式下创建文件夹invertedindexinput

./bin/hdfs dfs -mkdir invertedindexinput

在这里插入图片描述
3、创建并编辑文件filed.txt、filee.txt、filef.txt文本文件

gedit filed.txt
gedit filee.txt
gedit filef.txt

在这里插入图片描述

4、把filed.txt、filee.txt、filef.txt文本文件上传到伪分布式下

./bin/hdfs dfs -put ./filed.txt invertedindexinput
./bin/hdfs dfs -put ./filee.txt invertedindexinput
./bin/hdfs dfs -put ./filef.txt invertedindexinput

在这里插入图片描述
5、localhost:50070端口查看目录/user/hadoop/invertedindexinput下我们刚才上传的文本文件
在这里插入图片描述

6、在eclipse下创建工程InvertedIndex用来做倒排索引
在这里插入图片描述

7、InvertedIndexMapper.java程序代码如下

package cn.demo.hadoop.mr.invertedIndex;

import java.io.IOException;

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;

public class InvertedIndexMapper extends Mapper<LongWritable, Text, Text, Text>{

private static Text keyInfo = new Text();// 存储单词和 URL 组合  
 private static final Text valueInfo = new Text("1");// 存储词频,初始化为1  
 @Override 
 protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { 
	 String line = value.toString(); 
	 String[] fields = line.split(" ");// 得到字段数组  
	 FileSplit fileSplit = (FileSplit) context.getInputSplit();// 得到这行数据所在的文件切片 
	 String fileName = fileSplit.getPath().getName();// 根据文件切片得到文件名  
	 for (String field : fields) { 
		 // key值由单词和URL组成,如“MapReduce:file1”  
		 keyInfo.set(field + ":" + fileName); 
		 context.write(keyInfo, valueInfo);
		 } 
	 } 
 }

在这里插入图片描述
8、InvertedIndexCombiner.java程序代码如下

package cn.demo.hadoop.mr.invertedIndex;
 
import java.io.IOException;
 
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
 
public class InvertedIndexCombiner extends Reducer<Text, Text, Text, Text>{
	private static Text info = new Text();
	// 输入: <MapReduce:file3 {1,1,...}>  
	// 输出:<MapReduce file3:2>  
	@Override 
	protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { 
		int sum = 0;// 统计词频  
		for (Text value : values) { 
			sum += Integer.parseInt(value.toString());
			} 
		int splitIndex = key.toString().indexOf(":"); 
		// 重新设置 value 值由 URL 和词频组成  
		info.set(key.toString().substring(splitIndex + 1) + ":" + sum); 
		// 重新设置 key 值为单词 
		key.set(key.toString().substring(0, splitIndex)); 
		context.write(key, info); 
		} 
	}

在这里插入图片描述
9、InvertedIndexReducer.java程序代码如下

package cn.demo.hadoop.mr.invertedIndex;
 
import java.io.IOException;
 
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
 
public class InvertedIndexReducer extends Reducer<Text, Text, Text, Text>{
	private static Text result = new Text();
	// 输入:<MapReduce file3:2>  
	// 输出:<MapReduce file1:1;file2:1;file3:2;>  
@Override 
protected void reduce(Text key, Iterable<Text> values, Context context)  throws IOException, InterruptedException { 
	// 生成文档列表 
	String fileList = new String(); 
for (Text value : values) { 
	fileList += value.toString() + ";"; 
	} 
result.set(fileList); 
context.write(key, result); 
} 
}

在这里插入图片描述
10、InvertedIndexRunner.java程序代码如下

package cn.demo.hadoop.mr.invertedIndex;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
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;

public class InvertedIndexRunner {
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJarByClass(InvertedIndexRunner.class);
		job.setMapperClass(InvertedIndexMapper.class);
		job.setCombinerClass(InvertedIndexCombiner.class);
		job.setReducerClass(InvertedIndexReducer.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		FileInputFormat.setInputPaths(job, new Path("hdfs://localhost:9000/user/hadoop/invertedindexinput"));
		// 指定处理完成之后的结果所保存的位置
		FileOutputFormat.setOutputPath(job, new Path("hdfs://localhost:9000/user/hadoop/invertedindexoutput"));
		// 向 yarn 集群提交这个 job
		boolean res = job.waitForCompletion(true);
		System.exit(res ? 0 : 1);
		}
	}

在这里插入图片描述
11、编译运行查看locaihost:50070端口/user/hadoop/invertedindexoutput目录下运行自动产生的内容如下
在这里插入图片描述

12、在伪分布式下查看invertedindexoutput/part-r-00000的结果如下

../bin/hdfs dfs -cat invertedindexoutput/part-r-00000

在这里插入图片描述
完成,加油!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_44830040/article/details/105805413