概述
Lucene 作为 Apache 开源的一款搜索工具,一直以来是实现搜索功能的神兵利器,现今火热的 Solr 和 Elasticsearch 均基于该工具包进行开发,而 Lucene 之所以能在搜索中发挥至关重要的作用正是因为倒排索引。因此,本文将介绍一下倒排索引的概念以及倒排索引在 Lucene 中的实现。
基本原理
什么是倒排索引
搜索的核心需求是全文检索,全文检索简单来说就是要在大量文档中找到包含某个单词出现的位置,在传统关系型数据库中,数据检索只能通过 like 来实现。
例如需要在酒店数据中查询名称包含公寓的酒店,需要通过如下 sql 实现:
select * from hotel_table where hotel_name like '%公寓%';
这种实现方式实际会存在很多问题:
搜索的核心目标实际上是保证搜索的效果和性能,为了高效的实现全文检索,我们可以通过倒排索引来解决。
倒排索引是区别于正排索引的概念:
倒排索引的生成过程
假设目前有以下两个文档内容:
苏州街维亚大厦
桔子酒店苏州街店
其处理步骤如下:
1、正排索引给每个文档进行编号,作为其唯一的标识。
文档 id | content |
---|---|
1 | 苏州街维亚大厦 |
2 | 桔子酒店苏州街店 |
2、生成倒排索引:
- 首先要对字段的内容进行分词,分词就是将一段连续的文本按照语义拆分为多个单词,这里两个文档包含的关键词有:苏州街、维亚大厦…
- 然后按照单词来作为索引,对应的文档 id 建立一个链表,就能构成上述的倒排索引结构。
Word | 文档 id |
---|---|
苏州街 | 1,2 |
维亚大厦 | 1 |
维亚 | 1 |
桔子 | 2 |
酒店 | 2 |
大赛 | 1 |
有了倒排索引,能快速、灵活地实现各类搜索需求。整个搜索过程中我们不需要做任何文本的模糊匹配。
例如,如果需要在上述两个文档中查询 苏州街桔子 ,可以通过分词后 苏州街 查到 1、2,通过 桔子 查到 2,然后再进行取交取并等操作得到最终结果。
倒排索引的结构
根据倒排索引的概念,我们可以用一个 Map来简单描述这个结构。这个 Map 的 Key 的即是分词后的单词,这里的单词称为 Term,这一系列的 Term 组成了倒排索引的第一个部分 —— Term Dictionary (索引表,可简称为 Dictionary)。
倒排索引的另一部分为 Postings List(记录表),也对应上述 Map 结构的 Value 部分集合。
记录表由所有的 Term 对应的数据(Postings) 组成,它不仅仅为文档 id 信息,可能包含以下信息:
- 文档 id(DocId,Document Id),包含单词的所有文档唯一 id,用于去正排索引中查询原始数据。
- 词频(TF,Term Frequency),记录 Term 在每篇文档中出现的次数,用于后续相关性算分。
- 位置(Position),记录 Term 在每篇文档中的分词位置(多个),用于做词语搜索(Phrase Query)。
- 偏移(Offset),记录 Term 在每篇文档的开始和结束位置,用于高亮显示等。
Lucene 倒排索引实现
全文搜索引擎在海量数据的情况下是需要存储大量的文本,所以面临以下问题:
因此上面说的基于 Map 的实现方式几乎是不可行的。
在海量数据背景下,倒排索引的实现直接关系到存储成本以及搜索性能。
为此,Lucene 引入了多种巧妙的数据结构和算法。其倒排索引实现拥有以下特性:
- 以较低的存储成本存储在磁盘 (索引大小大约为被索引文本的20-30%)
- 快速读写
下面将根据倒排索引的结构,按 Posting List 和 Terms Dictionary 两部分来分析 Lucene 中的实现。
Posting List 实现
PostingList 包含文档 id、词频、位置等多个信息,这些数据之间本身是相对独立的,因此 Lucene 将 Postings List 被拆成三个文件存储:
基本所有的查询都会用 .doc 文件获取文档 id,且一般的查询仅需要用到 .doc 文件就足够了,只有对于近似查询等位置相关的查询则需要用位置相关数据。
三个文件整体实现差不太多,这里以.doc 文件为例分析其实现。
.doc 文件存储的是每个 Term 对应的文档 Id 和词频。每个 Term 都包含一对 TermFreqs 和 SkipData 结构。
其中 TermFreqs 存放 docId 和词频信息,SkipData 为跳表信息,用于实现 TermFreqs 内部的快速跳转。
文件位置指针。
其他更多介绍请参考:ES之倒排索引详解_wh柒八九的博客-CSDN博客_es倒排索引
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。