在 上一部分 中,您了解到如何编写一个 spider 程序来进行网页的爬取,做为 spider 的爬取结果,咱们得到了一个按照必定格式存储的原始网页库,原始网页库也是咱们第二部分网页预处理的数据基础。网页预处理的主要目标是将原始网页经过一步步的数据处理变成可方便搜索的数据形式。下面就让咱们逐步介绍网页预处理的设计和实现。html
预处理模块的总体结构java
预处理模块的总体结构以下:mysql
经过 spider 的收集,保存下来的网页信息具备较好的信息存储格式,可是仍是有一个缺点,就是不能按照网页 URL 直接定位到所指向的网页。因此,在第一个流程中,须要先创建网页的索引,如此经过索引,咱们能够很方便的从原始网页库中得到某个 URL 对应的页面信息。以后,咱们处理网页数据,对于一个网页,首先须要提取其网页正文信息,其次对正文信息进行分词,以后再根据分词的状况创建索引和倒排索引,这样,网页的预处理也所有完成。可能读者对于其中的某些专业术语会有一些不明白之处,在后续详述各个流程的时候会给出相应的图或者例子来帮助你们理解。正则表达式
回页首算法
创建索引网页库sql
原始网页库是按照格式存储的,这对于网页的索引创建提供了方便,下图给出了一条网页信息记录:数据库
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // 以前的记录 version:1.0 // 记录头部 url:http://ast.nlsde.buaa.edu.cn/ date:Mon Apr 05 14:22:53 CST 2010 IP:218.241.236.72 length:3981 <!DOCTYPE …… // 记录数据部分 <html> …… </html> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // 以后的记录 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
咱们采用“网页库名—偏移”的信息对来定位库中的某条网页记录。因为数据量比较大,这些索引网页信息须要一种保存的方法,dySE 使用数据库来保存这些信息。数据库们采用 mysql,配合 SQL-Front 软件能够轻松进行图形界面的操做。咱们用一个表来记录这些信息,表的内容以下:url、content、offset、raws。URL 是某条记录对应的 URL,由于索引数据库创建以后,咱们是经过 URL 来肯定须要的网页的;raws 和 offset 分别表示网页库名和偏移值,这两个属性惟一肯定了某条记录,content 是网页内容的摘要,网页的数据量通常较大,把网页的所有内容放入数据库中显得不是很实际,因此咱们将网页内容的 MD5 摘要放入到 content 属性中,该属性至关于一个校验码,在实际运用中,当咱们根据 URL 得到某个网页信息是,能够将得到的网页作 MD5 摘要而后与 content 中的值作一个匹配,若是同样则网页获取成功,若是不同,则说明网页获取出现问题。编程
这里简单介绍一下 mySql 的安装以及与 Java 的链接:安全
介绍了数据库的相关操做时候,如今咱们能够来完成网页索引库的创建过程。这里要说明的是,第一条记录的偏移是 0,因此在当前记录 record 处理以前,该记录的偏移是已经计算出来的,处理 record 的意义在于得到下一个记录在网页库中的偏移。假设当前 record 的偏移为 offset,定位于头部的第一条属性以前,咱们经过读取记录的头部和记录的数据部分来获得该记录的长度 length,从而,offset+length 即为下一条记录的偏移值。读取头部和读取记录都是经过数据间的空行来标识的,其伪代码以下:网络
For each record in Raws do begin 读取 record 的头部和数据,从头部中抽取 URL; 计算头部和数据的长度,加到当前偏移值上获得新的偏移; 从 record 中数据中计算其 MD5 摘要值; 将数据插入数据库中,包括:URL、偏移、数据 MD5 摘要、Raws; end; |
您可能会对 MD5 摘要算法有些疑惑,这是什么?这有什么用? Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域普遍使用的一种散列函数,用以提供消息的完整性保护。MD5 的典型应用是对一段信息 (Message) 产生一个 128 位的二进制信息摘要 (Message-Digest),即为 32 位 16 进制数字串,以防止被篡改。对于咱们来讲,好比经过 MD5 计算,某个网页数据的摘要是 00902914CFE6CD1A959C31C076F49EA8,若是咱们任意的改变这个网页中的数据,经过计算以后,该摘要就会改变,咱们能够将信息的 MD5 摘要视做为该信息的指纹信息。因此,存储该摘要能够验证以后获取的网页信息是否与原始网页一致。
对 MD5 算法简要的叙述能够为:MD5 以 512 位分组来处理输入的信息,且每一分组又被划分为 16 个 32 位子分组,通过了一系列的处理后,算法的输出由四个 32 位分组组成,将这四个 32 位分组级联后将生成一个 128 位散列值。其中“一系列的处理”即为计算流程,MD5 的计算流程比较多,可是不难,同时也不难实现,您能够直接使用网上现有的 java 版本实现或者使用本教程提供的源码下载中的 MD5 类。对于 MD5,咱们知道其功能,能使用就能够,具体的每一个步骤的意义不须要深刻理解。
在正文信息抽取以前,咱们首先须要一个简单的工具类,该工具类能够取出数据库中的内容而且去原始网页集中得到网页信息,dySE 对于该功能的实如今 originalPageGetter.java 中,该类经过 URL 从数据库中得到该 URL 对应的网页数据的所在网页库名以及偏移,而后就能够根据偏移来读取该网页的数据内容,一样以原始网页集中各记录间的空行做为数据内容的结束标记,读取内容以后,经过 MD5 计算当前读取的内容的摘要,校验是否与以前的摘要一致。对于偏移的使用,BufferedReader 类提供一个 skip(int offset) 的函数,其做用是跳过文档中,从当前开始计算的 offset 个字符,用这个函数咱们就能够定位到咱们须要的记录。
public String getContent(String fileName, int offset) { String content = ""; try { FileReader fileReader = new FileReader(fileName); BufferedReader bfReader = new BufferedReader(fileReader); bfReader.skip(offset); readRawHead(bfReader); content = readRawContent(bfReader); } catch (Exception e) {e.printStackTrace();} return content; } |
上述代码中,省略了 readRawHead 和 readRawContent 的实现,这些都是基本的 I/O 操做,详见所附源码。
对于得到的单个网页数据,咱们就能够进行下一步的处理,首先要作的就是正文内容的抽取,从而剔除网页中的标签内容,这一步的操做主要采用正则表达式来完成。咱们用正则表达式来匹配 html 的标签,而且把匹配到的标签删除,最后,剩下的内容就是网页正文。限于篇幅,咱们以过滤 script 标签为示例,其代码以下 :
public String html2Text(String inputString) { String htmlStr = inputString; // 含 html 标签的字符串 Pattern p_script; Matcher m_script; try { String regEx_script = "<script[^>]*?>[\\s\\S]*?</script>"; p_script = Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE); m_script = p_script.matcher(htmlStr); htmlStr = m_script.replaceAll(""); // 过滤 script 标签 }catch(Exception e) {e.printStackTrace();} return htmlStr;// 返回文本字符串 } |
经过一系列的标签过滤,咱们能够获得网页的正文内容,就能够用于下一步的分词了。
中文分词是指将一个汉字序列切分红一个一个单独的词,从而达到计算机能够自动识别的效果。中文分词主要有三种方法:第一种基于字符串匹配,第二种基于语义理解,第三种基于统计。因为第二和第三种的实现须要大量的数据来支持,因此咱们采用的是基于字符串匹配的方法。
基于字符串匹配的方法又叫作机械分词方法,它是按照必定的策略将待分析的汉字串与一个“充分大的”机器词典中的词条进行配,若在词典中找到某个字符串,则匹配成功(识别出一个词)。按照扫描方向的不一样,串匹配分词方法能够分为正向匹配和逆向匹配;按照不一样长度优先匹配的状况,能够分为最大(最长)匹配和最小(最短)匹配。经常使用的几种机械分词方法以下:
咱们采用其中的正向最大匹配法。算法描述以下:输入值为一个中文语句 S,以及最大匹配词 n
须要说明的是,在第三步的起始,n 若是不为 1,则意味着有匹配到的词;而若是 n 为 1,咱们默认 1 个字是应该进入分词结果的,因此第三步能够将前 n 个字做为一个词而分割开来。还有须要注意的是对于停用词的过滤,停用词即汉语中“的,了,和,么”等字词,在搜索引擎中是忽略的,因此对于分词后的结果,咱们须要在用停用词列表进行一下停用词过滤。
您也许有疑问,如何得到分词字典或者是停用词字典。停用词字典比较好办,因为中文停用词数量有限,能够从网上得到停用词列表,从而本身建一个停用词字典;然而对于分词字典,虽然网上有许多知名的汉字分词软件,可是不多有分词的字典提供,这里咱们提供一些在 dySE 中使用的分词字典给您。在程序使用过程当中,分词字典能够放入一个集合中,这样就能够比较方便的进行比对工做。
分词的结果对于搜索的精准性有着相当重要的影响,好的分词策略常常是由若干个简单算法拼接而成的,因此您也能够试着实现双向最大减字匹配法来提升分词的准确率。而若是遇到歧义词组,能够经过字典中附带的词频来决定哪一种分词的结果更好。
这个章节咱们为您讲解预处理模块的最后两个步骤,索引的创建和倒排索引的创建。有了分词的结果,咱们就能够得到一个正向的索引,即某个网页以及其对应的分词结果。以下图所示:
在本文的开头,咱们创建了索引网页库,用于经过 URL 能够直接定位到原始网页库中该 URL 对应的数据的位置;而如今的正向索引,咱们能够经过某个网页的 URL 获得该网页的分词信息。得到正向索引看似对于咱们的即将进行的查询操做没有什么实际的帮助,由于查询服务是经过关键词来得到网页信息,而正向索引并不能经过分词结果反查网页信息。其实,咱们创建正向索引的目的就是经过翻转的操做创建倒排索引。所谓倒排就是相对于正向索引中网页——分词结果的映射方式,采用分词——对应的网页这种映射方式。与图 2 相对应的倒排索引如上图 3 所示。
接下来咱们分析如何从正向索引来获得倒排索引。算法过程以下:
创建倒排索引的算法不难实现,主要是其中数据结构的选用,在 dySE 中,正向索引和倒排索引都是采用 HashMap 来存储,映射中正向索引的键是采用网页 URL 对应的字符串,而倒排索引是采用分词词组,映射中的值,前者是一个分词列表,后者是一个 URL 的字符串列表。这里能够采用一个优化,分别创建两个表,按照标号存储分词列表和 URL 列表,这样,索引中的值就可使用整型变量列表来节省空间。
到目前为止,虽然咱们尚未正式的查询输入界面以及结果返回页面,但这丝绝不影响咱们来对咱们的搜索引擎进行初步的实验。在倒排索引创建之后,咱们在程序中得到一个倒排索引的实例,而后定义一个搜索的字符串,直接在倒排索引中遍历这个字符串,而后返回该词组所指向的倒排索引中的 URL 列表便可。
网页的预处理是搜索引擎的核心部分,创建索引网页库是为了网页数据更方便的从原始网页库中获取,而抽取正文信息是后续操做的基础。从分词开始就正式涉及到搜索引擎中文本数据的处理,分词的好坏以及效率很大程度上决定着搜索引擎的精确性,是很是须要关注的一点,而倒排索引时根据分词的结果创建的一个“词组——对应网页列表”映射,倒排索引是网页搜索的最关键数据结构,搜索引擎执行的速度与倒排索引的创建以及倒排索引的搜索方式息息相关。
在本系列的第三部分中,您将了解到如何从建立网页,从网页中输入查询信息经过倒排索引的搜索完成结果的返回,而且完成网页排名的功能。
学习