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






4.81/5 (58投票s)
Lucene.Net 简介,一款开源的全文搜索引擎。
- 下载源代码 - 1 MB [codeproject.com]
- 下载完整源代码 [dotlucene.net]
- 在线演示 [dotlucene.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;
// ...
}
资源
- Lucene.Net 主页 [apache.org]
- DotLucene - Lucene.Net 教程 [dotlucene.net]
- Lucene.Net API 文档 [dotlucene.net]
- Lucene API 搜索 [dotlucene.net]