Lucene 实战教程第五章说说 Index(索引)、Document(文档)、Field(字段)、Term(词条)、Token

JAVA herman 417浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

要理解 Lucene,必须要先对它的基本构成有所了解。上一章我写了 Field,有些人还是看不明白,在微信群里讨论。所以,这一章我在把 Lucene 内部的几个概念拿出来讲一讲。

如果这几个概念:索引(index)、段(Segement)、文档(document)、字段(field)、词条(term)和 Token。你没理解,那么代码你就更难理解。

  • Index:索引,由很多的 Document 组成。
  • Segment:段,可以理解为一个子索引,添加索引时并不是每个 document 都马上添加到同一个索引文件,它们首先被写入到不同的小文件,然后再合并成一个大索引文件,这里每个小文件都是一个 segment。
  • Document:由很多的 Field 组成,是 Index 和 Search 的最小单位。
  • Field:由很多的 Term 组成,包括 Field Name和 Field Value。
  • Term:由很多的字节组成。一般将 Text 类型的 Field Value 分词之后的每个最小单元叫做 Term。
  • Token:Token 是 erm 的一次出现,它包含 term  文本和相应的起止偏移,以及一个类型字符串。一句话中可以出现多次相同的词语,它们都用同一个 term 表示,但是用不同的 Token,每个 Token 标记该词语出现的地方。

Segment

Lucene 的索引文件中会包含很多个 segments 文件,每个 segment 中包含多个 documents 文件,一个 segment 中会有完整的正向索引和反向索引。在搜索时,Lucene 会遍历这些 segments,以 segments 为基本单位独立搜索每个 segments 文件,而后再把搜索结果合并。

建立索引文件的过程,实际就是把 documents 文件一个个加入索引中,Lucene 的做法是最开始为每个新加入的 document 独立生成一个 segment,放在内存中。而后,当内存中 segments 数量到达一个阙值时,合并这些 segments,新生成一个 segment 加入文件系统的 segments 列表中。而当文件系统的 segments 数量过多时,势必影响搜索效率,因此需要不断合并这些 segments 文件。

Lucene 有两套基本的合并策略。第一种策略实现代码位于 IndexWriter#optimize() 函数,其实就是把所有 segments 文件合并成一个文件。合并的算法是递归合并列表最后的 mergeFactor 个 segments 文件直到合并成一个文件。这儿 mergeFactor 是 Lucene 的一个参数。

第二种策略实现代码位于 IndexWriter#maybeMergeSegments() 函数中,这个代码就复杂了,它的基本策略就是要求确保合并后两个公式的成立。

假定 segments 是个有序列表,B 表示 maxBufferedDocs,f(n)=ceil(log_M(ceil(n/B))),M 表示 mergeFactor,这儿 maxBufferedDocs 和 mergeFactor 是两个参数。

  1. 如果第 i 个segment 的 documents 数量为 x,第 i+1 个 segment 的 documents 数量为 y,那么 f(x)>f(y) 一定成立。
  2. f(n) 值相同的 segments 的数量不得超过 M

说完 segments,我们来说 document。

Document

lucene 中的文档模型 document 类似于数据库,但是又不完全相同,体现在下面两个方面:

  • 无规范格式,即无需固定的 schema,无列等预先设计,同一个索引中加入的 document 可包含不同的 field。
  • 非正规化,lucene 中的文档模型是一个平面化的结构,没有递归定义,自然连接等等复杂的结构。

然后,我们再来说说 field。

Field

一个 document 可能包含若干个 field。每一个 field 有不同的策略。通过上一章我们可以知道 field 有 3 种策略。

  • 被索引 or not,将该字段(field)经过分析(analyise)后,加入索引中,并不是原文。
  • 如果被索引,可选择是否保存“term vector”(向量),用于相似检索。
  • 可选择是否存储(store),将原文直接拷贝,不做索引,用于检索后的取出。

Term

term 就是 analyzer 分词后的词组。每一个 document 都含有一个 term vector,TermVector 表示文档的条目(由一个 Document 和 Field 定位)和它们在当前文档中所出现的次数,存储了这个 document 含有的 term(unique,如果某个 term 出现多次也只存一个),以及这个 term 出现在 field 中的 position,以及 offset。这些信息可以用来以后高亮一个选中的 term 等等。Field.TermVector 参数指示 index 是否存储 term vector。

词是索引的最小单位,是经过词法分析和语言处理后的字符串。

索引过程

索引过程理解起来也非常的简单。可以用 3 个词来总结,提取摘要,分析,建立索引。

  1. 提取摘要:从原文提取,并创建 document 和 field对象。可以从 pdf、word 等非文本的文件中提取。
  2. 分析:analysis,首先对 document 的 field 进行分解,产生 token 流,然后经过一系列 filter(如小写化)等。
  3. 建立索引:通过 indexwriter 的 adddocument 写入到索引中。lunece 使用了反向索引,即“那个 document 包含单词x”,而不是“ document 包含哪些 word”

在 lucene 中,读写路径是分离的。写入的时候创建一个 IndexWriter,而读的时候会创建一个 IndexSearcher。后面我们继续深入学习 Lucene。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » Lucene 实战教程第五章说说 Index(索引)、Document(文档)、Field(字段)、Term(词条)、Token