MapReduce 基础案例 之 倒排索引

倒排索引

倒排索引是文档检索系统中最常用的数据结构,被广泛地应用于全文搜索引擎

倒排索引,不是按照每个文档中单词的字数来统计,而是反过来根据单词去不同文件中进行统计,故而称为倒排索引。

而在统计的过程中,单词在不同文件中还会带上一个权值,这个权值用来指出每个文档与搜索内容的相关度,经常是在文件中出现的次数

MapReduce 基础案例 之 倒排索引_第1张图片

MapReduce 基础案例 之 倒排索引_第2张图片

举例

index.html

hadoop hadoop hadoop hadoop index bigdata

hadoop.html

hadoop hadoop is nice nice best

spark.html

spark is best best best

将单词在文件中出现的次数作为权值,按照单词之间字典序升序的顺序,一个单词在文件中出现的次数降序输出

best         spark.html:3;hadoop.html:1;
bigdata    index.html:1;
hadoop    index.html:4;hadoop.html:2;
index       index.html:1;
is             spark.html:1;
nice         hadoop.html:2;
spark       spark.html:1;

代码思想

首先,我们想,需要三个信息。1.单词、2.文件名、3.词频

Map端

将单词+文件作为key,value设为固定值1

    · · ·

    · · ·

Combine端

将map端传过来的数据会先进行归并

>

>

>

    · · ·

类似于词频统计wordcount,将values中的多个1进行相加,得到次数

    · · ·

但不能直接将这种数据发送给Reduce端,因为,我们要以单词作为key,所以要进行拆分。将单词作为key,将文件名+次数作为value。

    · · ·

Reduce端

将Combine端传过来的数据又进行了归并

>

    · · ·

至此,基本输出格式已经确定。

但为了让中的顺序为,即出现次数多的文件在前,出现次数少的在后,降序排列。这里可以借鉴另一篇博客MapReduce 二次排序中的两种方法取其一。本帖用了TreeSet临时存储每个value,在TreeSet中排序,再遍历输出。因为归并后,每个单词对应的文件及出现次数,不会很多,数据结构能够装得下。

>

    · · ·

代码


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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


import java.io.IOException;
import java.util.Comparator;
import java.util.TreeSet;


public class Daopai {

    public static class MyMapper extends Mapper{
        public Text k = new Text();
        public Text v = new Text("1");
        public FileSplit split;
        @Override
        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            split = (FileSplit) context.getInputSplit();
            String name = split.getPath().getName();
            String row = value.toString();
            String[] words = row.split(" ");
            for (String word : words) {
                k.set(word+":"+name);
                context.write(k,v);
            }
        }
    }

    public static class MyCombiner extends Reducer{
        public Text k = new Text();
        public Text v = new Text();
        @Override
        protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {
            int count = 0;
            for (Text value : values) {
                count += Integer.parseInt(value.toString());
            }
            String[] keys = key.toString().split(":");
            k.set(keys[0]);
            v.set(keys[1]+":"+count);
            System.out.println(count);
            context.write(k,v);
        }
    }

    public static class MyReducer extends Reducer{
        public Text v = new Text();
        TreeSet set = new TreeSet(new MyComparator());
        public class MyComparator implements Comparator{
            @Override
            public int compare(String o1, String o2) {
                int i1 = Integer.parseInt(o1.split(":")[1]);
                int i2 = Integer.parseInt(o2.split(":")[1]);
                return i2 - i1;
            }
        }
        @Override
        protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {
            for (Text value : values) {
                set.add(value.toString());
            }
            String str = "";
            for (String s : set) {
                str += s + ";";
            }
            v.set(str);
            set.clear();
            context.write(key,v);
        }
    }

    public static void main(String[] args) throws IOException {
        try {
            //新建作业
            Job job = Job.getInstance(new Configuration(),"Daopai");
            //设置主类
            job.setJarByClass(Daopai.class);
            //设置map端
            job.setMapperClass(MyMapper.class);
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(Text.class);
            //设置reduce端
            job.setReducerClass(MyReducer.class);
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(Text.class);
            //设置combine端
            job.setCombinerClass(MyCombiner.class);
            //设置job输入输出路径
            FileInputFormat.addInputPath(job,new Path("/input/daopai/"));
            FileOutputFormat.setOutputPath(job,new Path("/output/mr/daopai/test1/"));
            //提交作业
            int success = job.waitForCompletion(true) ? 0 : 1;
            //退出
            System.exit(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

 

你可能感兴趣的:(Hadoop,#,MapReduce)