Lucene.Net 简介






4.86/5 (83投票s)
深入了解创建具有高级搜索功能的快速全文索引。
什么是 Lucene.Net?
Lucene.Net 是一个高性能的信息检索 (IR) 库,也称为搜索引擎库。Lucene.Net 包含强大的 API,用于创建全文索引,并将高级且精确的搜索技术集成到您的程序中。有些人可能会将 Lucene.Net 与现成的应用程序混淆,例如网络搜索/爬虫或文件搜索应用程序,但 Lucene.Net 并非此类应用程序,它是一个框架库。Lucene.Net 提供了一个框架,供您自己实现这些复杂的技术。Lucene.Net 对您可以索引和搜索的内容不做任何区分,这比其他全文索引/搜索实现提供了更大的灵活性;您可以索引任何可以表示为文本的内容。还有一些方法可以让 Lucene.Net 索引 HTML、Office 文档、PDF 文件等。
Lucene.Net 是原始 Lucene 项目的 API 对 API 端口,该项目是用 Java 编写的,甚至单元测试也已移植以保证质量。此外,Lucene.Net 索引与 Lucene 索引完全兼容,两个库可以一起在同一个索引上使用,没有任何问题。许多产品使用 Lucene 和 Lucene.Net 来构建它们的搜索;一些知名的网站包括 Wikipedia、CNET、Monster.com、Mayo Clinic、FedEx 以及 更多。但是,不仅仅是网站使用 Lucene;还有一个名为 Lookout 的产品使用了 Lucene.Net,这是一个用于 Microsoft Outlook 的搜索工具,它使得 Outlook 的集成搜索显得非常缓慢和不准确。
Lucene.Net 目前正在 Apache 软件基金会进行孵化。其源代码存储在一个 subversion 存储库中,可以在 这里 找到。如果您需要下载源代码的帮助,可以使用免费的 TortoiseSVN 或 RapidSVN。Lucene.Net 项目始终欢迎新贡献者。并且,请记住,除了编写代码之外,还有 多种方式 可以为开源项目做出贡献。
创建搜索解决方案
搜索解决方案大致有两个主要部分。索引您希望搜索的内容,以及实际搜索内容。而且,这几乎就是这么简单。在我们拥有索引后,我们将执行搜索。
创建索引所需的内容
让我们看一个创建索引并填充它的例子。
//state the file location of the index
string indexFileLocation = @"C:\Index";
Lucene.Net.Store.Directory dir =
Lucene.Net.Store.FSDirectory.GetDirectory(indexFileLocation, true);
//create an analyzer to process the text
Lucene.Net.Analysis.Analyzer analyzer = new
Lucene.Net.Analysis.Standard.StandardAnalyzer();
//create the index writer with the directory and analyzer defined.
Lucene.Net.Index.IndexWriter indexWriter = new
Lucene.Net.Index.IndexWriter(dir, analyzer,
/*true to create a new index*/ true);
//create a document, add in a single field
Lucene.Net.Documents.Document doc = new
Lucene.Net.Documents.Document();
Lucene.Net.Documents.Field fldContent =
new Lucene.Net.Documents.Field("content",
"The quick brown fox jumps over the lazy dog",
Lucene.Net.Documents.Field.Store.YES,
Lucene.Net.Documents.Field.Index.TOKENIZED,
Lucene.Net.Documents.Field.TermVector.YES);
doc.Add(fldContent);
//write the document to the index
indexWriter.AddDocument(doc);
//optimize and close the writer
indexWriter.Optimize();
indexWriter.Close();
好了,不错,让我们看看我们刚刚做了什么。这里使用了五个主要类,它们是 Directory
、Analyzer
、IndexWriter
、Document
和 Field
。我们创建一个 Directory
,让 Lucene 知道我们将把索引存储在哪里。Analyzer
用于分析文本。我们有一个 IndexWriter
,它使用 Directory
和 Analyzer
来创建和写入索引。然后,我们创建一个新的 Document
对象,并创建一个 Field
,其字段名称设置为“content”,值为“The quick brown fox jumps over the lazy dog”。我们将 Field
添加到 Document
中,现在,我们可以使用 IndexWriter
索引新创建的 Document
。然后,我们有一个看起来很奇怪的 Optimize
调用(稍后会详细介绍),并在完成后调用 Close
来关闭写入器。我们已成功创建了一个准备好进行搜索的全文索引。首先,让我们稍微详细地介绍一下我们刚刚使用的一些类。
Lucene.Net.Store.Directory
–Directory
是一个基类,用于提供目录的抽象视图。Lucene.Net 提供了两个实现。FSDirectory
使用文件目录来存储索引。RAMDirectory
是一个内存中的目录,您可以使用它来存储索引。您可以继承Directory
类来实现自己的自定义目录对象来存储索引。Lucene.Net.Analysis.Analyzer
–Analyzer
是一个基类,负责将文本分解为单个单词或词条,并删除任何停用词,或者 Lucene.net 称之为停用词;停用词包括“and”、“a”、“the”等。现在,我们将仅使用StandardAnalyzer
类,因为它是一个非常好的第一选择。您可以将您自己的停用词列表作为字符串数组传递给StandardAnalyzer
的构造函数。使用默认构造函数将使用默认的停用词列表。您可以继承Analyzer
来实现自定义的处理要索引的文档的方式。Lucene.Net.Index.IndexWriter
–IndexWriter
负责协调Analyzer
并将结果发送到Directory
进行存储。在创建索引期间,写入器将在Directory
中创建一些文件。当我们向索引写入器添加文档时,索引写入器将使用Analyzer
来分解每个字段,并找到一个位置将索引的文档存储在Directory
中。在完成一次索引会话后,建议您优化索引,这会压缩索引以获得资源消耗更少的模型。另请注意,不建议您为添加到索引的每个Document
调用Optimize
,最好在索引会话后只调用一次,如果可能的话。在IndexWriter
的构造函数结束时,我们将true
指定为创建新索引。要添加更多文档到索引,您应该将false
指定在这里,以避免覆盖索引。Lucene.Net.Documents.Document
–Document
类是由IndexWriter
索引的内容。您可以将Document
视为一个您想要检索的实体;一个Document
可以代表一封电子邮件、一个网页、一个食谱,甚至是一篇 CodeProject 文章。Lucene.Net.Documents.Field
–Document
包含一个Field
列表,用于描述文档。每个字段都有一个名称和一个值。每个字段的值都包含您希望使其可搜索的文本。字段构造函数的其他部分包含有关如何处理单个字段的说明。Field.Store
说明告诉IndexWriter
您希望将字段的值存储在索引中,以便稍后检索该值并对其进行操作,例如在搜索结果中向用户显示数据或存储一个标识值,例如此字段文档所代表对象的初识键。
其他说明是 Field.Index
值,它们告诉 IndexWriter
如何(如果根本)索引该字段。可能的值包括 Field.Index.TOKENIZED
,这意味着我们希望使用 IndexWriter
提供的 Analyzer
来分解字符串并使其可搜索。另一个选项是 Field.Index.UNTOKENIZED
,它仍然会索引该字段,但作为一个整体,并且不会被 Analyzer
分解。存储值和索引值之间的区别在于,当您存储值时,目的是能够从索引中检索回该值。而索引值的目的是使字段的值可搜索。存储一个值但不对其进行索引是完全可以接受的,就像您可能希望存储一个标识值但不想对其进行索引一样,而您可能希望索引一封电子邮件的内容,但实际上不想在搜索结果中显示该内容。另一组说明定义了如何处理 TermVector
。将 TermVector
存储在索引中用于 Lucene 的高级功能,该功能不完全匹配搜索查询项,但使用词向量,您将能够检索相关文档 - 例如,关于同一主题的文档。
在对一些文档进行了良好的索引后,我相信我们已经准备好迎接有趣的部分了。
搜索索引所需的内容
让我们看一个执行简单搜索所需的示例。
//state the file location of the index
string indexFileLocation = @"C:\Index";
Lucene.Net.Store.Directory dir =
Lucene.Net.Store.FSDirectory.GetDirectory(indexFileLocation, true);
//create an index searcher that will perform the search
Lucene.Net.Search.IndexSearcher searcher = new
Lucene.Net.Search.IndexSearcher(dir);
//build a query object
Lucene.Net.Index.Term searchTerm =
new Lucene.Net.Index.Term("content", "fox");
Lucene.Net.Search.Query query = new Lucene.Net.Search.TermQuery(searchTerm);
//execute the query
Lucene.Net.Search.Hits hits = searcher.Search(query);
//iterate over the results.
for (int i = 0; i < hits.Length(); i++)
{
Document doc = hits.Doc(i);
string contentValue = doc.Get("content");
Console.WriteLine(contentValue);
}
使用这段简短的代码,我们定义了索引的存储位置,再次通过使用 Directory
类。但是现在,我们有了这个 IndexSearch
对象,它完成了实际搜索的所有繁重工作。要使用 IndexSearcher
,我们必须向其传递一个 Query
对象。您从 IndexSearcher
对象调用 Search
方法,并将 Query
对象传递给搜索。它将返回一个 Hits
对象。最后,通过迭代 Hits
,我们可以提取与该查询匹配的 Document
。在我们获得文档后,我们可以提取在索引该文档时曾存储过的字段的值。让我们更仔细地看看这些类!
Lucene.Net.Search.IndexSearcher
–IndexSearcher
对象再次完成了实际搜索的所有繁重工作。当执行搜索时,它将使用传递给IndexSearcher
构造函数的Directory
对象将索引打开为只读文件。IndexSearcher
对象上还有更多方法,提供了其他查询索引的方式。Lucene.Net.Index.Term
–Term
是最基本的搜索结构。Term
由两部分组成,您要搜索的字段的名称,以及该字段的值。Lucene.Net.Search.Query
– 一个基类,它与IndexSearcher
一起提供结果。Query
是一个抽象基类。在上面的示例中,我们使用了TermQuery
对象,该对象对单个Term
进行查询。还有许多其他创建查询的方式。Query
类的一些实现,除了TermQuery
之外,还包括BooleanQuery
、PhraseQuery
、PrefixQuery
、PhrasePrefixQuery
、RangeQuery
、FilteredQuery
和SpanQuery
。有了所有这些查询选项,我们就需要一种方法让用户从单个文本框中进行强大的查询。这就是另一个类的作用,那就是QueryParser
。稍后会详细介绍。Lucene.Net.Search.Hits
– 这代表搜索返回的文档列表。Hits
对象可以被迭代,并负责从搜索中获取文档。对于大型索引,不建议迭代所有搜索结果。另外,值得注意的是,Hits
对象不会立即加载所有文档,它只加载一部分文档。否则,会导致性能问题。在获得Hits
对象后,您可以调用Doc(int index)
方法,该方法将返回与单个命中相关的文档。
正如我之前提到的,Query
类有许多实现,它们在查询中都有其位置。通常,您不会自己创建查询对象,而是让一个强大的解析器使用简单的语法为您构建复杂的查询,就像您搜索 Google 一样。这就是我向您介绍 QueryParser
的地方。QueryParser
实例有一个名为 Parse(string query)
的方法。以下是使用 QueryParser
的小示例。
//create an analyzer to process the text
Lucene.Net.Analysis.Analyzer analyzer = new
Lucene.Net.Analysis.Standard.StandardAnalyzer();
//create the query parser, with the default search feild set to "content"
Lucene.Net.QueryParsers.QueryParser queryParser = new
Lucene.Net.QueryParsers.QueryParser("content", analyzer);
//parse the query string into a Query object
Lucene.Net.Search.Query
query = queryParser.Parse("fox");
而且,如果您认为所有这些东西都很棒,我们才刚刚触及表面。但是,本文到此就结束了。如果您想了解更多信息,请告诉我,我将开始撰写另一篇关于 Lucene.Net 的文章。