基于hadoop搜索引擎实践——生成倒排表文件(四)

来源:互联网 发布:淘宝如何修改折扣 编辑:程序博客网 时间:2024/06/06 04:02
2.3 建立倒排表文件(下面原理引用刘鹏hadoop实战)
    在分析完分词,Rank值得计算等问题的解决方案之后,就可以设计相应的MapReduce算法,来建立倒排表,计算,保存Rank和Position等附属信息。
    首先定义倒排表存储信息格式,这是算法的输出目标,也是查询程序从倒排表中获取信息的接口。本系统倒排表的存储格式定义如下:
    (1)倒排表文件(INVERTED_INDEX_FILE)有若干索引词记录组成,每个索引词记录(TERM_RECORD)是有一个索引词(TERM)和包含该词的所有帖子的信息(MULTI_INFO)组成,其中TERM和MULTI_INFO之间用空格隔开。索引词记录按照顺序追加的方式存放,之间用换行符分隔,例如:
    TERM+'\t'+MULTI_INFO+'\r\n'
    (2)在每条索引词记录中,TERM是用分词软件切分出来的一个词。而MULTI_INFO则由多个单条帖子信息(SINGLE_INFO)组成。其中SINGLE_INFO和SINGLE_INFO之间用分号隔开。表示如下:
    MULTI_INFO=SINGLE_INFO1;SINGLE_INFO2;……;SINGLE_INFONn
    (3)单条帖子信息SINGLE_INFO,由帖子ID(DID),索引词语该帖子的Rank值(Rank),索引词在该帖子中出现的位置(POSITIONS)组成,其间用冒号隔开。表示格式如下:
    SINGLE_INFO=DID:RANK:POSITIONS
    (4)SINGLE_INFO中的DID是唯一指定某个帖子的值。本系统选择原文件中帖子行首在原文件中的偏移量(offset)作为帖子ID(DID)。每个帖子的源文件中有唯一的偏移量,且给定一个偏移量offset后,可以通过在源文件中定位offset,并执行readline操作(帖子和帖子之间用换行符间隔的),即可读出这条帖子的信息。
    (5)SINGLE_INFO中的RANK用一个浮点类型的数值表示。
    (6)SINGLE_INFO中的POSITIONS由多个单个位置信息(POSITIONS)组成,之间用百分号隔开。表示格式如下:
    POSITIONS=POSITIONS1%POSITIONS2%……%POSITIONSn
    (7)对于单个位置信息(POSITION),其有标题记标识(ISTITLE),起始位置(START),结束为止(END)组成。之间用竖线隔开,表示格式如下:
    POSITIONS=ISTITLE|START|END
    下面给出一个索引词记录的存储实例
    黑莓    4852292:162.6:1|2|4%0|804|806;42910773:106.26:0|456|458%0|560|562
    该实例说明关键词“黑莓”在ID号为“48522292”和“42910773”的两个帖子中出现。在"48522292"中出现了两次,第一次的位置是在标题中,具体出现在第2-4位;第二次出现在正文中,具体出现在第804-806;该词相对于这个帖子的Rank值为162.6
    由于倒排表的信息来自于每条帖子,这些帖子可以并行地被处理,因此设计了基于MapReduce的并行算法来建立倒排表。算法描述如下

图1-1 MapReduce建立倒排表的流程图
    
建立倒排表的算法流程如下:
    (1)采用Hadoop默认的文件分给方式,将源文件分成若干个小文件,每个Mapper节点一次只处理一个小文件。
    (2)在Map阶段,对于每个小文件采用按行切分的方法输入。每个map函数的输入<key,value>分别是offset和line.其中offset作为key是指输出的这一行的行首相对于整个源文件的偏移量,也就是帖子的DID;line作为value是指输入的一行,在本系统也就是一条帖子,可以从中切分出帖子的TITLE和CONTENT。
    (3)对于输入的每条line(一条帖子),在map函数中切分出TITLE和CONTENT中的每个词(TERM)。对于每个词,根据其出现的情况计算出RANK和POSITIONS,将这些信息封装成一个SINGLE_INFO.输出阶段要发送k次(k是切分出来的TERM的个数),每次发射的key和value是TERM及其对应的SINGLE_INFO。
    (4)经过分区(Partion)阶段,从Map发射出来具有相同的key(TERM)的<key,value>对会分别发到同一个Reducer端,每个reduce函数会处理具有相同TERM的<key,value>对。
    (5)输入到每个reduce函数的相同TERM对应的SINGLE_INFO的数目就是包含这个TERM的帖子的数目,记为num.根据前面介绍的IT-IDF算法,在reduce函数里更新每个SINGLE_INFO里面的Rank值,更新的的公式为RANK=RANK/num.更新后的RANK值就是TERM相对于某个帖子的最终RANK值。
    核心代码如下:
 public static class InvertedIndexerMapper extends            Mapper<LongWritable, Text, Text, RecordWritable> {        public final static Text WORD = new Text();        public final static RecordWritable RECORD = new RecordWritable();        public final static Gson gson = new Gson();        @Override        protected void map(LongWritable key, Text value, Context context)                throws IOException, InterruptedException {            BBS bbs = gson.fromJson(value.toString(), BBS.class);            HashMap<String, RankPosition> map = new HashMap<String, RankPosition>();            StringReader title = new StringReader(bbs.getTitle());            IKSegmenter ik_title = new IKSegmenter(title, true);            Lexeme lex_title = new Lexeme(0, 0, 0, 0);            while ((lex_title = (ik_title.next())) != null) {                if (lex_title.getLength() >= 2) {                    String token = lex_title.getLexemeText();                    int start = lex_title.getBeginPosition();                    int end = lex_title.getEndPosition();                    if (!map.containsKey(token)) {                        map.put(token, new RankPosition(5, true, start, end));                    } else {                        map.put(token, map.get(token).add(5, true, start, end));                    }                }            }            StringReader content = new StringReader(bbs.getContent());            IKSegmenter ik_content = new IKSegmenter(content, true);            Lexeme lex_content = new Lexeme(0, 0, 0, 0);            while ((lex_content = ik_content.next()) != null) {                if (lex_content.getLength() >= 2) {                    String token = lex_content.getLexemeText();                    int start = lex_content.getBeginPosition();                    int end = lex_content.getEndPosition();                    if (!map.containsKey(token)) {                        map.put(token, new RankPosition(1, false, start, end));                    } else {                        map.put(token, map.get(token).add(1, false, start, end));                    }                }            }            EmitMapValue(map, key.get(), context);            map.clear();        }        public void EmitMapValue(HashMap<String, RankPosition> map,                long DID, Context context) throws IOException,                InterruptedException {            for (Map.Entry<String, RankPosition> entry : map.entrySet()) {                WORD.set(entry.getKey());                RECORD.set(DID, entry.getValue());                context.write(WORD, RECORD);            }        }    }    public static class InvertedIndexerReducer extends            Reducer<Text, RecordWritable, Text, Text> {        private final static Text OUT=new Text();        @Override        protected void reduce(Text key, Iterable<RecordWritable> values,                Context context) throws IOException, InterruptedException {            StringBuilder info = new StringBuilder();            List<RecordWritable> list=new ArrayList<RecordWritable>();                       while(values.iterator().hasNext()){                RecordWritable record=values.iterator().next();                RecordWritable recordWritable=new RecordWritable(record.getDID(), record.getRank(), record.getPositions());                list.add(recordWritable);            }            int sum=list.size();            for(int i=0;i<list.size();i++){                info.append(resetFinalRank(list.get(i), sum)+";");            }            OUT.set(info.toString());            context.write(key,OUT);        }        public String resetFinalRank(RecordWritable value, long num) {            value.setRank((float) (value.getRank().get() / num));            return value.toString();        }    }


具体实现代码可以查看:
    离线处理程序:http://download.csdn.net/detail/long1657/8059593
    在线处理程序:http://download.csdn.net/detail/long1657/8059567
参考文献:
1.刘鹏,hadoop实战,电子工业出版社,2011.9
0 0
原创粉丝点击