动机:实习读项目代码,撰写的时候是以Lucene为原型的,其中一些命名也和Lucene中的相同命名概念等价。所以用博客做个归档。
参考页面:https://www.javacodegeeks.com/2015/09/introduction-to-lucene.html
Inverted Index:通过举例说明。设有3个文档。正排索引的模式大致如下:
Document1 -> { going, to, dive, into, Apache, Lucene, rich, open, source, full, text, search,... } Document2 -> { so, must, wonder, Lucene, can, achieve, very, fast, full, text, search, not,... } Document3 -> { reason, that, inverted, index, work, good ,can, be, seen, following, diagrams,... }
那么对应的倒排索引的模式就是这样:
reason -> { (3,0) } Lucene -> { (1,6), (2,4) } full -> { (1,10),(2,9) } going -> { (1,0) } index -> { (3,3) } search -> { (1,11), (2,10)} ...
这种数据结构的思想是把少数单个长度过大的词汇列表转变成很多单个长度较小的document指针列表,从而能完成对检索哪些document包含期望词汇的需求时能快速完成检索的需求。
Directories:一个Lucene的Index和一个Directories object对应。Directory可以对应一个文件路径(FSDirectory class),也可以对应内存上的区域(RAMDirectory),也可以是通过JDBC建立连接的数据库。
Documents:Lucene中的每一条基本数据最小单位为文档,即写入Lucene一条数据,可以看作为写入Lucene一条文档。
Document类似于关系型数据库的一行数据,但是对于数据库而言Schma是强Schema,即每一行的数据元数据结构是一致;对于Lucene的Document没有固定的Schema限制,Ducument内的每一条数据可以有互相不同的字段。
Fields:一条Document内可以有多个Field。Field本质就是(name, value)元组。
Field可以被存放(Stored)入index,也可以被建立索引(Indexed)。Store操作中,上述元组的完整信息在index中被保存。Index操作中,元组中的value部分会被拆分成Terms(下文单独解释),并进行倒排操作以供之后搜索使用。Store和Index是两个独立的操作,Indexing一个field不一定需要Store它。举例如下:
Name | Value | Stored | Indexed |
---|---|---|---|
Title | Email from example | Yes | No |
Location | location of the email | Yes | No |
From | sample#hotmail.com | Yes | No |
To | sample2#outlook.com | Yes | No |
Subject | Communication | Yes | No |
Body | Hi there ! Nice meeting you… | No | Yes |
Terms:Term表示Document中的一个词(更准确的概念是Token)。Term是查找操作的单元。Term由两部分构成:literal term和它出现的field的name。
Analyzers:作用是把输入的查询文本转换成terms序列。
开发者需要给Analyzer提供parser以把复杂文本(例如html)转变成plain text。之后Analyzer通过内部的tokenizer,把plain text转换成terms序列。
Segment:一系列Document的组合,具有merge特性,即只能做顺序写,顺序添加,不能随机写入和更改。
Segment存在套娃机制(一系列小segments可以merge成大segment),目的是避免segment文件大小膨胀。
Index:一系列Segment的组合,类似于关系型数据库的一张表。
查询流程:
- Lucene_Directory -> IndexReader -> IndexSearcher
- Analyzer + other fields = QueryParser
- QueryParser.parse(Input_query) = Lucene_query
- IndexSearcher.search(Lucene_query) = results
写入流程:
- Analyzer + other_configs = IndexWriter_Config
- IndexWriter_Config + Lucene_Directory = IndexWriter
- InputData -> Lucene Document
- Document.addFieldData(…)
- IndexWriter.AddDocumentToMem(Document)
- IndexWriter.FlushToDriverPeriodically()
- IndexWriter.MergeSegments(…)