Lucene介绍

Lucene简介

  Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年比较受欢迎的免费Java信息检索程序库。最近几年流行的搜索引擎elasticSearch就是基于Lucene开发的。

Lucene与搜索引擎的区别

全文检索系统是按照全文检索理论建立起来的用于提供全文检索服务的软件系统,包括建立索引、处理查询返回结果集、增加索引、优化索引结构等功能。
Lucene和搜索引擎不同,Lucene是一套用java或其它语言写的全文检索的工具包,为应用程序提供了很多个api接口去调用,可以简单理解为是一套实现全文检索的类库,搜索引擎是一个全文检索系统,它是一个单独运行的软件系统。

数据结构

  开始了解Lucene之前先了解一下数据的数据的分类: 

    数据总体分为两种:结构化数据和非结构化数据。

    (1)结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。

    (2)非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等磁盘上的文件

结构化数据查询方法

  数据库搜索

  数据库中的搜索很容易实现,通常都是使用sql语句进行查询,而且能很快的得到查询结果。

  为什么数据库搜索很容易?

  因为数据库中的数据存储是有规律的,有行有列而且数据格式、数据长度都是固定的。

非结构化数据查询方法

  (1)顺序扫描法(Serial Scanning)

  所谓顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为我们要找的文件,接着看下一个文件,直到扫描完所有的文件。如利用windows的搜索也可以搜索文件内容,只是相当的慢。

  (2)全文检索(Full-text Search)

  将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引。

例如:字典。字典的拼音表和部首检字表就相当于字典的索引,对每一个字的解释是非结构化的,如果字典没有音节表和部首检字表,在茫茫辞海中找一个字只能顺序扫描。然而字的某些信息可以提取出来进行结构化处理,比如读音,就比较结构化,分声母和韵母,分别只有几种可以一一列举,于是将读音拿出来按一定的顺序排列,每一项读音都指向此字的详细解释的页数。我们搜索时按结构化的拼音搜到读音,然后按其指向的页数,便可找到我们的非结构化数据——也即对字的解释。

  

这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)。

  虽然创建索引的过程也是非常耗时的,但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的。

全文检索的应用场景

  对于数据量大、数据结构不固定的数据可采用全文检索方式搜索,比如百度、Google等搜索引擎、论坛站内搜索、电商网站站内搜索等。


Lucene的核心类库

索引过程的核心类

·IndexWriter
·Directory
·Analyzer
·Document
·Field

①IndexWriter
索引过程的核心组件。这个类负责创建新索引或者打开已有索引,以及向索引中添加、删除或更新被索引文档的信息。可以把IndexWriter看作这样一个对象:它为你提供针对索引文件的写入操作,但不能用于读取或搜索索引。IndexWriter需要开辟一定空间来存储索引,该功能可以由Directory完成。

②Directory
该类描述了Lucene索引的存放位置。它是一个抽象类,它的子类负责具体指定索引的存储路径。用FSDirectory.open方法来获取真实文件在文件系统的存储路径,然后将它们一次传递给IndexWriter类构造方法。IndexWriter不能直接索引文本,这需要先由Analyzer将文本分割成独立的单词才行。

③Analyzer
文本文件在被索引之前,需要经过Analyzer(分析器)处理。Analyzer是由IndexWriter的构造方法来指定的,它负责从被索引文本文件中提取语汇单元,并提出剩下的无用信息。如果被索引内容不是纯文本文件,那就需要先将其转换为文本文档。对于要将Lucene集成到应用程序的开发人员来说,选择什么样Analyzer是程序设计中非常关键的一步。分析器的分析对象为文档,该文档包含一些分离的能被索引的域。

④Document
Document对象代表一些域(Field)的集合。文档的域代表文档或者文档相关的一些元数据。元数据(如作者、标题、主题和修改日期等)都作为文档的不同域单独存储并被索引。Document对象的结构比较简单,为一个包含多个Filed对象容器;Field是指包含能被索引的文本内容的类。

⑤Field
索引中的每个文档都包含一个或多个不同命名的域,这些域包含在Field类中。每个域都有一个域名和对应的域值,以及一组选项来精确控制Lucene索引操作各个域值。

搜索过程中的核心类

·IndexSearcher
·Term
·Query
·TermQuery
·TopDocs

①IndexSearcher
该类用于搜索由IndexWriter类创建的索引,它是连接索引的中心环节。可以将IndexSearcher类看作是一个以只读方式打开索引的类。它需要利用Directory实例来掌控前期创建的索引,然后才能提供大量的搜索方法。
②Term
Term对象是搜索功能的基本单元。Term对象包含一对字符串元素:域名和单词(或域名文本值)。
③Query
包含了一些非常有用的方法,TermQuery是它的一个子类。
④TermQuery
该类提供最基本的查询,用来匹配指定域中包含特定项的文档。
⑤TopDocs
该类是一个简单的指针容器,指针一般指向前N个排名的搜索结果,搜索结果即匹配查询条件的文档。

Lucene如何对搜索内容进行建模

①文档和域
文档是Lucene索引和搜索的原子单位。文档为包含一个或多个域的容器,而域则依次包含“真正的”被搜索内容。每个域都有一个标识名称,该名称为一个文本值或二进制值。如:用户在输入搜索内容“title:lucene”时,搜索结果则为标题域值包含单词“lucene”的所有文档。

Lucene可以针对域进行3种操作:
·域值可以被索引。如果需要搜索一个域,则必须首先对它进行索引。被索引的域值必须是文本格式的(二进制格式的域值只能被存储而不能被索引)。在索引一个域时,需要首先使用分析过程将域值转换为语汇单元,然后将语汇单元加入到索引中。
·域被索引后,还可以选择性地存储项向量,后者可以看作该域的一个小型反向索引集合,通过该向量能够检索该域的所有语汇单元。这个机制有助于实现一些高级功能,比如搜索与当前文档相似的文档。
·域值可以被单独存储,即是说被分析前的域值备份也可以写进索引中,以便后续的检索。这个机制可以使你将原始值展现给用户,比如文档的标题或摘要。

【注意】
当搜索程序通过索引检索文档时,只有被存储的域才会被作为搜索结果展现。例如,被索引但未被存储于文档的域是不会被作为搜索结果展现的。这种机制通常会使得搜索结果具有不确定性。

②灵活的架构
与数据库不同的是,Lucene没有一个确定的全局模式;Lucene要求在进行索引操作时简单化或反向规格化原始数据。

理解索引过程

这里写图片描述
在索引操作期间,文本首先从原始数据中提取出来,并用于创建对应的Document实例,该实例包含多个Field实例,它们都用来保存原始数据信息。随后的分析过程将域文本处理成大量语汇单元。最后将语汇单元加入到段结构中。
①提取文本和创建文档
使用Lucene索引数据时,必须先从数据中提取纯文本格式信息,以便Lucene识别该文本并建立对应的Lucene文档。
②分析文档
一旦建立其Lucene文档和域,就可以调用IndexWriter对象的addDocument方法将数据传递给Lucene进行索引操作了。在索引操作时,Lucene首先分析文本,将文本数据分割成语汇单元串,然后对它们执行一些可选操作。
③向索引添加文档
对输入数据分析完毕后,就可以将分析结果写入索引文件中。Lucene将输入数据以一种倒排索引的数据结构进行存储。在进行关键字快速查找时,这种数据结构能够有效利用磁盘空间。Lucene使用倒排数据结构的原因是:把文档中提取出的语汇单元作为查询关键字,而不是将文档作为中心实体,这种思想很像书籍的索引与页码的对应关系。

–索引段
Lucene索引都包含一个或多个段。每个段都是一个独立的索引,它包含整个文档索引的一个子集。每当writer刷新缓冲区增加的文档,以及挂起目录删除操作时,索引文件都会建立一个新段。在搜索索引时,每个段都是单独访问的,但搜索结果是合并后返回的。
每个段文件都包含多个文件,文件格式为_X.,这里X代表段名称,为扩展名,用来标识该文件对应索引的某个部分。如果使用混合文件格式(这是Lucene默认的处理方式,可以通过IndexWriter.setUseCompoundFile方法进行修改),那么上述索引文件都会被压缩成一个单一的文件:_X.cfs。这种方式能在搜索期间减少打开的文件数量。
还有一个特殊文件,名叫段文件,用段_标识,该文件指向索引激活的段。Lucene会首先打开该文件,然后打开它所指向的其他文件。IndexWriter类会周期性地选择一些段,然后将它们合并到一个新段中,然后删除老的段。被合并段的选取策略由一个独立的MergePolicy类主导。
这里写图片描述

基本索引操作

①向索引添加文档
添加文档的方法有两个:
——addDocument(Document),使用默认分析器添加文档,该分析器在创建IndexWriter对象时指定,用于语汇单元操作
——addDocument(Document , Analyzer),使用指定的分析器添加文档和语汇单元操作。

②删除文档
——deleteDocuments(Term)负责删除包含项的所有文档
——deleteDocuments(Term[])
——deleteDocuments(Query)
——deleteDocuments(Query[])
——deleteAll()
通过Term类删除单个文档,需要确认在每个文档中都已索引过对应的Field类,还需要确认所有域值都是以唯一的,这样才能将这个文档单独找出来删除。
注意,如果碰巧指定了一个错误的Term对象(例如,由一个普通的被索引的域文本创建的Term对象,而不是由唯一ID值创建的域),那么Lucene将很容易地快速删除索引中的大量文档。删除操作不会马上执行,而是放入内存缓冲区,Lucene周期性刷新文档目录来执行该操作。不过即使删除操作已完成,存储该文档的磁盘空间也不会马上释放,Lucene只是将该文档标记为“删除”。

③更新文档
Lucene更新文档通过先删除整个旧文档,然后向索引中添加新文档来完成。
——updateDocument(Term,Document)首先删除包含Term变量的所有文档,然后使用writer的默认分析器添加新文档。
——updateDocument(Term,Document,Analyzer)同上,区别是可以指定分析器。由于updateDocument方法要在后台调用deleteDocuments方法,因此注意:要确认被更新文档的Term标识的唯一性。

域选项

①域索引选项(Field.Index.*)
域索引选项通过倒排索引来控制域文本是否可被搜索。
——Index.ANALYZED,使用分析器将域值分解成独立的语汇单元流,并使每个语汇单元能被搜索。该选项适用于普通文本域(如正文、标题、摘要等)
——Index.NOT_ANALYZED,对域进行索引,但不对String值进行分析。该操作实际上将域值作为单一语汇单元并使之能被搜索。该选项适用于索引那些不能被分解的域值,如URL、文件路径、日期、人名等。
——Index.ANALYZED_NO_NORMS,这是Index.ANALYZED的变体,它不会在索引中存储norms信息。norms记录了索引中的index-time boost信息,但是当你进行搜索时可能会比较耗费内存。
——Index.NOT_ANALYZED_NO_NORMS。该选项常用语在搜索期间节省索引空间和减少内存耗费,因为single-token域并不需要norms信息,除非它们已被进行加权操作。
——Index.NO,使对应的域值不被搜索。
当Lucene建立起倒排索引后,默认情况下它会保存所有必要信息以实施VectorSpace Model。该Model需要计算文档中出现的term数,以及它们出现的位置。但有时候这些域只是在布尔搜索时用到,它们并不为相关评分做贡献,一个常见的例子是,域只是被用作过滤,如权限过滤和日期过滤。这种情况下,可以通过调用Field.setOmitTermFreqAndPositions(true)方法让Lucene跳过该项的出现频率和出现位置的索引。该方法可以节省一些索引在磁盘上的存储空间,还可以加速搜索和过滤过程,但会阻止需要位置信息的搜索,如阻止PhraseQuery和SpanQuery类的运行。

②域存储选项(Field.Store.*)
用来确定是否需要存储域的真实值,以便后续搜索时能恢复这个值:
——Store.YES,指定存储域值。原始的字符串全部被保存在索引中,并可以由IndexReader类恢复。该选项对于需要展示搜索结果的一些域很有用(如URL、标题或数据库主键)。如果索引的大小在搜索程序考虑之列的化,不要存储太大的文本域值,因为这些域值会消耗掉索引的存储空间。
——Store.NO,指定不存储域值
Lucene包含一个工具类CompressionTools,提供静态方法压缩和解压字节数组。可以在存储域值之前对它进行压缩。注意,尽管该方法可以为索引节省一些空间,但节省的幅度跟域值的可被压缩程度有关,而且该方法会降低索引和搜索速度。这样其实就是通过消耗更多的CPU计算能力来换取更多的磁盘空间。如果域值所占空间很小,建议少使用压缩。

③域的项向量选项
它是介于索引域和存储域的一个中间结构。

④Reader、TokenStream和byte[]域值
Field对象还有其他几个初始化方法,允许传入除String以外的其他参数:
·Field (String name, Reader value, TermVector termVector)方法使用 Reader而不是String对象来表示域值。在这种情况下,域值是不能被存储的。(域存储选项被硬编码成 Store. NO ), 并且该域会一直用于分析和索引(Index.ANALYZED ). 如果在内存中保存 String 代价较高或者不太方便时,如存储的域值较大时,使用这个初始化方法则比较有效.
·Field(String name,Reader value), 与前述方法类似, 使用 Reader 而不是 String 对象来表示域值,但使用该方法时,默认的 termVector 为 TermVector.NO
• Field (String name, TokenStream tokenStream, termVector termVector )允许程序对域值进行预分析并生成 TokenStream 对象.此外,这个域不会被存储并将一直用于分析和索引.
• Field(String name,TokenStream tokenStream), 与前一个方法类似,允许程序对域值进行预分析并生成 TokenStream 对象,但使用该方法时默认的termVector 为 TermVector.NO.
• Field (String name, byte [] value, Store store)方法可以用来存储二进制域, 如用不参与索引的域( Index.NO )和没有项向量的域( TermVector. NO ). 其中 store 参数必须设置为 Store.YES.
• Field (String name, byte[] value, int offset, int length, Stroe store) 与前一个方法类似,能够对二进制域进行索引,区别在于该方法允许你对这个二进制的部分片段进行引用,该片段的起始位置可以用 offset 参数表示,处理长度可以用参数 length 对应的字节数来表示.
Field 类是一个非常复杂的类, 它提供了大量的初始化选项,以向 Lucene 传达精确的域值处理指令。

⑤域选项组合

这里写图片描述


Lucene实现全文检索的流程

  索引和搜索流程图

这里写图片描述
Lucene实现全文检索主要分为两部分,首先是创建索引库,然后查询时在索引库中查询实现全文检索。

  1、绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:

    确定原始内容即要搜索的内容→采集文档→创建文档→分析文档→索引文档

  2、红色表示搜索过程,从索引库中搜索内容,搜索过程包括:

    用户通过搜索界面→创建查询→执行搜索,从索引库搜索→渲染搜索结果

  接下来详细讲解一下这张图片: 
  
  1,创建索引

  对文档索引的过程,将用户要搜索的文档内容进行索引,索引存储在索引库(index)中。

这里我们要搜索的文档是磁盘上的文本文件,根据案例描述:凡是文件名或文件内容包括关键字的文件都要找出来,这里要对文件名和文件内容创建索引。

  1.1.1. 获得原始文档

  原始文档是指要索引和搜索的内容。原始内容包括互联网上的网页、数据库中的数据、磁盘上的文件等。

  1.1.2. 创建文档对象

  获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档中包括一个一个的域(Field),域中存储内容。

这里我们可以将磁盘上的一个文件当成一个document,Document中包括一些Field(file_name文件名称、file_path文件路径、file_size文件大小、file_content文件内容),如下图:
这里写图片描述

1.1.3. 分析文档

  将原始内容创建为包含域(Field)的文档(document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。

  比如下边的文档经过分析如下:

  原文档内容:

  Lucene is a Java full-text search engine.

  分析后得到的语汇单元:

  lucene、java、full、search、engine

  每个单词叫做一个Term,不同的域中拆分出来的相同的单词是不同的term。term中包含两部分一部分是文档的域名,另一部分是单词的内容。

  例如:文件名中包含apache和文件内容中包含的apache是不同的term。

  1.1.4. 创建索引

  对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。

这里写图片描述

  注意:(1)创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。

     (2)传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。

   (3)倒排索引结构是根据内容(词语)找文档,如下图:

这里写图片描述

  倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合较大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值