1.lucene如何对搜索内容进行建模
1.1文档(document)和域(field)
文档是lucene索引和搜索的原子单位。文档为包含一个或多个域的容器,而域则依次包含真正的被搜索的内容。比如一篇文章就是一个文档,标题是一个域,标题内容为域值,正文也是一个域,正文内容为域值。lucene可以针对域进行三种操作:
- 域值可以被索引
- 域被索引后,可以选择性的存储项向量。项向量(TermVector)可以被用作相似查找
- 域值还可以被单独存储
2.理解索引过程
2.1提取文本和创建文档
使用lucene索引数据时,必须先从数据中提取纯文本格式信息,以便lucene识别该文本并建立对应的lucene文档。tika框架可以轻易的从各种格式的文件中提取文本信息
2.2分析文档
一旦建立起lucene文档和域,就可以调用IndexWriter对象的addDocument方法将数据传递给lucene进行索引操作了。在索引操作时,lucene首先分析文本,将文本数据分割成词汇单元,然后对它们执行一些可选操作。文本分析包含了词汇切割、大小写转换、移除停用词等操作。分析过程的步骤很重要,这一步会产生大量的词汇单元,随后这些词汇单元将被写入索引文件中。
2.3向索引添加文档
对文档分析完毕之后,就可以将分析结果写入索引文件了。lucene将输入数据以一种倒排索引的数据结构进行存储。lucene索引都包含一个或者多个段(segment),每个段都是一个独立的索引,它包含整个文档索引的一个子集。
3.基本索引操作
3.1向索引添加文档
添加文档的方法有两个:
- addDocument(Document): 使用默认分析器添加文档,该文档分析器在创建IndexWriter对象时指定
- addDocument(Document, Analyzer): 使用指定的分析器添加文档
3.2删除索引中的文档
IndexWriter提供了各种方法来从索引中删除文档
- deleteDocuments(Term): 负责删除包含项的所有文档
- deleteDocuments(Term[]):负责删除包含项数组任一元素的所有文档
- deleteDocuments(Query): 负责删除匹配查询语句的所有文档
- deleteDocuments(Query[]): 负责删除匹配查询语句数组任一元素的所有文档
- deleteAll(): 负责删除索引中的所有文档
3.3更新索引中的文档
IndexWriter提供了两个简便的方法来更新索引中的文档
- updateDocument(Term, Document):首先删除包含Term变量的所有文档,然后使用writer的默认分析器添加新文档
- updateDocument(Term, Document, Analyzer):功能与上述一致,区别在于可以指定分析器添加文档
4.域选项
4.1域索引选项
- Index.ANALYZED:使用分析器将域值分解成词汇单元,并建立索引
- Index.NOT_ANALYZED: 不使用分析器分解阈值,并建立索引
- Index.ANALYZED_NO_NORMS: 与Index.ANALYZED类似,但不存储norms信息
- Index.NOT_ANALYZED_NO_NORMS: 与Index.NOT_ANALYZED类似,但不存储norm信息
- Index.NO:不建立索引
4.2域存储选项
- Store.YES: 指定存储阈值
- Store.NO: 指定不存储阈值
4.3域排序选项
如果需要按照某一域值对匹配的文档集合进行排序,那么该阈值应该被正确的索引以及存储。如果域是数值类型,在将它加入文档和进行排序时,要用NumericField类来表示
4.4多值域
文档的一个域可能有多个值,可以用document.add()多个域相同但域值不同的对象
5.对文档和域进行加权操作
5.1文档加权操作
调用加权操作的API只包含一个方法:documents.setBoost(float)
5.2域加权操作
使用field.setBoost(float)对域进行加权
5.3 加权基准
在索引期间,文档中域的所有加权都被合并成一个单一的浮点数。除了域,文档也有自己的加权值。这些权值被合并到一处,并被编码(量化)成一个单一的字节,作为域或文档信息的一部分存储起来。在搜索期间,被搜索域的norms都被加载到内存,并被解码还原为浮点数,然后用于计算相关性评分(relevance score)。
虽然norms是在索引期间首次进行计算的,后续还是可以使用IndexReader的setNorm方法对它进行修改的。
6.索引数字、日期和时间
6.1索引数字
使用NumricField可以对数字进行索引。每个数值都用特里结构(trie structure)进行索引,能实现高效的范围搜索或者过滤功能。
6.2索引日期和时间
同样使用NumricField索引时间。可以将时间转换成时间戳,在用NumricField
7.域截取
一些应用程序需要对尺寸未知的文档进行索引。IndexWriter允许对域进行截取后再索引它们。传入MaxFieldLength对象告知IndexWriter截取的长度。
8.近实时搜索
lucene通过调用IndexWriter中的对象方法实现近实时搜索:IndexReader getReader()。该方法能实时刷新缓冲区中新增或者删除的文档,然后创建新的包含这些文档的只读型IndexReader实例。
9.优化索引
lucene中索引的优化只是对段(segment)进行合并,这样可以提升搜索效率。思考下搜索功能需要访问各个段中的索引,减少了段的数量也就减少了扫描的次数。优化索引只能提高搜索速度而不是索引速度。IndexWriter提供了4个优化方法:
- optimize()将索引压缩至一个段,操作完成再返回
- optimize(int maxNumSegments)也称部分优化,将索引压缩为最多maxNumSegment个段
- optimize(boolean doWait)跟optimize()类似,若doWait参数传入false值,这样的话调用会立即执行,但合并工作是在后台运行的
- optimize(int maxNumSegments, boolean doWait)也是部分优化
注意索引优化会消耗大量的cpu和i/o资源。
10.并发、线程安全及锁机制
10.1线程安全和多虚拟机安全
- 任意数量的只读属性的IndexReader类都可以同时打开一个索引。
- 对于一个索引来说,一次只能打开一个Writer。lucene采用文件锁来保证只有一个writer打开索引
- 任意一个线程都可以共享同一个IndexReader类或者IndexWriter类
10.2索引锁机制
锁文件默认为write.lock,存在于索引目录内。
网友评论