MapReduce经典案例——倒排索引

MapReduce经典案例————倒排索引

一、案例分析

1、倒排索引介绍:

  • 倒排索引是文档检索系统中最常用的数据结构,被广泛应用于全文搜索引擎。
  • 倒排索引主要用来存储某个单词(或词组)在一组文档中的存储位置的映射,提供了可以根据内容来查找文档的方式,而不是根据文档来确定内容,因此称为倒排索引(Inverted Index)。
  • 带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(Inverted File)。
  • image-20240419104220455

2、案例需求及分析

  • 现假设有三个源文件file1.txt、file2.txt和file3.txt,需要使用倒排索引的方式对这三个源文件内容实现倒排索引,并将最后的倒排索引文件输出。
  • image-20240419104508376

3、测试文档:

  • file1.txt:

    MapReduce is simple

  • file2.txt:

    MapReduce is powerful is simple

  • file3.txt:

    Hello MapReduce bye MapReduce

二、案例实现

1、Map阶段实现:

  • 使用Eclipse开发工具打开之前创建的Maven项目HadoopDemo,并且新创建cn.itcast.mr.invertedIndex包,在该路径下编写自定义Mapper类InvertedIndexMapper

  • 主要用于将文本中的单词按照空格进行切割,并以冒号拼接,“单词:文档名称”作为key,单词次数作为value,都以文本方式输出至Combine阶段。

  • InvertedIndexMapper.java:

    package cn.itcast.mr.invertedIndex;
    //Map阶段实现
    
    import java.io.IOException;
    import org.apache.commons.lang.StringUtils;
    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 = StringUtils.split(line, " ");// 得到字段数组
            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);
            }
        }
    }
    

2、Combine阶段实现

  • 根据Map阶段的输出结果形式,在cn.itcast.mr.InvertedIndex包下,自定义实现Combine阶段的类InvertedIndexCombiner,对每个文档的单词进行词频统计。

  • InvertedIndexCombiner.java:

    package cn.itcast.mr.invertedIndex;
    //Combine阶段实现
    
    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);
        }
    }
    

3、Reduce阶段实现

  • 根据Combine阶段的输出结果形式,同样在cn.itcast.mr.InvertedIndex包下,自定义Reducer类InvertedIndexMapper

  • 主要用于接收Combine阶段输出的数据,并最终案例倒排索引文件需求的样式,将单词作为key,多个文档名称和词频连接作为value,输出到目标目录。

  • InvertedIndexMapper.java:

    package cn.itcast.mr.invertedIndex;
    //Map阶段实现
    
    import java.io.IOException;
    import org.apache.commons.lang.StringUtils;
    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 = StringUtils.split(line, " ");// 得到字段数组
            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);
            }
        }
    }
    

4、Driver程序主类实现

  • 编写MapReduce程序运行主类InvertedIndexDriver,主要用于设置MapReduce工作任务的相关参数,由于本次演示的数据量较小,为了方便、快速进行案例演示,本案例采用了本地运行模式

  • 指定的本地E:\hadoop\fileStorage\InvertedIndexes\input目录下的源文件(需要提前准备)实现倒排索引,并将结果输入到本地E:\hadoop\fileStorage\InvertedIndexes\output\index目录下。

  • InvertedIndexDriver.java:

    package cn.itcast.mr.invertedIndex;
    //Driver程序主类实现
    
    import java.io.IOException;
    import org.apache.hadoop.conf.Configuration;
    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 InvertedIndexDriver {
        public static void main(String[] args) throws IOException,
                ClassNotFoundException, InterruptedException {
            Configuration conf = new Configuration();
            Job job = Job.getInstance(conf);
    
            job.setJarByClass(InvertedIndexDriver.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("E:\\hadoop\\fileStorage\\InvertedIndexes\\input"));
            // 指定处理完成之后的结果所保存的位置
            FileOutputFormat.setOutputPath(job, new Path("E:\\hadoop\\fileStorage\\InvertedIndexes\\output\\index"));
    
            // 向 yarn 集群提交这个 job
            boolean res = job.waitForCompletion(true);
            System.exit(res ? 0 : 1);
        }
    }
    

三、效果展示

1、查看本地文件:

image-20240419122828272

2、打开part-r-00000:

image-20240419122917009

FINISH

posted @ 2024-04-19 12:32  朝暮青丝  阅读(112)  评论(0编辑  收藏  举报