Lucene学习笔记(二)--------构建索引

Lucene构建索引涉及对搜索内容建模,包括文档和域的概念,以及分析、添加文档、删除和更新文档的过程。索引由多个段组成,每个段包含不同文件,通过分析器将文本转化为可搜索的词汇单元。域的索引、存储和项向量选项影响搜索和存储行为。索引优化可以提高搜索效率,但会消耗大量资源。此外,Lucene还支持对数字和日期的索引,以及近实时搜索功能。
摘要由CSDN通过智能技术生成

构建索引

对搜索内容建模

文档和域

文档是索引和搜索的原子单位,包含一个或多个域的容器,域则依次包含“真正的”被搜索内容。每个域都有一个标识名称(即一个文本值或二进制值)。将文档加入到索引中时,可以通过一系列选项控制Lucene的行为。在对原始数据进行索引操作时,先将数据转换成Lucene所能识别的文档和域,搜索过程中被搜索对象为阈值。

Lucene可以针对域进行3种操作:

  • 阈值可以被索引(或者不被索引),要搜索一个域就必须先进行索引。且被索引的域必须是文本格式的(二进制格式的域值只能被存储不能被索引),索引一个域时,首先需要使用分析过程将域值转换成语汇单元,然后将语汇单元加入到索引中

  • 域被索引后,还可以选择性的存储项向量,后者可以看作该域的一个小型反向索引集合,通过该向量能够检索该域的所有语汇单元,这个机制可以帮助实现一些高级功能,比如搜索与当前文档相似的文档

  • 域值可以被单独存储,即被分析前的域值备份也可以写进索引中

当搜索程序通过索引检索文档时,只有被存储的域才会被作为搜索结果展现。被索引但未被存储于文档的域是不会被作为搜索结果展示的

与数据库不同,Lucene没有一个确定的全局模式,即加入索引的每个文档都是独立的,与此前加入的文档完全没有关系:它可以包含任意的域,以及任意的索引、存储和项向量操作选项,不必包含与其他文档相同的域,甚至可以内容相同仅是相关操作选项有所区别

这种特性保证了可以递归访问文档并建立对应的索引,可以随时对文档进行索引,不必提前设计文档的数据结构表,若随后想向文档中添加域,可以完成添加后重新索引该文档或重建索引即可。

Lucene与数据库的第二个区别是,Lucene要求在进行索引操作时简单化或反向规格化原始数据。

反向规格化(Denormalization)是为了解决文档真实结构和Lucene表示能力之间的“不匹配”问题。

提取文本和创建文档

使用Lucene索引数据时,必须先从数据中提取纯文本格式信息,以便Lucene识别该文本并建立对应的Lucene文档。

分析文档

建立起Lucene文档和域,就可以调用IndexWriter对象的addDocument方法将数据传递给Lucene进行索引操作。索引操作时,首先分析文本,将文本数据分割成语汇单元串,然后对它们执行一些可选操作。
- LowerCaseFilter可以将词汇单元在索引前统一转换为小写,以使搜索不对大小写敏感
- StopFilter类从输入中去掉一些使用很频繁却没有实际意义的词(a、an、the、in、on、so on等)
- PorterStemFilter可以去掉英文词的词干

这些将原始数据转换为语汇单元,随后用一系列filter来修正该语汇单元的操作,一起构成了分析器。还可以通过链接Lucene的词汇单元和filter自定义分析器或通过其他方式自定义分析器

向索引添加文档

对输入数据分析完成,Lucene将分析结果以倒排索引(inverted index)的方式写入索引文件中存储。在进行关键字快速查找时,倒排索引能有效利用磁盘空间

Lucene使用倒排数据结构的原因是:把文档中提取出来的词汇单元作为查询关键字。

索引段
  • segment_N: —->Segment0, Segment1, Segment2, Segment3,….

Lucene索引都包含一个或多个段,每个段都是一个独立的索引,包含整个文档索引的一个子集。每当writer刷新缓冲区增加的文档,以及挂起目录删除操作时,索引文件都会建立一个新段。在搜索索引时,每个段都是单独访问的,但搜索结果是合并后返回的。

每个段都包含多个文件,文件格式为_X.,X代表段名称,是扩展名,用来标识该文件对应索引的某个部分。各个独立的文件共同组成了索引的不同部分(项向量、存储的域、倒排索引等)。

如果使用混合文件格式(Lucene的默认处理方式,但可以通过IndexWriter.setUseCompoundFile方法进行修改),上述索引文件会被压缩成一个单一的文件:_X.cfs。这种方式的好处是能在搜索期间减少打开的文件数量。

还有一个段文件,用段_标识,该文件指向所有激活的段。Lucene会首先打开该文件,然后打开它所指向的其他文件。值被称为“the generation”,它是一个整数,Lucene每次向索引提交更改时都会将这个数加1.

久而久之,索引会积聚很多段,尤其当程序打开和关闭writer较为频繁时。IndexWriter类会周期性地选择一些段,然后将它们合并到一个新段中,然后删除老的段。被合并的段选取策略由一个独立的MergePolicy类主导。一旦选取好这些段,具体合并操作由MergeScheduler类实现。

基本索引操作

向索引添加文档

添加文档的方法有两个:

  • addDocument(Document)——使用默认分析器添加文档,在创建IndexWriter对象时指定分析器,用于词汇单元化操作

  • addDocument(Document,Analyzer)——使用指定的分析器添加文档和词汇单元化操作,但要注意分析器在搜索时能够匹配索引时生成的词汇单元才能正常工作

IndexWriter类初始化方法并不显式包含索引是否已创建的布尔值,它在初始化时会首先检查传入的Directory类是否已包含索引,如果索引存在,IndexWriter类则在该索引上追加内容,否则则向Directory类写入新创建的索引。

IndexWriter类有多个初始化方法。其中一些方法会显式包含创建索引的参数,这允许强制建立新的索引并覆盖原来的索引。

一旦建立起索引,就可以用for循环来初始化文档对象:首先创建一个新的Document空对象,然后根据需要向这个Documnet对象中逐个添加Field对象。每个文档都有4个域,每个域都有各自不同的选项。最后调用writer.addDocument方法来索引文档。

删除索引中的文档

IndexWriter类提供了各种方法从索引中删除文档:

  • deleteDocument(Term):删除包含项的所有文档
  • deleteDocument(Term[]):删除包含项数组任一元素的所有文档
  • deleteDocument(Query):删除匹配查询语句的所有文档
  • deleteDocument(Query[]):删除匹配查询语句数组任一元素的所有文档
  • deleteAll():删除索引中所有文档

如果需要通过Term类删除单个文档,需要确认在每个文档中都已索引过对应的Field类,还要确认所有域值都是唯一的。还可以对这个域进行任意命名(通常用ID命名),该域需要被索引成未被分析的域以保证分析器不会将它分解成语汇单元,然后利用该域来删除对应文档:

writer.deleteDocument(new Term("ID", documentID));

在所有情况下,删除操作不会马上执行,而是放入内存缓冲区,与加入文档的操作类似,Lucene会通过周期性刷新文档目录来执行该操作。不过即使删除操作已经完成,存储该文档的磁盘空间也不会马上释放,Lucene只是将该文档标记为“删除”。

  • writer.hasDeletions()方法用于检查索引中是否包含被标记为已删除的文档
  • IndexWriter.maxDoc()返回索引中被删除和未被删除的文档数
  • IndexWriter.numDocs()返回索引中未被删除的文档总数
更新索引中的文档

Lucene做不到只更新文档中的部分域,只能删除整个旧文档,然后向索引中添加新文档。这要求新文档必须包含旧文档中所有域,包括内容未发生改变的域。IndexWriter提供了两个方法更新索引中的文档

  • updateDocument(Term, Document)首先删除包含Term变量的所有文档,然后使用writer的默认分析器添加新文档
  • updateDocument(Term, Document, Analyzer)功能与上述一致,区别在于可以指定分析器添加文档

这两个方法是通过调用deleteDocument(Term)和addDocument两个方法合并实现的。

writer.updateDocument(new Term("ID", documentId), newDocument);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值