solr运行原理之倒排索引

最近在研究智能客服的相关技术,其中涉及到检索相关的技术,基于字面检索的倒排索引技术和基于语义检索的ANNOY技术,本篇博客,就以开源框架solr为例,详细讲解这方面的知识。

solr和elasticsearch、Lucene三者之间的关系

Lucene是一套信息检索工具包,并不包含搜索引擎系统,它包含了索引结构、读写索引工具、相关性工具、排序等功能,因此在使用Lucene时仍需要关注搜索引擎系统,例如数据获取、解析、分词等方面的东西。而solr和elasticsearch都是基于该工具包做的一些封装。

Solr是一个有HTTP接口的基于Lucene的查询服务器,封装了很多Lucene细节,自己的应用可以直接利用诸如 …/solr?q=abc 这样的HTTP GET/POST请求去查询,维护修改索引。

Elasticsearch也是一个建立在全文搜索引擎 Apache Lucene基础上的搜索引擎。采用的策略是分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索三者三者区别如下:

  • solr和elasticsearch都是基于Lucene实现的,其次,solr利用zookpper进行分布式管理,而elasticsearch自身带有分布式协调管理功能;
  • solr比elasticsearch实现更加全面,solr官方提供的功能更多,而elasticsearch本身更注 重于核心功能,高级功能多由第三方插件提供;
  • solr在传统的搜索应用中表现好于elasticsearch,而elasticsearch在实时搜索应用方面比solr表现好!

最后有必要说明一下传统搜索和实时搜索:
传统搜索是从静态数据库中筛选出符合条件的结果,这种结果往往是不可变得、静态的。而实时搜索则是说用户对于搜索的结果是实时变化的。

海量数据的检索—倒排索引

我们生活中的数据总体分为两种:

  • 结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等;
  • 非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等;

按照数据的分类,搜索也分为两种:

  • 对结构化数据的搜索:如对数据库的搜索,用SQL语句。再如对元数据的搜索,如利用windows搜索对文件名,类型,修改时间进行搜索等。
  • 对非结构化数据的搜索:如利用windows的搜索也可以搜索文件内容,Linux下的grep命令,再如用Google和百度可以搜索大量内容数据。

对非结构化数据的检索,一般先建立索引(倒排索引),再对索引进行搜索,这个过程又称全文检索。
下面这幅图来自《Lucene in action》,但却不仅仅描述了Lucene的检索过程,而是描述了全文检索的一般过程。
在这里插入图片描述
全文检索大体分两个过程,索引创建(Indexing)和搜索索引(Search)。

  • 索引创建:根据现存数据提取信息,创建索引的过程;
  • 搜索索引:就是得到用户的查询请求,搜索创建的索引,然后返回结果的过程。

倒排索引的创建

当文档数据来临时,solr会首先对文档数据进行分词,创建索引库和文档数据库。所谓的分词是指:将一段字符文本按照一定的规则分成若干个单词。如下面两篇文档通过solr后如何产生分词存储:
在这里插入图片描述
文章中的标点符号可以直接过滤掉,像and、too可以直接过滤掉。形成的分词表表示:
在这里插入图片描述
倒排索引存储结构为:词项的字符串+词项的文档频率+记录词项的频率信息+记录词项的位置信息+跳跃偏移量。简单的理解可以形成以下结构:
在这里插入图片描述
分别表示词,词出现的文档编号,文档中出现的频率和文档中出现的位置。这样当我们对词进行搜索时,会找到该词出现过的所有文档的ID,然后再通过该文档的ID寻找文档的具体内容。左边保存的是一系列字符串,称为词典。每个字符串都指向包含此字符串的文档(Document)链表,此文档链表称为倒排表(Posting List)。

有了索引,便使保存的信息和要搜索的信息一致,可以大大加快搜索的速度。比如说,我们要寻找既包含字符串“lucene”又包含字符串“solr”的文档,我们只需要以下几步:1. 取出包含字符串“lucene”的文档链表。2. 取出包含字符串“solr”的文档链表。3. 通过合并链表,找出既包含“lucene”又包含“solr”的文件。

如何对索引进行搜索?

现在假设,倒排索引库已经构建完成了,用户发送一个query,如何快速找到相匹配的文档,并且返回呢?如果在检索的过程中,发现匹配的有成千上万个,如何排序,返回排名靠前的呢?
比如说您想在百度找份工作,于是打开百度app,输入“百度 job”,您却发现总共有22600000个结果返回。好大的数字呀,突然发现找不到是一个问题,找到的太多也是一个问题。在如此多的结果中,如何将最相关的放在最前面呢?
这就涉及到索引的检索和排序,主要分为以下几个步骤:
1.对用户的query进行分析和处理,提取关键词;
2.在反向索引表中,分别找出包含那几个关键词的文档链表。其次,对包含那几个关键词的链表进行合并操作,此时的文档链表就是我们要找的文档;
3.对上述找到的文档,根据与query的相关性进行排序,挑选排名靠前的文档,返回结果;
那么如何对文档进行排序呢?分为三步:

  • 基于tf-idf算法,计算关键词term对于文档的重要性得分,以此得分作为term的权重;
  • 构造文档向量,文档向量由文档中的关键词term的权重组成;

Document = {term1, term2, …… ,term N},Document Vector = {weight1, weight2, …… ,weight N},同样我们把查询语句看作一个简单的文档,也用向量来表示。Query = {term1, term 2, …… , term N},Query Vector = {weight1, weight2, …… , weight N}

  • 计算query向量与各个文档向量之间的余玄相似度,根据相似度的值进行排序;

我们把所有搜索出的文档向量及查询向量放到一个N维空间中,每个词(term)是一维。如图:
在这里插入图片描述
我们认为两个向量之间的夹角越小,相关性越大。所以我们计算夹角的余弦值作为相关性的打分,夹角越小,余弦值越大,打分越高,相关性越大。有人可能会问,查询语句一般是很短的,包含的词(Term)是很少的,因而查询向量的维数很小,而文档很长,包含词(Term)很多,文档向量维数很大。你的图中两者维数怎么都是N呢?在这里,既然要放到相同的向量空间,自然维数是相同的,不同时,取二者的并集,如果不含某个词(Term)时,则权重(Term Weight)为0。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值