基于hadoop搜索引擎实践——生成倒排表文件(三)
来源:互联网 发布:新破天一剑淘宝 编辑:程序博客网 时间:2024/05/20 09:21
1.源文件过滤
在对源文件进行功能性处理之前,有必要对生成的源文件进行一次预分析和过滤。
(1)去重,过滤掉爬取过程中重复的帖子,保持帖子的唯一性。
(2)过滤不符合要求的帖子,比如获取的信息不能正常转为json格式的数据。内容全部为空的数据等。
这部分过滤处理相对简单,在map阶段,把帖子的url作为key,map中的value仍为value,组成<key,value>传输到reduce中。在reduce接段,同一个key,只输出一次。代码如下:
public static class RemoveRepeatMapper extends Mapper<LongWritable, Text, Text, Text>{ private 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); context.write(new Text(bbs.getUrl()), value); } } public static class RemoveRepeatReducer extends Reducer<Text, Text, NullWritable, Text>{ @Override protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { while(values.iterator().hasNext()){ context.write(NullWritable.get(), values.iterator().next()); break; } } }
2.生成倒排索引文件
倒排文件使用文档中所含有的关键词作为索引,把文档作为索引目标的一种结构(类似于有些纸质书籍的索引附录中,用关键词做索引,书的页面是索引目标)。这部分工作中是整个系统的重点,大致工作过程有如下3步。
<1>对已过滤的源文件中的每条记录进行切分,并将每条记录中的title和content转化为一组词的集合。
<2>为了在后期能够对用户查询的结果进行排序并显示摘要,在对帖子分词过程中,还需要计算出每个索引词对该帖子的相关度(Rank),以及在该帖子中出现的位置(Position).
<3>在完成上述的分析和准备工作之后,设计MapReduce算法,把帖子和索引词之间的映射转化为索引词到帖子的映射,并在此过程中计算并统计索引词相关帖子的Rank和Position,由此生成的文件成为倒排表。
(1)分词
获取的帖子内容可能是中文和英文,在英文中是通过空格分隔,而在中文中的词汇大多数由两个或者两个以上的汉字组成,并且语句是连续书写的。在对中文文本进行自动分析前,需要将整句切割成小的词汇但愿,即中文分词(或中文切词),被系统采用开源分词软件IKAnalyzer.经过分词处理,一片帖子切分出来的有效的词语数量大约在及时到几百不等。
(2)索引词的Rank和position
计算并统计索引词相对于帖子的相关度(Rank)的目的是能够排序显示用户查询到结果帖子;记录索引词在该帖子中的位置(Posistion)用于显示查询结果时,能够生成该词在帖子中的部分摘要。
关于Rank的计算有Google著名的PageRank算法,该算法的主要思路是越链接的次数越多的网页,其重要程度和知名程度越高,相应的Rank值也就越高。而本系统是一条条帖子,这些帖子基本都是独立的,且帖子与帖子之间几乎不存在网页上的链接关系。因此本系统并没有采用PageRank算法,而是针对自身的特点采用改进的TF-IDF算法用于计算Rank值。
TF-IDF(Term Frequency-Inverse Document Frequency)算法的大致思想有亮点。第一,如果一个词在某个文档中出现的频率越高,那么这个词语与这边文档的相关度(rank)也就越高;第二,如果一个词在越多的文档中出现,则该词用于区分文档相关性的作用也就越小。TF-IDF算法的公式描述如下
式中,式(1)中的表示词t在文档n中出现的次数,表示文档n中词的总个数;式(2)中的|D|表示库中文档的总数目;表示包含词t的文档的数据;式总的是指词t与文档n的相关度
本系统改进的部分是将词出现在文档的区域(标题或者正文)加入计算Rank的考虑范畴,改进后的算法思想描述如下:
(1)令词i与帖子j的相关度表示为R,这个值越大表示越相关,初始为0
(2)统计词i在帖子j的标题中出现的次数,每次出现一次,则R的值增加5
(3)统计词i在帖子j的正文中出现的次数,每次出现一次,则R的值加1
(4)在所有帖子中统计出包含词i的帖子的数据,记为num
(5)最后计算出R的值等于R/num
相对于Rank的计算,记录Position则要容易得多,下面对此进行简单的介绍。
IKAnalzer分词软件在切分出每个词时,同时会输出这个词在帖子中出现的起始和结束为止(相对于帖子首部的偏移量)。因此,Position信息只要用两个整数表示即可,本系统用(start,end)来表示。
由于在MapReduce的计算过程中,需要在Map和Reduce阶段之间传递Rank和Position,因此本系统在将Rank和Position封装成类之后,继承了Hadoop提供的IO类中的Writable类,重新实现了一个Writable类RecordWritable ,用于封装并序列化传输Rank和Position的信息。类RecordWritable 的核心实现代码如下:
public class RecordWritable implements WritableComparable<RecordWritable> { private LongWritable DID = new LongWritable(); private FloatWritable rank = new FloatWritable(); private Text positions = new Text(); public RecordWritable() { } public RecordWritable(LongWritable DID, FloatWritable rank, Text positions) { set(DID, rank, positions); } public void set(LongWritable DID, FloatWritable rank, Text positions) { this.DID.set(Long.valueOf(DID.toString()).longValue()); this.rank.set(Float.valueOf(rank.toString()).floatValue()); this.positions.set(positions.toString()); } public void set(long DID, float rank, String positions) { this.DID.set(DID); this.rank.set(rank); this.positions.set(positions); } public void set(long DID, RankPosition rankPosition) { this.DID.set(DID); this.rank.set(rankPosition.getRank()); this.positions.set(rankPosition.getPositions()); } public void setDID(long DID) { this.DID.set(DID); } public void setRank(float rank) { this.rank.set(rank); } public void setPositions(Text positions) { this.positions.set(positions); } @Override public void readFields(DataInput in) throws IOException { // TODO Auto-generated method stub this.DID.readFields(in); this.rank.readFields(in); this.positions.readFields(in); } @Override public void write(DataOutput out) throws IOException { // TODO Auto-generated method stub this.DID.write(out); this.rank.write(out); this.positions.write(out); } public LongWritable getDID() { return DID; } public FloatWritable getRank() { return rank; } public Text getPositions() { return positions; } @Override public boolean equals(Object obj) { if (obj instanceof RecordWritable) { RecordWritable tmp = (RecordWritable) obj; return this.DID.equals(tmp.DID) && this.rank.equals(tmp.rank) && this.positions.equals(tmp.positions); } return false; } @Override public String toString() { return this.DID.toString() + ":" + this.rank.toString() + ":" + this.positions.toString(); } @Override public int compareTo(RecordWritable tmp) { return this.DID.compareTo(tmp.DID); }}
具体实现代码可以查看:
离线处理程序:http://download.csdn.net/detail/long1657/8059593
在线处理程序:http://download.csdn.net/detail/long1657/8059567
参考文献:
1.刘鹏,hadoop实战,电子工业出版社,2011.9
0 0
- 基于hadoop搜索引擎实践——生成倒排表文件(三)
- 基于hadoop搜索引擎实践——生成倒排表文件(四)
- 基于hadoop搜索引擎实践——生成倒排表文件(四)
- 基于hadoop搜索引擎实践——二级索引文件(五)
- 基于hadoop搜索引擎实践——总体概述(一)
- 基于hadoop搜索引擎实践——在线处理(六)
- 基于hadoop搜索引擎实践——总体概述(一)
- 基于hadoop搜索引擎实践——网页爬取(二)
- 基于hadoop搜索引擎实践——网页爬取(二)
- 基于Hadoop生态圈的数据仓库实践 —— 环境搭建(三)
- 基于Hadoop生态圈的数据仓库实践 —— ETL(三)
- 基于Hadoop生态圈的数据仓库实践 —— 进阶技术(三)
- 基于hadoop生态圈的数据仓库实践 —— OLAP与数据可视化(三)
- hadoop实践(三)hadoop 集群配置
- 这就是搜索引擎(三)——搜索引擎优化
- 基于Hadoop生态圈的数据仓库实践 —— 目录
- 基于Hadoop生态圈的数据仓库实践 —— ETL
- hadoop和hive的实践应用(二)——基于Hadoop的数据仓库工具hive搭建
- jquer mobile关于查找替换修改span style样式问题
- C++学习 C++中虚函数工作原理和(虚)继承类的内存占用大小计算
- PHP截取各种编码的汉字字符串
- 字符编码那些事儿(UTF-8,GBK,Unicode,ASCII)(二)
- java的数据类型
- 基于hadoop搜索引擎实践——生成倒排表文件(三)
- java学习--java回收机制
- 广告点击率预估中的特征选择
- 判断是否为手机号
- hdu 5074 Hatsune Miku(2014 鞍山现场赛)
- java 获取叶子节点
- listview定位到某一行位置
- 编程感想
- 安卓的事件处理