简要的介绍搜索引擎的原理,然后在本机实现了一个较为简单的搜索引擎。主要的任务就是设计一个爬虫,然后整理和存储爬取的网页内容,分析链接,当有用户查询的时候根据按照一定的原则返回相应网址。因为任务就分为以下几个部分,抓取网页,分析网页,存储网页和相关内容,根据查询返回结果。
网页抓取的任务,需要使用到python的urllib2库,用于获取网页,需要注意的是在抓取的时候可能会因为网络延迟等原因而失败,因为在抓取一个网页的时候需要多尝试几次。
网页分析当然是首推BeautifulSoup,可以分析一个网页形成一个DOM,按照属性查找,也可以按照节点在网络的中的顺序挨个访问非常方便。在一个网页中有各种各样的内容,比如标题,段落中的文字,超链接,锚文本等等。不同的内容有不同的作用,例如在一般情况下网页内容跟标题有很大的关系,每个段落第一句在这个段落中的重要性比较高,超链接可以用于获取跟这个网页所指向的网页,获得这个网页和其他网页的关联,而锚文本则标明了这个url所指向的链接的主题。
存储的内容包含已经访问过的网页,已经访问过的网页的内容,链接之间的关系,链接两个网页的锚文本,所遇到的每个单词。所有存储的这些内容都有着不同的用处。存储访问过的网页时为了避免重复访问某个url,除了使用字符串的方式来存储已经访问的网页,也可以使用字符指纹的方式来存储,这样在url很长的情况下可以显著额降低数据库的大小。已经访问过的网页的内容,主要是单词的信息,单词在哪个url中出现,单词的位置信息,在某种程度上单词的位置也体现了单词的重要程度,因此需要记录。当不使用数据库来记录这些信息的时候,可以使用倒排索引来存储这些信息,然后就是周期性的更新这些数据库了。链接之间的关系是指链接引用另一个链接这种关系。这种关系在最终计算PageRank是需要使用到,现在必须先存储。锚文本信息,用于将两个网页连接起来的文字信息,在某种程度上指明了网页之间的主题相关性,是很重要的信息。单词信息就是出去停用词之后所遇到的新单词,每个单词给一个单词id,方便引用的。
根据查询返回相关的结果。这个问题的深度和广度那是相当之大啊,涉及到很多的内容,几本书都讲不完的,这里使用相当简单的方法来对返回的结果进行排序。网页内容相关的部分,PageRank的得分,根据用户返回的点击结果这几个大类来给出最后的综合得分。在综合各种打分的时候,一个很重要的做法就是normalization。有一些函数给出的分值在绝对值上可能会大过另外一些函数给出的分值,这个时候分值高的项目在总体的比重就会增大,使得绝对值小的项目对结果的影响减小,需要将不同函数的得分区间划分为同一个得分区间。在某个测试项目中,分数越高越好,而在另一些里则是越低越好,所以需要统一方向,比如统一改为分值越高越好或者是越低越好。上面提到的两种方法都是normalization需要考虑到的问题。
基于网页内容的得分。评分的包括query出现在玩各种的频率,query出现在网页中的位置,指向网页的锚文本跟query是否相关等内容。
基于PageRank的得分。这种评分的想法很简单,加入现在已经已知了一些网页的重要性,判断一个新的网页的重要性可以根据这个网页是否被重要的网页所引用,引用的次数来判定,如果一个网页被不同的重要网页应用,引用的次数越多越能说明目前这个网页的重要性。但是问题我们对所有网页的重要性都一无所知,如何bootstrap?这里我觉得类似于k-means的方法,首先每个网页都被赋予一个初始值,然后通过多次迭代,每次都对所有的网页应用PageRank算法,然后即可获得每个每个网页的PageRank得分。
点击得分,事实上是借助于用户的反馈来修改返回的结果,使用ANN的方法来训练。觉得这里的难点是如何决定输入节点,隐含节点,输出节点的个数。如果把所有的字都作为输入节点,那么这个ANN的规模就相当的将大大了,所有选择了跟query相关的词作为输入节点,每个查询建立一个隐含节点,并且建立一个输入层到隐含层的链接,是从每一个查询单词到为这个query而建立的隐含节点,然后每个可能的url作为输出节点,建立隐含层到输出层的节点链接。每个首先建立的初始链接权值都设置为固定的值,根据用户所点击的url,训练网络,输出可能的权值。
最后对每个大类的重要性做出评价,将得分线性组合,然后输出每个url的得分,输出排序结果。