lucene简介
本文是我们名为“ Apache Lucene基础知识 ”的学院课程的一部分。
在本课程中,您将了解Lucene。 您将了解为什么这样的库很重要,然后了解Lucene中搜索的工作方式。 此外,您将学习如何将Lucene Search集成到您自己的应用程序中,以提供强大的搜索功能。 在这里查看 !
1.简介
在本课程中,我们将深入探讨Apache Lucene。 Lucene是一款功能丰富的开源全文搜索工具。 这意味着Lucene将帮助您实现针对您的应用程序需求量身定制的全文搜索引擎。 我们将处理Lucene的Java风格,但请记住,存在用于各种编程语言的API客户端。
1.1什么是全文搜索
用户通常需要检索与某些条件匹配的文档或来源列表。 例如,图书馆用户需要能够找到特定作者撰写的所有书籍。 或所有书名中带有特定单词或短语的书籍。 或在特定年份从特定出版商发行的所有书籍。 上面的查询可以通过众所周知的关系数据库轻松地处理。 如果您拥有一个存储(元组, 标题,作者,出版者,出版年)元组的表,则可以有效地完成上述搜索。 现在,如果用户想要获取在其实际内容中包含某个单词或短语的所有文档,该怎么办? 如果您尝试使用传统数据库并将所有文档的原始内容存储在元组的字段中,那么搜索将花费不可接受的时间。
那是因为在全文搜索中 ,搜索引擎必须扫描文本文档或一般文本流中的所有单词 ,并尝试针对它匹配多个条件,例如查找其内容中的某些单词或短语。 传统的关系数据库中的此类查询将毫无希望。 当然,许多数据库系统(例如MySQL和PostgreSQL)都支持全文搜索,无论是本机搜索还是使用外部库。 但这效率不高,速度不够快或无法自定义。 但是最大的问题是可伸缩性。 他们只是无法处理全文搜索引擎可以处理的数据量。
1.2为什么我们需要全文搜索引擎
生成大量数据的过程是我们这个时代的主要特征之一,也是技术进步的主要结果。 它被称为信息过载 。 话虽如此,只有当您能够从中提取有用的信息,并使应用程序的最终用户可以访问这些信息时,收集和存储所有这些数据才有用。 当然,最著名和最常用的工具就是搜索。
有人可能会争辩说,在文件中搜索单词或短语就像从上到下以串行方式扫描文件一样简单,就像使用grep命令一样。 实际上,这可能只需要少量的文档。 但是,拥有数百万个文件的巨大文件系统又如何呢?如果这对您而言似乎非同寻常,那么网页,数据库,电子邮件,代码存储库,仅举几例,将它们全部结合在一起,又如何呢? 容易理解的是,每个用户所需的信息可能驻留在一个小小的文档中,位于大量不同信息资源的某个地方。 而且该文档的检索必须像呼吸一样容易。
现在可以看到为什么完全定制的基于搜索的应用程序越来越受到关注和吸引。 更重要的是,搜索已成为最终用户体验的一个重要方面,以至于对于现代Web应用程序(从简单的博客到Twitter或Facebook之类的大型平台,甚至是军用级应用程序)来说,没有搜索功能都是不可理解的。 这就是为什么大型供应商不想冒险将其搜索功能弄乱,并希望保持它们尽可能快而又简单的原因。 这导致需要将搜索从简单功能升级到完整平台。 具有强大,高效,必要的灵活性和定制性的平台。 而Apache Lucene提供了,这就是为什么在上述大多数应用程序中都使用它的原因。
1.3 Lucene的工作方式
因此,您一定想知道Lucene如何执行快速的全文本搜索。 毫不奇怪,答案是它使用了index 。 Lucene索引属于倒排索引的类别。 倒置索引不是在每个文档中都包含其包含的单词(或术语 )完整列表的经典索引,而是相反。 对于文档中的每个术语 (单词),您都有包含该术语的所有文档的列表。 当执行全文搜索时,这非常方便。
下图显示了反向索引如此之好的原因。 假设您有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)} ...
对于每个术语,我们维护一个包含该术语的所有文档的列表,然后是该术语在文档中的位置(当然,可以保留其他信息)。 现在,当用户搜索术语“ Lucene”时,我们可以立即回答,术语“ Lucene”位于文档1的位置6的位置和文档2的位置4的位置。总而言之,倒排索引使用大量可以立即搜索的小清单。 相反,经典索引将使用少量无法快速搜索的非常大的列表。
1.4基本Lucene工作流程
因此,Lucene必须在实际搜索之前完成一些工作。 大概就是创建索引。 索引过程的基本工作流程如下所示:
如上图所示:
- 您用文本文档/来源来喂它
- 对于每个文档,它都会分析文本并将其拆分为术语 (单词)。 同时,它可以在纯文本中执行各种分析。 您可以定制该步骤以适合您自己的应用程序的需求。
- 对于文档的每个术语,它都会创建先前描述的倒排列表。
- 现在可以开始搜索索引了。 您可以用许多不同的格式编写查询,结果将得到满足查询中指定条件的所有文档的列表。
到目前为止,Lucene似乎是一个非常强大的工具,因为它可以分析文本,创建索引并对该索引执行查询。 但是您必须自己做一些工作,例如选择要建立索引的文档,组织和管理整个过程以及过程的多个方面,以及最终从用户那里获得搜索查询并向他们提供任何可能的结果。
2.索引的基本组件
在本节中,我们将描述用于创建索引的基本组件和基本Lucene类。
2.1目录
Lucene索引仅托管在普通文件系统位置,或在需要额外性能且您不希望将其永久存储在驱动器上时存储在内存中。 您甚至可以选择通过JDBC将索引存储在数据库中。 前述选项的实现扩展了抽象Directory类。
为了简单起见,我们只说它使用了文件系统中的目录,尽管使用内存或数据库时并没有太多区别,但是我认为普通目录更加直观。 Lucene将使用该目录存储索引所需的所有内容。 您可以使用FSDirectory
类使用这样的目录,并为它提供文件系统的任意路径(使用内存时,使用RAMDirectory )。 FSDirectory
类只是普通Java File操作类之上的抽象。
这是创建FSDirectory
:
Directory directory = FSDirectory.open( new File( "C:/Users/nikos/Index" ));
这就是创建RAMDirectory
:
Directory ramDirectory = new RAMDirectory();
2.2文件
如您所记得,我们说过,您有责任选择文档(文本文件,PDF,Word文档等)以及您要搜索的所有文本源,然后对其进行索引。 对于要索引的每个文档,必须创建一个代表该Document
对象。 在这一点上,重要的是要了解文档是索引组件,而不是实际的文本源。 自然,由于Document
代表单个物理文本源,因此它是索引的构建单元。 创建此类文档后,您必须将其添加到索引中。 稍后,在调度搜索时,结果将得到一个满足查询条件的Document
对象的列表。
这样可以创建一个新的空Document
:
Document doc = new Document();
现在是时候用Fields
填充Document了。
2.3领域
Document
对象填充有Fields
的集合。 一个Field
只是一对(名称,值)项。 因此,当创建一个新的Document
对象时,必须用这种对来填充它。 Field
可以存储在索引中,在这种情况下,字段的名称和值都按字面意义存储在索引中。 另外,可以对Field
进行索引 ,或者更精确地说,可以对字段进行倒置 ,在这种情况下,该字段的值将被分析并标记为Terms
,并且可以进行搜索。 Term
表示来自Field
值文本的单词。 Field
既可以被存储又可以被索引/取反 ,但是您不必存储一个字段就可以对其进行索引/取反。 存储字段和对字段建立索引/取反是两个不同的独立事物。
如前所述,在部署搜索时,作为回报,您将获得一个满足查询条件的Document
对象列表(代表物理文本源)。 如果要访问Field
的实际值,则必须声明该Field
存储。 当您要存储本Document
代表的文件名,上次修改日期,完整文件路径或有关您要访问的文本源的任何其他信息时,这通常很有用。 例如,如果您正在索引的文本源是电子邮件,则表示该电子邮件的Document
对象可以具有以下字段:
代表电子邮件的示例文档:
领域 | 已储存 | 索引 | |
名称 | 值 | ||
标题 | 来自示例的电子邮件 | 是 | 没有 |
位置 | 电子邮件位置 | 是 | 没有 |
从 | example@javacodegeeks.com | 是 | 没有 |
至 | foo@example.com | 是 | 没有 |
学科 | 通讯 | 是 | 没有 |
身体 | 嗨,您好 ! 很高兴见到你… | 没有 | 是 |
在以上文档中,我选择了对电子邮件的正文进行索引/反转,但不进行存储。 这意味着将对电子邮件的正文进行分析并将其标记为可搜索的术语,但实际上不会将其存储在索引中。 当文本源的内容量很大并且要节省空间时,可以采用这种策略。 另一方面,我选择存储而不是索引所有其他字段。 当我执行搜索时,将仅搜索正文 ,而搜索中未考虑所有其他字段,因为它们没有被索引。
如果Body
的上述切分项符合查询,这个Document
将被包括在结果中。 现在,当您访问检索到的Document
,您只能查看其存储的Fields
及其值。 因此,尽管可以搜索,但文件的实际主体将无法通过Document
对象提供给您。 您只能看到标题,位置,从,到主题 Fields
。 存储该电子邮件的位置,将有助于我访问其实际正文内容。 当然,如果要通过Document
对象检索电子邮件的主体,从而使其既可搜索又可存储(其他字段也是如此),则也可以存储电子邮件的主体。
因此,让我们看看如何创建上述Document
。 要创建仅存储的字段,我们将使用StoredField
类。 为了创建文本的未存储和索引主体,我们将使用TextField
类。
领域
如您所见,我们给了FileReader
作为"body"
字段的值。 在分析阶段中将使用此FileReader
,以从该源中提取纯文本。 从文件中提取纯文本后,Lucene的特殊组件将对其进行分析并将其拆分为索引词。
2.4条款
术语表示文本中的单词。 术语是从Fields值的分析和标记化中提取的,因此Term
是搜索的单位。 术语由两个元素组成,实际的文字单词(可以从文字到电子邮件地址,日期等的任何形式)以及该单词出现的字段的名称。
标记和分析字段以从中提取术语并不是绝对必要的。 在上一个示例中,如果要对“ From Field
索引,则不必真正将其标记化。 电子邮件地址example@javacodegeeks.com可以用作Term
。
2.5分析仪
Analyzer
是索引和搜索过程中最关键的组件之一。 它负责获取纯文本并将其转换为可搜索的术语。 现在,重要的是要了解分析器可以使用纯文本输入。 提供一个解析器以将文本源(例如HTML页面或文件系统中的文件)转换为纯文本,是程序员的责任。 该解析器通常是Reader。 例如,如果是文件,则可以是FileReader。
分析器内部使用Tokenizer 。 令牌生成器可以将上述阅读器用作输入,并使用它从特定来源(例如文件)中提取纯文本。 在获得纯文本之后,令牌生成器将文本简单地拆分为单词。 但是,分析器可以做的不仅仅是简单的文本拆分。 它可以执行多种文本和单词分析,例如:
- 词干:用词干代替词。 例如,在英语中,“橙色”的词干是“橙色”。 因此,如果最终用户搜索“橙色”,则将获得包含“橙色”和“橙色”的文档。
- 停用词过滤:执行搜索时,诸如“ the”,“ and”和“ a”之类的词没有特别的意义,因此不妨将其视为“噪音”。 删除它们将导致更好的性能和更准确的结果。
- 文本规范化:删除重音符号和其他字符标记。
- 同义词扩展:在与当前单词相同的标记位置添加同义词。
这些只是Lucenes Analyzer类内置的一些分析工具。 分析器中最常用的内置工具是StandardAnalyzer ,它可以删除停用词,将单词转换为小写字母并进行词干处理。 如您所知,不同的语言有不同的语法规则。 Lucene社区正在尝试为尽可能多的不同语言嵌入尽可能多的语法。 但是,如果Lucene的内置分析仪都不适合您的应用程序,则可以创建自己的分析仪。
2.6与索引互动
到目前为止,我们已经看到了如何创建索引Directory
,创建Document
并向其添加Fields
。 现在,我们必须将Document
写入Directory
,然后将其添加到索引。 这也是步骤,其中Analyzers
和Tokenizers
发挥自己的部分。
正如您所期望的那样,在Lucene中没有称为Index (或类似的东西)的特殊类。 与索引进行交互的方式是通过IndexWriter
,当您要将内容推送到索引(并通常对其进行操作)时,通过IndexReader从索引中读取内容,以及通过IndexSearcher
,当您要搜索索引时课程。
现在,让我们看看如何创建所需的IndexWriter
:
领域
我们选择为此使用StandardAnalyzer
实例。 其构造函数将Version.LUCENE_46
作为参数。 这有助于发现多个Lucene版本之间的兼容性依赖性。 请记住, StandardAnalyzer
在内部使用StandardTokenizer
。 然后,我们创建一个IndexWriterConfig
实例。 这是一个帮助程序类,可以保存IndexWriter
所有配置选项。 如您所见,我们已指定我们希望IndexWriter
使用先前创建的analyzer
并将其设置为适当的版本。 最后,我们创建IndexWriter
实例。 在其构造函数参数中,我们提供FSDirectory
实例和先前创建的配置选项。
现在,您可以继续使用上述IndexWriter
将先前创建的Document
添加到Index中:
领域
就是这样。 现在,当addDocument
时,所有前面描述的操作都会发生:
-
Tokenizer
使用FileReader
读取文件并将其转换为纯文本。 然后将其分解为令牌。 - 同时,
Analyzer
可以对纯文本然后对单个标记执行各种语法和语法分析。 - 通过令牌分析,将创建
Terms
并用于生成倒排索引。 - 最后,将包含
Document
和索引的所有信息的所有必需文件都写入指定的路径:"C:/Users/nikos/Index"
。
现在我们的文档已建立索引。 添加到索引的每个Document
都遵循相同的过程。
现在,一切都变得更加清晰了,让我们来看一下在图表中使用的类的索引编制过程:
如你看到的:
- 我们将
Document
对象传递给IndexWriter
。 - 他使用
Analyzer
从Reader
获得的纯文本中生成Terms
。 - 然后,他将更新索引所需的所有内容都写入
Directory
。
尝试构建搜索引擎时,索引编制工作很难,因为您必须:
- 选择您要索引的文档和文本源。
- 提供读取器类,以读取文本源并将其转换为纯文本。 内置的类(或外部库)种类繁多,可以读取大量的文档格式。 但是,如果它们都不适合您的文档,则您将必须编写自己的Reader来解析它们并将其转换为纯文本。
- 确定适合您应用程序需求的标记和分析策略。 大多数应用程序使用StandardAnalyzer和StandardTokenizer都可以正常工作。 但是,您可能想进一步自定义分析步骤,这需要做一些工作。
- 确定使用哪种字段,以及存储和/或索引哪些字段。
3.搜索的基本组件
在本节中,我们将描述用于执行搜索的基本组件和基本Lucene类。 搜索是Lucene这样的平台的目标,因此它必须尽可能灵活和容易。
3.1 QueryBuilder和查询
在Lucene中,传递给Index的每个查询都是一个Query对象。 因此,在与索引进行实际交互以执行搜索之前,必须构建此类对象。
一切都以查询字符串开头。 就像您放在众所周知的搜索引擎(例如Google)上的查询字符串一样。 可以是任意短语,也可以是结构更复杂的短语,我们将在下一课中看到。 但是只发送要在索引中搜索的原始字符串将是没有用的。 您必须像处理带索引的纯文本一样处理它。 您必须将查询字符串拆分为单词并创建可搜索的术语。 据推测,这可以使用分析仪来完成。
注意:需要注意的重要一点是,您应该使用与用于索引过程的分析器相同的Analyzer子类来检查查询,以检查纯文本。
这是创建由StandardAnalyzer处理的简单查询的方式:
领域
我们将QueryBuilder对象与StandarAnalyzer的实例绑定。 现在,您可以使用该QueryBuilder实例创建Query对象。
Query是一个抽象类,并且有许多具体的子类可用,例如:
- 搜索包含特定术语的Document的
TermQuery
。 - 创建其他查询的布尔组合的
BooleanQuery
-
WildcardQuery
以实现通配符搜索,例如用于查询字符串“ * abc *”。 -
PhraseQuery
可以搜索整个短语,而不仅仅是单个术语。 -
PrefixQuery
搜索具有预定义前缀的术语。
所有这些不同的Query
风格都将确定将在索引上执行的搜索的性质。 并且每个对象都可以通过该QueryBuilder
实例获得。 在我们的示例中,我们选择使用createBooleanQuery
方法。 它有两个参数。 第一个是将要搜索其值(确定为索引且可能已标记化)的Field
的名称。 第二个是将使用StandardAnalyzer
分析的查询字符串。 createBooleanQuery
可以根据查询字符串的语法返回TermQuery
或BooleanQuery
。
3.2 IndexReader
大概是要在索引中进行搜索,首先必须打开它。 您可以使用IndexReader打开和访问它。 所有需要将数据从索引中拉出的过程都通过该抽象类。
使用IndexReader
打开已经创建的索引非常容易:
领域
如您所见,我们使用DirectoryReader打开存储索引的目录。 DirectoryReader
返回索引的句柄,这就是IndexReader
的含义。
3.3 IndexSearcher
IndexSearcher
是用于搜索单个Index的类。 它与IndexReader
绑定。
这是创建一个的方法:
领域
您可以使用IndexSearcher
将Query
对象传递给IndexReader
。 方法如下:
领域
我们使用IndexSearcher
public TopDocs search(Query query, int n)
方法执行搜索。 此方法需要两个参数。 第一个是Query
对象。 第二个是整数,用于设置返回的搜索结果数的限制。 例如,如果您有10000个满足查询条件的文档,则可能不希望全部返回。 您可以声明只需要前n个结果。 最后,该方法返回一个TopDocs
实例。
3.4 TopDocs
TopDocs
类表示满足您的查询的匹配。 TopDocs
有一个public ScoreDoc[]
类字段。
3.5 ScoreDoc
SocreDoc
代表查询命中。 它包括 :
- 一个
public int doc
字段,即满足查询条件的Document
的ID。 - 还有一个
public float score
字段,即Document
在查询中获得的分数。
评分公式是任何搜索平台中必不可少且非常复杂的部分,这正是Lucene发挥出色的作用。 该公式用于为检索到的文档提供相关性度量。 分数越高,Document与您的查询越相关。 这有助于表征“好”和“差”的文档,并确保为您提供尽可能接近您真正需要的文档的高质量结果。 您可以在当前版本的“ 相似性”类的文档, 旧版本的“ 相似性”类的文档中以及此信息检索文章中找到一些有关评分的有用信息。
4.一个简单的搜索应用程序
我们将构建一个简单的搜索应用程序,该应用程序将演示索引和搜索的基本步骤。 在此应用程序中,我们将使用包含一堆Java源文件的输入文件夹。 本文档中的每个文件都将被处理并添加到索引中。 然后,我们将对该索引执行简单查询,以了解其工作原理。
我们将使用:
- Eclipse Kepler 4.3作为我们的IDE。
- JDK 1.7。
- Maven 3构建我们的项目。
- Lucene 4.6.0,Lucene的最新版本。
首先,让我们使用Eclipse创建我们的Maven项目。
4.1使用Eclipse创建一个新的Maven项目
打开Eclipse并转到File-> New-> Other-> Maven-> Maven Project,然后单击Next。
在下一个窗口中,选择“创建简单项目(跳过原型选择)”选项,然后单击下一步:
在下一个窗口中,填写组ID和工件ID,如下图所示,然后单击“完成”:
将使用以下结构创建一个新的Maven项目:
4.2 Maven依赖
打开pom.xml
并添加使用Lucene库所需的依赖项:
pom.xml:
领域
如您所见,我们将导入提供所有核心类的lucene-core-4.6.0.jar
,以及提供所有文本分析所需的所有类的lucene-analyzers-common-4.6.0.jar
包。
一个简单的索引器类
要创建此类,请转到Eclipse的Package Explorer。 在src/java/main
创建一个名为com.javacodegeeks.enterprise.lucene.index
的新包。 在新创建的包下,创建一个名为SimpleIndexer
的新类。
让我们看一下该类的代码,该代码将进行索引编制:
SimpleIndexer.java:
领域
在上述类中,我们指定了将文本文件放置在C:/Users/nikos/Desktop/LuceneFolders/LuceneHelloWorld/SourceFiles
输入文件夹,还将要存储索引的文件夹放置在C:/Users/nikos/Desktop/LuceneFolders/LuceneHelloWorld/Index
。
在index
方法上,首先我们创建一个新的StandardAnalyzer
实例和一个新的IndexWriter
实例。 IndexeWriter
将使用StrandardAnalyzer分析文本,并将索引存储在FSDirectory
指向上述索引路径。
有趣的是在for
循环上。 对于源目录中的每个文件:
- 我们创建一个新的
Document
实例。 - 我们添加了一个新的
Filed
,确切地说是一个TextField
,它表示文件的内容。 请记住,TextField
用于创建一个字段,该字段的值将被标记和索引但不存储 。 - 我们添加了另一个
Field
,这次是一个StoredFiled
,其中包含文件名。 请记住,StoredField
用于刚刚存储 , 未建立索引和未标记化的字段。 因为我们将文件名存储为完整路径,所以以后可以使用它来访问,显示和检查其内容。 - 然后,我们只需将
Document
添加到索引中即可。
循环后:
- 我们调用
IndexWriter
maxDoc()
方法,该方法返回索引Documents
的数量。 - 我们关闭
IndexWriter
,因为我们不再需要它,因此系统可以回收其资源。
当我运行此代码时,这是它产生的输出 :
领域
Here is the index folder in my system. As you can see, several special files are created (more on that next lessons):
Now let's search that index.
4.4。
To create this class go to the Package Explorer of Eclipse. Under src/java/main
create a new package named com.javacodegeeks.enterprise.lucene.search
. Under the newly created package, create a new class named SimpleSearcher
.
To get a more clear view of he final structure of the project, have a look at the image bellow:
Let's see the code of that class, which will do the searching:
SimpleSearcher.java:
领域
In the searchIndex
method we pass the index directory and the query string as arguments. So I'm going to search for “private static final String”. Remember that the files I've indexed were Java source files,
The code is pretty self explanatory:
- We open the index directory and obtain the
IndexReader
andIndexSearcher
classes. - We then use the
QueryBuilder
, fed with theStrandardAnalyzer
, to build ourQuery
object. We usedcreateBooleanQuery
to obtain theQuery
object. Our query string does not have a boolean format (as we will see in the next lesson), so the method will createTermQueries
for the analyzed and tokenized terms of the query string. - We then use the search method of the
IndexSearcher
to perform the actual search. - We obtain the
ScoreDocs
that satisfied the query from theTopDocs
returned from thesearch
method. For every ID in thatScoreDocs
array, we obtain the correspondingDocument
from theIndexSearcher
. - From that
Document
, usingget
method, we obtain the name of the file, stored in the value of the “fileName”Field
. - We finally print the name of the file and the score it achieved.
Let's run the program and see what is the output :
领域
It is important to understand that these files do not certainly contain the whole phrase "private static final String"
. Intuitively, the documents with the higher score contain most of the words of that sentence and more frequently than documents with smaller scores. Of course the scoring formula is much more complex than that, as we said earlier.
For example if you change:
领域
至
领域
the whole phrase will be searched. Only documents that contain the whole phrase will be returned. When you run the code with that minor change, here is the output :
领域
These files contain the whole query string "private static final String"
in their contents.
4.5 Download the source code
You can download the Eclipse project of this example here: LuceneHelloWorld.zip
5. Final notes
It is important to mention that an IndexReader
reads the “image” that the index has the moment he opens it. So, if your application is dealing with text sources that change over short periods of time, it is possible that you have to re-index those files at run time. But you want to be sure that the changes are reflected when you search the Index, while your application is still running and you have already opened an IndexReader
(who now is outdated). In this case you have to obtain an updated IndexReader
like this:
领域
This will ensure that you get a new more updated IndexReader
, but only if the index has changed. Furthermore, if you want to achieve fast, near real time searches ( eg for stream data) you can obtain your IndexReader
like so:
领域
For performance reasons, the IndexWriter
doesn't flush the changes of the index immediately to the disk. It uses buffers instead, and persists the changes asynchronously. Opening an IndexReader
like in the above snippet, gives him immediate access to the write buffers of the IndexWriter
, and thus he has instant access to index updates.
Finally, it's worth mentioning that IndexWriter
is thread safe, thus you can use the same instance in many threads to add Documents
one particular index. The same goes for the IndexReader
and IndexSearcher
. Many threads can use the same instance of these classes to simultaneously read or search the same index.
翻译自: https://www.javacodegeeks.com/2015/09/introduction-to-lucene.html
lucene简介