`

Lucene.NET 使用

阅读更多
本文仅记录一些简单的使用方法,供初学者参考。
以下例子采用 Lucene.NET 1.9 版本,可取去 Lucene.Net 下载。

1. 基本应用
using System;
using System.Collections.Generic;
using System.Text;
using Lucene.Net;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;

namespace ConsoleApplication1.Lucene
{
public class LuceneTest
{
private const string FieldName = "name";
private const string FieldValue = "value";

private Directory directory = new RAMDirectory();
private Analyzer analyzer = new StandardAnalyzer();

public LuceneTest()
{
}

private void Index()
{
IndexWriter writer = new IndexWriter(directory, analyzer, true);
writer.maxFieldLength = 1000;

for (int i = 1; i <= 100; i++)
{
Document document = new Document();

document.Add(new Field(FieldName, "name" + i, Field.Store.YES, Field.Index.UN_TOKENIZED));
document.Add(new Field(FieldValue, "Hello, World!", Field.Store.YES, Field.Index.TOKENIZED));

writer.AddDocument(document);
}

writer.Optimize();
writer.Close();
}

private void Search()
{
Query query = QueryParser.Parse("name*", FieldName, analyzer);

IndexSearcher searcher = new IndexSearcher(directory);

Hits hits = searcher.Search(query);

Console.WriteLine("符合条件记录:{0}; 索引库记录总数:{1}", hits.Length(), searcher.Reader.NumDocs());
for (int i = 0; i < hits.Length(); i++)
{
int docId = hits.Id(i);
string name = hits.Doc(i).Get(FieldName);
string value = hits.Doc(i).Get(FieldValue);
float score = hits.Score(i);

Console.WriteLine("{0}: DocId:{1}; Name:{2}; Value:{3}; Score:{4}",
i + 1, docId, name, value, score);
}

searcher.Close();
}
}
}

除了 RAMDirectory,还可以使用 FSDirectory。(注意 FSDirectory.GetDirectory 的 create 参数,为 true 时将删除已有索引库文件,可以通过 IndexReader.IndexExists() 方法判断。)

从指定目录打开已有索引库。
private Directory directory = FSDirectory.GetDirectory("c:\index", false);

将索引库载入内存,以提高搜索速度。
private Directory directory = new RAMDirectory(FSDirectory.GetDirectory(@"c:\index", false));
//或
//private Directory directory = new RAMDirectory(c:\index");

2. 多字段搜索

使用 MultiFieldQueryParser 可以指定多个搜索字段。
Query query = MultiFieldQueryParser.Parse("name*", new string[] { FieldName, FieldValue }, analyzer);

IndexReader reader = IndexReader.Open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

3. 多条件搜索

除了使用 QueryParser.Parse 分解复杂的搜索语法外,还可以通过组合多个 Query 来达到目的。
Query query1 = new TermQuery(new Term(FieldValue, "name1")); // 词语搜索
Query query2 = new WildcardQuery(new Term(FieldName, "name*")); // 通配符
//Query query3 = new PrefixQuery(new Term(FieldName, "name1")); // 字段搜索 Field:Keyword,自动在结尾添加 *
//Query query4 = new RangeQuery(new Term(FieldNumber, NumberTools.LongToString(11L)), new Term(FieldNumber, NumberTools.LongToString(13L)), true); // 范围搜索
//Query query5 = new FilteredQuery(query, filter); // 带过滤条件的搜索

BooleanQuery query = new BooleanQuery();
query.Add(query1, BooleanClause.Occur.MUST);
query.Add(query2, BooleanClause.Occur.MUST);

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

4. 设置权重

可以给 Document 和 Field 增加权重(Boost),使其在搜索结果排名更加靠前。缺省情况下,搜索结果以 Document.Score 作为排序依据,该数值越大排名越靠前。Boost 缺省值为 1。
Score = Score * Boost

通过上面的公式,我们就可以设置不同的权重来影响排名。

如下面的例子中根据 VIP 级别设定不同的权重。
Document document = new Document();
switch (vip)
{
case VIP.Gold: document.SetBoost(2F); break;
case VIP.Argentine: document.SetBoost(1.5F); break;
}

只要 Boost 足够大,那么就可以让某个命中结果永远排第一位,这就是百度等网站的"收费排名"业务。明显有失公平,鄙视一把。 [no]

5. 排序

通过 SortField 的构造参数,我们可以设置排序字段,排序条件,以及倒排。
Sort sort = new Sort(new SortField(FieldName, SortField.DOC, false));

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query, sort);

排序对搜索速度影响还是很大的,尽可能不要使用多个排序条件。

6. 过滤

使用 Filter 对搜索结果进行过滤,可以获得更小范围内更精确的结果。

举个例子,我们搜索上架时间在 2005-10-1 到 2005-10-30 之间的商品。
对于日期时间,我们需要转换一下才能添加到索引库,同时还必须是索引字段。
// index
document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);

//...

// search
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-1"), DateTime.Parse("2005-10-30"));
Hits hits = searcher.Search(query, filter);

除了日期时间,还可以使用整数。比如搜索价格在 100 ~ 200 之间的商品。
Lucene.Net NumberTools 对于数字进行了补位处理,如果需要使用浮点数可以自己参考源码进行。
// index
document.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));

//...

// search
Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true);
Hits hits = searcher.Search(query, filter);

使用 Query 作为过滤条件。
QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer));

我们还可以使用 FilteredQuery 进行多条件过滤。
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-10"), DateTime.Parse("2005-10-15"));
Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true);

Query query = QueryParser.Parse("name*", FieldName, analyzer);
query = new FilteredQuery(query, filter);
query = new FilteredQuery(query, filter2);

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

7. 分布搜索

我们可以使用 MultiReader 或 MultiSearcher 搜索多个索引库。
MultiReader reader = new MultiReader(new IndexReader[] { IndexReader.Open(@"c:\index"), IndexReader.Open(@"\\server\index") });
IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);


IndexSearcher searcher1 = new IndexSearcher(reader1);
IndexSearcher searcher2 = new IndexSearcher(reader2);
MultiSearcher searcher = new MultiSearcher(new Searchable[] { searcher1, searcher2 });
Hits hits = searcher.Search(query);

还可以使用 ParallelMultiSearcher 进行多线程并行搜索。

8. 合并索引库

将 directory1 合并到 directory2 中。
Directory directory1 = FSDirectory.GetDirectory("index1", false);
Directory directory2 = FSDirectory.GetDirectory("index2", false);

IndexWriter writer = new IndexWriter(directory2, analyzer, false);
writer.AddIndexes(new Directory[] { directory });
Console.WriteLine(writer.DocCount());
writer.Close();

9. 显示搜索语法字符串

我们组合了很多种搜索条件,或许想看看与其对等的搜索语法串是什么样的。
BooleanQuery query = new BooleanQuery();
query.Add(query1, true, false);
query.Add(query2, true, false);
//...

Console.WriteLine("Syntax: {0}", query.ToString());

输出:
Syntax: +(name:name* value:name*) +number:[0000000000000000b TO 0000000000000000d]

呵呵,就这么简单。

10. 操作索引库

删除 (软删除,仅添加了删除标记。调用 IndexWriter.Optimize() 后真正删除。)
IndexReader reader = IndexReader.Open(directory);

// 删除指定序号(DocId)的 Document。
reader.Delete(123);

// 删除包含指定 Term 的 Document。
reader.Delete(new Term(FieldValue, "Hello"));

// 恢复软删除。
reader.UndeleteAll();

reader.Close();

增量更新 (只需将 create 参数设为 false,即可往现有索引库添加新数据。)
Directory directory = FSDirectory.GetDirectory("index", false);
IndexWriter writer = new IndexWriter(directory, analyzer, false);
writer.AddDocument(doc1);
writer.AddDocument(doc2);
writer.Optimize();
writer.Close();

11. 优化

批量向 FSDirectory 增加索引时,增大合并因子(mergeFactor )和最小文档合并数(minMergeDocs)有助于提高性能,减少索引时间。
IndexWriter writer = new IndexWriter(directory, analyzer, true);

writer.maxFieldLength = 1000; // 字段最大长度
writer.mergeFactor = 1000;
writer.minMergeDocs = 1000;

for (int i = 0; i < 10000; i++)
{
// Add Documentes...
}

writer.Optimize();
writer.Close();

相关参数说明


转自《深入 Lucene 索引机制

利用 Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中。为了解决这个问题, Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?幸运的是,Lucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。

1.合并因子 (mergeFactor)

这个参数决定了在 Lucene 的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如,如果合并因子的值是 10,那么当内存中的文档数达到 10 的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且,如果磁盘上的索引块的隔数达到 10 的话,这 10 个索引块会被合并成一个新的索引块。这个参数的默认值是 10,如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲,为这个参数赋一个比较大的值会得到比较好的索引效果。

2.最小合并文档数 (minMergeDocs)

这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10,如果你有足够的内存,那么将这个值尽量设的比较大一些将会显著的提高索引性能。

3.最大合并文档数 (maxMergeDocs)

这个参数决定了一个索引块中的最大的文档数。它的默认值是 Integer.MAX_VALUE,将这个参数设置为比较大的值可以提高索引效率和检索速度,由于该参数的默认值是整型的最大值,所以我们一般不需要改动这个参数。
分享到:
评论

相关推荐

    lucene.NET使用教程整合

    lucene.NET使用教程整合 lucene.NET使用教程整合 lucene.NET使用教程整合 lucene.NET使用教程整合 lucene.NET使用教程整合 lucene.NET使用教程整合

    Lucene.Net

    4. **高效存储**:Lucene.Net使用倒排索引技术,极大地提高了搜索速度。同时,它还支持压缩,以减少磁盘空间占用。 5. **内存优化**:Lucene.Net在内存管理和缓存策略上进行了优化,能在大规模数据集上保持良好的...

    lucene.NET 中文分词

    - **缓存策略**:合理使用Lucene.NET的缓存机制,如TermVector缓存,可以提升查询性能。 总的来说,Lucene.NET在中文分词和高亮显示方面的应用需要结合合适的分词器,并进行适当的配置和优化。开发者可以根据实际...

    Lucene.Net2.0(C#)

    Lucene.Net使用TF-IDF(词频-逆文档频率)算法来计算文档与查询的相关性。每个匹配的文档都会得到一个分数,这个分数用于决定搜索结果的排序。此外,还可以通过自定义ScoreComparator来实现更复杂的排序逻辑。 五、...

    Lucene.net搜索

    1. **高性能**:Lucene.NET 使用倒排索引,可以实现快速的全文搜索,查询速度极快。 2. **灵活性**:支持多种数据源和多种格式的文档,可以通过自定义分析器处理不同语言和文本类型。 3. **易用性**:API 设计直观...

    lucene.net+完全入门教程

    5. **结果排序**: Lucene.Net使用Scorer类对搜索结果进行评分,基于查询词在文档中的频率和位置等因素。然后,可以使用TopDocs类获取最高得分的文档。 6. **更新与删除**: 当文档内容变化或需要删除时,可以通过...

    Lucene.Net的DLL

    这个DLL包含了文档处理、索引构建、查询解析、结果排序等功能的类和接口,是使用Lucene.Net进行全文搜索的基础。 使用Lucene.Net,开发者可以构建自定义的搜索解决方案,包括但不限于以下步骤: 1. **创建索引**:...

    lucene.net以及高亮的DLL文件

    3. **索引**:Lucene.Net使用倒排索引技术,这是一种高效的数据结构,它将每个词汇项映射到包含该词汇项的文档列表,便于快速查找匹配的文档。 4. **搜索**:用户输入查询后,Lucene.Net会解析查询语句,生成一个...

    Lucene.net学习帮助文档

    使用Lucene.net,你可以创建自己的网站搜索引擎。首先,你需要定义要索引的数据源,然后创建索引,接着配置查询解析器以理解用户的输入,最后执行查询并返回结果。在这个过程中,你还可以实现高级特性,如布尔查询、...

    autoSearch 基于Lucene.Net的站内搜索

    Lucene.Net使用TF-IDF(词频-逆文档频率)算法来计算文档的相关性。 在使用Lucene.Net进行站内搜索时,你需要遵循以下步骤: 1. **设置项目和引用**:首先,在你的C#项目中添加对Lucene.Net库的引用。你可以通过...

    Lucene.Net_2_9_1.zip

    Lucene.Net_2_9_1.zip中的实例代码可以帮助我们更好地理解如何使用这些组件。通过创建索引、查询和展示搜索结果,我们可以学习到如何构建一个完整的搜索系统。例如,你可以看到如何创建一个新的索引目录,添加文档,...

    Lucene.NET 实例

    在“Lucene.NET 搜索实例 源码 VS2008”这个项目中,我们主要探讨如何使用 Lucene.NET 在 Visual Studio 2008 开发环境中构建一个完整的搜索应用。下面将详细介绍几个关键的知识点: 1. **索引创建**:Lucene.NET ...

    lucene.net 2.9.1 源码

    《深入剖析Lucene.NET 2.9.1:源码解析与应用开发》 Lucene.NET 2.9.1是开源搜索引擎库Lucene的.NET版本,它为.NET开发者提供了强大的全文检索和索引功能。这个版本的源码提供了一个宝贵的资源,帮助我们理解其内部...

    Lucene.Net.dll

    开发者可以通过NuGet包管理器轻松地将其引入项目,同时可以找到大量的教程、示例代码和第三方扩展,帮助开发者更好地理解和使用Lucene.Net。 总之,Lucene.Net.dll 2.9.2版本是.NET开发者构建全文搜索引擎的理想...

    lucene.net1.4.3全文检索源文件

    4. 搜索(Searching):Lucene.NET使用评分系统(Scoring)来衡量文档与查询的相关性,返回最相关的文档结果。 三、主要组件 1. 文档(Document):代表要被搜索的信息单元,可以包含多个字段(Field),如标题、...

    Lucene.Net +盘古分词 搜索引擎

    在项目中,你需要创建索引器类,用于读取数据并使用盘古分词进行分词,然后将分词结果作为文档添加到Lucene.Net的索引中。同时,还需要实现查询解析器,将用户输入的查询字符串转化为可以匹配索引的查询对象。 创建...

    Lucene.Net2.9.1

    3. **搜索执行**:Lucene.Net 使用倒排索引进行搜索,提供布尔、短语、模糊、范围等多种搜索方式。 4. **结果排序**:支持基于评分、相关度、自定义排序函数等多种排序方式,以满足不同场景的需求。 5. **高亮显示**...

    lucene.net

    6. **存储(Store)**:Lucene.NET使用RAMDirectory或FSDirectory来存储索引,前者在内存中,适合小规模数据,后者在硬盘上,适合大规模数据。 实际应用中,Lucene.NET常用于网站搜索、日志分析、知识图谱等场景。...

    Lucene.Net 实现全文检索

    在本案例中,我们将在 .Net MVC4 框架上使用 Lucene.Net 来构建一个全文检索系统。 首先,我们需要理解全文检索的基本概念。全文检索是指在文档集合中,根据用户输入的查询词,查找包含这些词的文档。与传统的...

    Lucene.Net2.3源码,最新版

    这些是 HTML 文档,可能包含了 Lucene.Net 的概述和组件介绍,帮助用户了解库的功能和使用方法。NDoc(.NET 文档生成器)可能被用来自动生成这些文档,从注释和源代码中提取信息。 9. **Lucene.Net-2.3.1.ndoc** ...

Global site tag (gtag.js) - Google Analytics