MapReduce编程(七) 倒排索引构建

一、倒排索引简介

倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。

以英文为例,下面是要被索引的文本:

T0="it is what it is"
T1="what is it"
T2="it is a banana"

我们就能得到下面的反向文件索引:

 "a":      {2}
 "banana": {2}
 "is":     {0, 1, 2}
 "it":     {0, 1, 2}
 "what":   {0, 1}

检索的条件”what”, “is” 和 “it” 将对应这个集合:{0, 1}&{0, 1, 2}& {0, 1, 2}={0,1}

对于中文分词,可以使用开源的中文分词工具,这里使用ik-analyzer。

准备几个文本文件,写入内容做测试。

file1.txt内容如下:

事实上我们发现,互联网裁员潮频现甚至要高于其他行业领域

file2.txt内容如下:

面对寒冬,互联网企业不得不调整人员结构,优化雇员的投入产出

file3.txt内容如下:

在互联网内部,由于内部竞争机制以及要与竞争对手拼进度

file4.txt内容如下:

互联网大公司职员虽然可以从复杂性和专业分工中受益
互联网企业不得不调整人员结构

二、添加依赖

出了hadoop基本的jar包意外,加入中文分词的lucene-analyzers-commonik-analyzers


   <!--Lucene分词模块-->
    <dependency>
      <groupId>org.apache.lucene</groupId>
      <artifactId>lucene-analyzers-common</artifactId>
      <version>6.0.0</version>
    </dependency>

 <!--IK分词 -->
    <dependency>
      <groupId>cn.bestwu</groupId>
      <artifactId>ik-analyzers</artifactId>
      <version>5.1.0</version>
    </dependency>

三、MapReduce程序

关于Lucene 6.0中IK分词的配置参考http://blog.csdn.net/napoay/article/details/51911875,MapReduce程序如下。

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 org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by bee on 4/4/17.
 */
public class InvertIndexIk {

    public static class InvertMapper extends Mapper<Object, Text, Text, Text> {

        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String filename = ((FileSplit) context.getInputSplit()).getPath().getName()
                    .toString();
            Text fname = new Text(filename);
            IKAnalyzer6x analyzer = new IKAnalyzer6x(true);
            String line = value.toString();
            StringReader reader = new StringReader(line);
            TokenStream tokenStream = analyzer.tokenStream(line, reader);
            tokenStream.reset();
            CharTermAttribute termAttribute = tokenStream.getAttribute
                    (CharTermAttribute.class);
            while (tokenStream.incrementToken()) {
                Text word = new Text(termAttribute.toString());
                context.write(word, fname);
            }
        }

    }

    public static class InvertReducer extends Reducer<Text, Text, Text, Text> {

        public void reduce(Text key, Iterable<Text> values,Reducer<Text,Text,
                Text,Text>.Context context) throws IOException, InterruptedException {
            Map<String, Integer> map = new HashMap<String, Integer>();
            for (Text val : values) {
                if (map.containsKey(val.toString())) {

                    map.put(val.toString(),map.get(val.toString())+1);

                } else {
                    map.put(val.toString(),1);
                }

            }
            int termFreq=0;
            for (String mapKey:map.keySet()){
                termFreq+=map.get(mapKey);
            }
            context.write(key,new Text(map.toString()+"  "+termFreq));
        }

    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        HadoopUtil.deleteDir("output");
        Configuration conf=new Configuration();

        String[] otherargs=new
                String[]{"input/InvertIndex",
                "output"};

        if (otherargs.length!=2){
            System.err.println("Usage: mergesort <in> <out>");
            System.exit(2);
        }

        Job job=Job.getInstance();
        job.setJarByClass(InvertIndexIk.class);
        job.setMapperClass(InvertIndexIk.InvertMapper.class);
        job.setReducerClass(InvertIndexIk.InvertReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        FileInputFormat.addInputPath(job,new Path(otherargs[0]));
        FileOutputFormat.setOutputPath(job,new Path(otherargs[1]));
        System.exit(job.waitForCompletion(true) ? 0: 1);

    }
}

四、运行结果

输出如下:

专业分工    {file4.txt=1}  1
中   {file4.txt=1}  1
事实上 {file1.txt=1}  1
互联网 {file1.txt=1, file3.txt=1, file4.txt=2, file2.txt=1}  5
人员  {file4.txt=1, file2.txt=1}  2
企业  {file4.txt=1, file2.txt=1}  2
优化  {file2.txt=1}  1
内部  {file3.txt=2}  2
发现  {file1.txt=1}  1
受益  {file4.txt=1}  1
复杂性 {file4.txt=1}  1
大公司 {file4.txt=1}  1
寒冬  {file2.txt=1}  1
投入产出    {file2.txt=1}  1
拼   {file3.txt=1}  1
潮   {file1.txt=1}  1
现   {file1.txt=1}  1
竞争对手    {file3.txt=1}  1
竞争机制    {file3.txt=1}  1
结构  {file4.txt=1, file2.txt=1}  2
职员  {file4.txt=1}  1
行业  {file1.txt=1}  1
裁员  {file1.txt=1}  1
要与  {file3.txt=1}  1
调整  {file4.txt=1, file2.txt=1}  2
进度  {file3.txt=1}  1
雇员  {file2.txt=1}  1
面对  {file2.txt=1}  1
领域  {file1.txt=1}  1
频   {file1.txt=1}  1
高于  {file1.txt=1}  1

结果有三列,依次为词项、词项在单个文件中的词频以及总的词频。

五、参考资料

1.https://zh.wikipedia.org/wiki/ 倒排索引

2. Lucene 6.0下使用IK分词器

时间: 2024-10-14 20:30:14

MapReduce编程(七) 倒排索引构建的相关文章

MapReduce编程之倒排索引

任务要求: //输入文件格式 18661629496 110 13107702446 110 1234567 120 2345678 120 987654 110 2897839274 18661629496 //输出文件格式格式 11018661629496|13107702446|987654|18661629496|13107702446|987654| 1201234567|2345678|1234567|2345678| 186616294962897839274|2897839274

Hadoop MapReduce编程 API入门系列之挖掘气象数据版本2(九)

下面,是版本1. Hadoop MapReduce编程 API入门系列之挖掘气象数据版本1(一) 这篇博文,包括了,实际生产开发非常重要的,单元测试和调试代码.这里不多赘述,直接送上代码. MRUnit 框架 MRUnit是Cloudera公司专为Hadoop MapReduce写的单元测试框架,API非常简洁实用.MRUnit针对不同测试对象使用不同的Driver: MapDriver:针对单独的Map测试  ReduceDriver:针对单独的Reduce测试    MapReduceDri

Hadoop MapReduce编程学习

一直在搞spark,也没时间弄hadoop,不过Hadoop基本的编程我觉得我还是要会吧,看到一篇不错的文章,不过应该应用于hadoop2.0以前,因为代码中有  conf.set("mapred.job.tracker", "192.168.1.2:9001");新框架中已改为 Yarn-site.xml 中的 resouceManager 及 nodeManager 具体配置项,新框架中历史 job 的查询已从 Job tracker 剥离,归入单独的mapre

MapReduce编程模型及其在Hadoop上的实现

转自:https://www.zybuluo.com/frank-shaw/note/206604 MapReduce基本过程 关于MapReduce中数据流的传输过程,下图是一个经典演示:  关于上图,可以做出以下逐步分析: 输入数据(待处理)首先会被切割分片,每一个分片都会复制多份到HDFS中.上图默认的是分片已经存在于HDFS中. Hadoop会在存储有输入数据分片(HDFS中的数据)的节点上运行map任务,可以获得最佳性能(数据TaskTracker优化,节省带宽). 在运行完map任务

[Hadoop入门] - 1 Ubuntu系统 Hadoop介绍 MapReduce编程思想

Ubuntu系统 (我用到版本号是140.4) ubuntu系统是一个以桌面应用为主的Linux操作系统,Ubuntu基于Debian发行版和GNOME桌面环境.Ubuntu的目标在于为一般用户提供一个最新的.同时又相当稳定的主要由自由软件构建而成的操作系统,它可免费使用,并带有社团及专业的支持应. 作为Hadoop大数据开发测试环境, 建议大家不要在windows上安装CgyWin来学习或研究, 直接用Vmware+ubuntu来学习. 下载 www.vmware.com这里下载vmware,

Hadoop 实践(二) Mapreduce 编程

Mapreduce 编程,本文以WordCount  为例:实现文件字符统计 在eclipse 里面搭建一个java项目,引入hadoop lib目录下的jar,和 hadoop主目录下的jar. 新建WordCount 类: package org.scf.wordcount; import java.io.IOException; import java.util.*; import org.apache.hadoop.fs.Path; import org.apache.hadoop.co

MapReduce编程实战之“高级特性”

本篇介绍MapReduce的一些高级特性,如计数器.数据集的排序和连接.计数器是一种收集作业统计信息的有效手段,排序是MapReduce的核心技术,MapReduce也能够执行大型数据集间的""连接(join)操作. 计数器 计数器是一种收集作业统计信息的有效手段,用于质量控制或应用级统计.计数器还可用于辅助诊断系统故障.对于大型分布式系统来说,获取计数器比分析日志文件容易的多. 示例一:气温缺失及不规则数据计数器 import java.io.IOException; import

Hadoop MapReduce编程 API入门系列之压缩和计数器(三十)

不多说,直接上代码. Hadoop MapReduce编程 API入门系列之小文件合并(二十九) 生成的结果,作为输入源. 代码 package zhouls.bigdata.myMapReduce.ParseTVDataCompressAndCounter; import java.net.URI; import java.util.List;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.conf.Co

MapReduce编程(六) 从HDFS导入数据到Elasticsearch

一.Elasticsearch for Hadoop安装 Elasticsearch for Hadoop并不像logstash.kibana一样是一个独立的软件,而是Hadoop和Elasticsearch交互所需要的jar包.所以,有直接下载和maven导入2种方式.安装之前确保JDK版本不要低于1.8,Elasticsearch版本不能低于1.0. 官网对声明是对Hadoop 1.1.x.1.2.x.2.2.x.2.4.x.2.6.x.2.7.x测试通过,支持较好,其它版本的也并不是不能用