65.9K
CodeProject 正在变化。 阅读更多。
Home

DotLucene:用 37 行代码实现您的内部网或网站的全文搜索

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (58投票s)

2005年2月1日

Apache

3分钟阅读

viewsIcon

399576

downloadIcon

6127

Lucene.Net 简介,一款开源的全文搜索引擎。

更新 

2012 年 11 月 6 日:该项目现已支持 Lucene.Net 3.0 和 .NET Framework 4.0。包含 Visual Studio 2010 解决方案。  

Lucene.Net:优秀的全文搜索引擎

能否用 37 行代码实现全文搜索?好吧,我将稍微偷个懒,使用 Lucene.Net 来完成繁重的工作。Lucene.Net 是 Jakarta Lucene 搜索引擎的 .NET 移植版本。以下是它的一些主要特性:

  • 可用于 ASP.NET、Win Forms 或控制台应用程序。
  • 性能极佳。
  • 搜索结果排名。
  • 搜索结果中的查询词高亮显示。
  • 搜索结构化和非结构化数据。
  • 元数据搜索(按日期查询,搜索自定义字段...)。
  • 索引大小约为索引文本的 30%。
  • 还可以存储完整的索引文档。
  • 纯托管 .NET。
  • 非常友好的许可(Apache 软件许可 2.0)。
  • 本地化(支持巴西、捷克、中文、荷兰、英语、法语、日语、韩语和俄语)。
  • 可扩展(包含源代码)。

警告 

不要太在意行数。我将向您展示核心功能仅需 37 行代码,但要使其成为一个真正的应用程序,您还需要花费一些额外的时间……

演示项目 

我们将创建一个简单的演示项目,展示如何

  • 索引指定目录(包括子目录)中的 HTML 文件。
  • 使用 ASP.NET 应用程序搜索索引。
  • 高亮显示搜索结果中的查询词。

但 Lucene.Net 还有更多潜力。在实际应用中,您可能需要

  • 当新文档出现在目录中时将其添加到索引。无需重建整个索引。
  • 包含其他文件类型。Lucene.Net 可以索引您能转换为纯文本的任何文件类型。

为什么不使用 Microsoft Indexing Server?

如果您对 Indexing Server 满意,那没问题。但是,Lucene.Net 具有许多优势:

  • Lucene.Net 是一个单一的、100% 托管代码的程序集。它没有任何外部依赖项。 
  • 您可以使用它来索引任何类型的数据(电子邮件、XML、HTML 文件等),来自任何源(数据库、Web 等)。这是因为您需要向索引器提供纯文本。加载和解析源取决于您。
  • 允许您指定应包含在索引中的属性(“字段”)。您可以使用这些字段进行搜索(例如,按作者、日期、关键字)。
  • 它是开源的。
  • 它易于扩展。

第 1 行:创建索引

以下代码行将在磁盘上创建一个新索引。directory 是索引将存储的目录路径。 

IndexWriter writer = new IndexWriter(FSDirectory.Open(directory), new StandardAnalyzer(Version.LUCENE_30), true, IndexWriter.MaxFieldLength.LIMITED); 

在此示例中,我们从头开始创建索引。这不是必需的,您也可以打开现有索引并向其中添加文档。您还可以通过删除现有文档并添加新版本来更新它们。

第 2-12 行:添加文档 

对于每个 HTML 文档,我们将在索引中添加两个字段: 

  • text 字段,包含 HTML 文件的文本(去除标签)。文本本身不会存储在索引中。
  • path 字段,包含文件路径。它将被索引并完整地存储在索引中。
public void AddHtmlDocument(string path)
{
    Document doc = new Document();

    string rawText;
    using (StreamReader sr = 
       new StreamReader(path, System.Text.Encoding.Default))
    {
        rawText = parseHtml(sr.ReadToEnd());
    }
    
    doc.Add(new Field("text", rawText, Field.Store.YES, Field.Index.ANALYZED));
    doc.Add(new Field("path", path, Field.Store.YES, Field.Index.NOT_ANALYZED));
    writer.AddDocument(doc);
}  

第 13-14 行:优化和保存索引

添加完文档后,您需要关闭索引器。优化将提高搜索性能。

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

第 15 行:打开索引以进行搜索

在进行任何搜索之前,您需要打开索引。directory 是索引存储的目录路径。 

IndexSearcher searcher = new IndexSearcher(FSDirectory.Open(indexDirectory));  

第 16-27 行:搜索 

现在我们可以解析查询(text 是默认搜索字段)。

var parser = new QueryParser(Version.LUCENE_30, "text", analyzer);
Query query = parser.Parse(this.Query); 
TopDocs hits = searcher.Search(query, 200);  

hits 变量是一个结果文档的集合。我们将遍历它并将结果存储在 DataTable 中。

DataTable dt = new DataTable();
dt.Columns.Add("path", typeof(string));
dt.Columns.Add("sample", typeof(string));

for (int i = 0; i < hits.TotalHits; i++) 
{
    // get the document from index
    Document doc = searcher.Doc(hits.ScoreDocs[i].Doc);

    // get the document filename
    // we can't get the text from the index 
    //because we didn't store it there
    DataRow row = dt.NewRow();
    row["path"] = doc.Get("path");

    dt.Rows.Add(row);
}  

第 28-37 行:查询高亮显示 

让我们创建一个 highlighter。我们将使用粗体字进行高亮显示(<B>短语</B>)。 

IFormatter formatter = new SimpleHTMLFormatter("<span style=\"font-weight:bold;\">", "</span>");
SimpleFragmenter fragmenter = new SimpleFragmenter(80);
QueryScorer scorer = new QueryScorer(query);
Highlighter highlighter = new Highlighter(formatter, scorer);
highlighter.TextFragmenter = fragmenter; 

在获取结果时,我们将加载原始文本的相关部分。

for (int i = 0; i < hits.TotalHits; i++) 
{
    // ...
    TokenStream stream = analyzer.TokenStream("", new StringReader(doc.Get("text")));
    row["sample"] = highlighter.GetBestFragments(stream, doc.Get("text"), 2, "...");    string plainText;
    // ...
}  

资源

© . All rights reserved.