倒排索引的mapreduce的简单实现

1、倒排索引

  1. 概述:
    1. 正向索引:例如:可以通过文件名,是否包含给定的关键词
      1. 注意:在生活中,一般都是通过关键字查找在哪个文本中。
    2. 反向索引:以关键字为索引,去索引这个关键字在那些文件中存在。
      1. 以关键字查找比较方便,反向索引更适用于全文搜索。
      2. 实例:以关键字查找网站采用倒排索引方式。
    3. 倒排索引定义:
      1. 官方定义:也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。
      2. 定义:以关键字进行创建索引,索引的是当前的关键字在哪一篇文章,或哪一组文章中出现的位置
  2. 案例
    1. 需求:编写MapReduce程序求出以下格式的结果数据:
      1. 创建倒排索引
      2. 统计每个关键字在每个文档中的第几个偏移量开始出现了多少次
    2. 要求字段:关键字、文件名、行数、在本行出现的次数
    3. 解题思路分析:
      1. map端
        1. key 检索关键字
        2. value 文件名+行数+次数
        3. map端还需要进行文件名称的获取,需要重写setup方法
      2. reduce端:相同关键词统计一次,接受的数据是相同关键词的所有数据、进行拼接。
    4. 代码实现:
      1. map端代码实现:
public class InvertedIndexMapper extends Mapper<LongWritable, Text, Text, Text> {
	private String filename = null;
	private Text mk = new Text();

	@Override
	protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
			throws IOException, InterruptedException {
		String[] infos = value.toString().split(" ");
		int count = 0;
		// 统计每一个关键字在这一行出现的次数
		Map<String, Integer> map = new HashMap<String, Integer>();
		for (String word : infos) {
			if (map.containsKey(word)) {
				map.put(word, map.get(word) + 1);
			} else {
				map.put(word, 1);
			}
		}
		Set<String> keys = map.keySet();
		for (String ks : keys) {
			mk.set(ks);
			String v = filename + "," + key + "," + map.get(ks);
			context.write(mk, new Text(v));
		}
	}

	@Override
	protected void setup(Mapper<LongWritable, Text, Text, Text>.Context context)
			throws IOException, InterruptedException {
		// 获取文件名
		FileSplit fileSplit = (FileSplit) context.getInputSplit();
		filename = fileSplit.getPath().getName();
	}
	
}
      1. reduce端代码实现
public class InvertedIndexReducer extends Reducer<Text, Text, Text, Text> {
	private Text rv = new Text();

	@Override
	protected void reduce(Text key, Iterable<Text> values, Reducer<Text, Text, Text, Text>.Context context)
			throws IOException, InterruptedException {
		StringBuffer sb = new StringBuffer();
		for (Text v : values) {
			String value = v.toString();
			sb.append(value).append(";");
		}
		rv.set(sb.substring(0, sb.length() - 1));
		context.write(key, rv);
	}
}
      1. 驱动类代码实现
public class Driver {

    	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    	Configuration conf = new Configuration();
    	Job job = Job.getInstance(conf);
    	job.setJarByClass(Driver.class);
    	job.setMapperClass(InvertedIndexMapper.class);
    	job.setReducerClass(InvertedIndexReducer.class);
    	job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		Path in = new Path("D:\\data\\day09\\invertedIndex");
		Path out = new Path("D:\\data\\day09\\invertedIndexOut");
		FileInputFormat.addInputPath(job, in);
		FileSystem fs = FileSystem.get(conf);
		if (fs.exists(out)) {
			fs.delete(out, true);
		}
		FileOutputFormat.setOutputPath(job, out);
		job.waitForCompletion(true);
	}

}
  1. 切片和切块的区别
    1. 应用场景上区分
      1. 切片针对于MapReduce的计算,对应maptask的个数-- 一个逻辑切片对应一个maptask个数
      2. 切块针对于hdfs的数据存储,切分成数据块
    2. 概念上区分
      1. 切片是逻辑概念,是数据偏移量的划分,没有进行物理切分。
      2. 切块是物理概念,物理上将用户数据切分成多个数据块,对数据真实的切分。

猜你喜欢

转载自blog.csdn.net/qq_29362113/article/details/89321462
今日推荐