Lucene 的索引里面存了些什么,如何存放的,也即 Lucene 的索引文件格式,是读懂 Lucene源代码的一把钥匙。
当我们真正进入到 Lucene 源代码之中的时候,我们会发现:
(1)Lucene 的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。
(2)Lucene 的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。
本文详细解读了 Apache Lucene - Index File Formats (http://lucene.apache.org/java/2_9_0/fileformats.html) 这篇文章。
上面曾经交代过,Lucene 保存了从 Index 到 Segment 到 Document 到 Field 一直到 Term 的正向信息,也包括了从 Term 到 Document 映射的反向信息,还有其他一些 Lucene 特有的信息。
下面对这三种信息一一介绍。
4.1. 正向信息
Index –> Segments (segments.gen, segments_N) –> Field(fnm, fdx, fdt) –> Term (tvx, tvd, tvf) 上面的层次结构不是十分的准确,因为 segments.gen 和 segments_N 保存的是段(segment)的元数据信息(metadata),其实是每个 Index 一个的,而段的真正的数据信息,是保存在域(Field)和词(Term)中的。
反向信息是索引文件的核心,也即反向索引。
反向索引包括两部分,左面是词典(Term Dictionary),右面是倒排表(Posting List)。
在 Lucene 中,这两部分是分文件存储的,词典是存储在 tii,tis 中的,倒排表又包括两部分,一部分是文档号及词频,保存在 frq 中,一部分是词的位置信息,保存在 prx 中。
-
Term Dictionary (tii, tis)
-
Frequencies (.frq)
-
Positions (.prx)
为什么会有标准化因子呢?
从第一章中的描述,我们知道,在搜索过程中,搜索出的文档要按与查询语句的相关性排序,相关性大的打分(score)高,从而排在前面。
相关性打分(score)使用向量空间模型(Vector Space Model),在计算相关性之前,要计算 Term Weight,也即某 Term 相对于某 Document 的重要性。
在计算 Term Weight 时,主要有两个影响因素,一个是此 Term 在此文档中出现的次数,一个是此 Term 的普通程度。
显然此 Term 在此文档中出现的次数越多,此 Term 在此文档中越重要。
ES 在检索方面至关重要,核心就是基于 lucene。我们自下而上学习,逐步升入,解开 lucene 的面纱。
官网简介
Apache Lucene™ 9.9.1 文档
Lucene 是一个用于 Java 的全文搜索引擎。Lucene 不是一个完整的应用程序,而是一个代码库和 API,可以轻松地用于向应用程序添加搜索功能。
这是 Apache Lucene 9.9.1 的官方文档。更多文档可在 Wiki 中找到。
入门指南
以下部分旨在作为一个“入门”指南。它面向三类受众:首次使用者,希望在其应用程序中安装 Apache Lucene 的用户;希望修改或以 Lucene 为基础开发应用程序的开发人员;以及希望参与并为 Lucene 的开发做贡献的开发人员。目标是帮助您“入门”。它不会深入讨论 Lucene 的某些概念或内部细节:
搜索基础
Lucene提供多种查询实现,大多数位于此包或queries模块中。
这些实现可以以多种方式组合,提供复杂的查询功能,同时提供有关匹配发生在文档集合中的位置的信息。
下面的"查询类"部分突出显示了一些更重要的查询类。
有关实现自己的查询类的详细信息,请参阅下面的"自定义查询 - 专家级别"。
要执行搜索,应用程序通常调用IndexSearcher.search(Query,int)。
创建并提交给IndexSearcher后,评分过程开始。在一些基础设置之后,控制最终传递给Weight实现及其Scorer或BulkScorer实例。有关该过程的更多注释,请参阅"算法"部分。
概述
尽管 Lucene 提供了通过其 API 创建自定义查询的功能,但它还通过查询解析器提供了一个丰富的查询语言,这是一个 lexer,它使用 JavaCC 将字符串解释为 Lucene 查询。
通常,查询解析器语法可能会在版本之间发生更改。本页面描述了当前版本的语法。如果您使用 Lucene 的不同版本,请查阅与您使用的版本一起分发的 docs/queryparsersyntax.html 的副本。
在选择使用提供的查询解析器之前,请考虑以下几点:
- 如果您正在以编程方式生成查询字符串,然后使用查询解析器解析它,那么您应该认真考虑直接使用查询 API 构建查询。换句话说,查询解析器是为人工输入的文本而设计的,而不是为程序生成的文本。
- 未标记的字段最好直接添加到查询中,而不是通过查询解析器添加。如果字段的值是由应用程序以编程方式生成的,则应为该字段生成查询子句。查询解析器使用的分析器旨在将人工输入的文本转换为词项。程序生成的值,如日期、关键字等,应该是一致的程序生成。
- 在查询表单中,应使用查询解析器的字段应为通用文本的字段。其他字段,如日期范围、关键字等,最好直接通过查询 API 添加。具有一组可以在下拉菜单中指定的有限值的字段不应添加到随后解析的查询字符串中,而应该作为 TermQuery 子句添加。
如果想实现一个简易版本的 lucene,有哪些核心功能要实现?
Lucene是一个强大的全文检索引擎,实现一个简易版本的Lucene需要考虑以下核心功能:
-
分词(Tokenization): 将文本拆分成词语的过程。实现一个简单的分词器,将文本分解为基本的单词或词元。
-
建立倒排索引(Inverted Index): 将文档中的词语映射到其所在的文档及位置。需要构建一个数据结构,以支持快速的倒排索引查询。
-
文档存储: 存储文档的原始内容以及相关的元数据,如文档ID、文档路径等。
-
查询解析(Query Parsing): 支持将用户输入的查询解析成可执行的查询对象。这涉及到将用户输入的查询语句转换成内部表示形式,以便进行检索。
-
检索(Retrieval): 实现基本的检索功能,根据用户的查询从建立的倒排索引中检索相关的文档。
-
评分(Scoring): 对检索结果进行评分,以便按照相关性对文档进行排序。
-
布尔查询(Boolean Queries): 实现对布尔运算符(AND、OR、NOT等)的支持,以允许用户构建复杂的查询。
-
更新索引: 允许添加、删除或更新文档,并相应地更新倒排索引。
-
性能优化: 考虑一些性能优化措施,例如缓存、压缩索引等,以提高系统的性能。
-
错误处理与容错: 处理可能发生的错误情况,提供一些容错机制以确保系统的健壮性。