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

Lucene.Net 为 MVC 或 WebForms 网站提供超快速搜索 => 轻松实现!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (137投票s)

2012 年 2 月 1 日

CPOL

17分钟阅读

viewsIcon

725194

downloadIcon

12182

面向任何希望快速在他们的网站或应用程序中实现 Lucene.Net 搜索的开发人员的分步教程!


本文介绍 Lucene.Net 3.0.3(官方网站 [^]) 

引言   

你听说过 Lucene.Net 吗?如果没有,请允许我简要介绍一下。

Lucene.Net 是流行的 Apache Lucene 的逐行移植,它是一个高性能、功能齐全的文本搜索引擎库,完全用 Java 编写。它是一种适用于几乎所有需要全文搜索的应用程序的技术。特别是,在一个你想要实现接近 Google 搜索结果的应用程序中,而且不仅仅是搜索结果,而是非常快速的搜索结果,甚至可能是令人难以置信的快速搜索结果,但仅限于你的应用程序,并按照你自己的方式!

因此,虽然技术上可能,尽管有些挑战,你可以将原始的 Apache Lucene 集成到你的 .NET 应用程序中,它将为你提供惊人的快速搜索。但这将花费相当长的时间,并且可能会迫使你在某些地方偷工减料,从而使你的网站过于复杂且容易出错。因此,除非你绝对需要地球上最快的搜索(并同时击败 Google),否则你不应该走这条路,因为对于大多数 .NET 应用程序而言,Lucene.Net 已经非常快了。

Lucene.Net 的主要目的是易于集成到任何 .NET 应用程序中,并提供原始 Java 库的大部分速度和灵活性。它做得相当不错!你将在本文中学到这一点。甚至原始的 Apache Lucene 文档在 99% 的情况下也适用于 Lucene.Net

你可能会问:“为什么要费心使用 Lucene.Net?我的 SQL Server anyway 返回搜索结果也很快……”是的,我之前也这么想,直到我尝试了 Lucene.Net

首先,我发现 Lucene 仍然比 SQL 查询快。而且在搜索某些文本或短语时,它绝对快,无论你的搜索中有多少单词。例如,当你搜索一些文本或描述中的一个包含五个不同单词的句子,并且想要结果按照相关性排序,就像主要的网络搜索引擎一样。你会在 SQL 中怎么做?或者 .NET?……你的代码可能会变得非常复杂,搜索查询会又长又复杂……这可能会变成类似乌龟般缓慢的搜索!

好消息是 Lucene.Net 为你解决了这些问题!不再需要编写复杂的搜索逻辑了!你只需要正确地将其集成到你的应用程序中!这就是本文的主题!

所以,如果你有兴趣为你的 .NET 网站或应用程序尝试 Lucene.Net,请继续阅读,准备好拥抱一些对 Lucene 的热爱吧!

一个小小的免责声明,算是吧))

我不是 Lucene 专家,本文不仅仅是关于 Lucene,它更多地是关于如何在你的 .NET 应用程序/网站中让它工作。因此,不会涵盖任何高级 Lucene 主题(至少一开始不会),只包含让它工作所需的内容。

文章目录

场景

- 本文结束时我们将实现的目标

安装

I. 通过 NuGet 安装

- 如何通过 NuGet 包管理器安装 Lucene.Net

II. 手动安装

- 如何通过手动下载安装 Lucene.Net

实现搜索,分步进行

- 为实现基本的 Lucene.Net 搜索你需要采取的步骤

步骤 1 - 创建示例数据源

步骤 2 - 创建基本的空 Lucene 搜索类

步骤 3 - 添加 Lucene 搜索索引目录处理器

步骤 4 - 添加向 Lucene 搜索索引添加数据的方��

步骤 5 - 添加从 Lucene 搜索索引删除和优化数据的方��

步骤 6 - 添加将 Lucene 搜索索引数据映射到 SampleData 的方��

步骤 7 - 添加主搜索方法

步骤 8 - 添加调用主搜索方法的公共方��

Using the Code

- 示例项目和 Github 下载链接 

参考文献 

- 用作源、灵感和 Lucene.Net 理论的文章

关注点

- 我在撰写本文时学到的东西

历史

- 带日期的文章列表和附带的示例网站更新

场景

本文介绍了一个使用 Lucene.Net 的简单搜索场景

鉴于

  • 你有一个数据源(很可能是数据库),其中包含一些独特��的文本数据

你需要能够

  • 数据源中的所有数据创建Lucene 搜索索引并删除整个索引
  • 将单个记录添加到Lucene 搜索索引并从中删除单个记录
  • 搜索Lucene 搜索索引中的所有字段,并按相关性获取匹配记录
  • 按特定字段搜索Lucene 搜索索引并按相关性获取匹配记录

我们将一步一步地在此场景中创建搜索,以便你了解它是如何工作的。我将在相应的步骤中详细解释 Lucene 搜索索引是什么。

安装

当然,首先我们需要安装 Lucene.Net 库本身,不是吗?

I. 通过 NuGet 安装

最简单且首选的方式是安装 Lucene.Net NuGet 包。

方法 1 - 使用 NuGet 包管理器控制台

通过单击来打开 Visual Studio 中的包管理器控制台

视图 > 其他窗口 > 包管理器控制台

一旦控制台出现在底部,让我们首先搜索“lucene”,方法是键入

get-package -remote -filter lucene” 在提示符下: 

截图 1。

 

从搜索结果中我们可以看到,有许多不同的包可供我们选择。��大部分情况下,这些包仅扩展了默认的 Lucene.Net 功能。本文将不涵盖它们,但你以后可以自己尝试。我们唯一需要的包是基本的 Lucene.Net

因此,要安装它,让我们键入“install-package Lucene.Net

截图 2。 

 

然后,哇!NuGet 又一次做得很好 - Lucene.Net 已安装并引用!

方法 2 - 使用 NuGet UI 工具

如果你不喜欢在任何类型的控制台中键入内容(“……控制台?控制台?!先生/女士,这真是胡说八道!……”)或者出于任何原因它不起作用,你可以使用精巧的 NuGet UI。右键单击你的项目,然后单击“管理 NuGet 程序包…

截图 3。

 

一个漂亮干净的窗口将弹出。在那里,首先选择:在线 > 所有,然后��搜索框中键入“Lucene.Net”,然后从列表中选择 Lucene.Net 并点击“安装”(我已经安装了它,所以它显示绿色图标而不是“安装”按钮)。

截图 4。 

 

这样,你就准备好了!

II. 手动安装

或者,你也可以在这里下载 Lucene.Net - 从官方网站[^] 下载 Lucene 二进制文件。

之后,将 lucene.net.dll 从存档手动复制到你的 bin 文件夹,并手动引用它。

那么,一切安装完毕后,让我们继续进行搜索实现!

实现搜索,分步进行

步骤 1 - 创建示例数据源

为了使用 Lucene.Net,我们首先需要从一组数据(很可能是数据库)创建Lucene 搜索索引Lucene 搜索索引只是 Lucene.Net 创建的一组文本文件,我们稍后会创建它。所以,对于我们的教程,让我们创建一个空的 SampleData.cs 文件,并在其中添加一些通用数据对象。

namespace MvcLuceneSampleApp.Search {
    public class SampleData {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }
} 

这个类可以代表你想要的任何数据,当然你也可以创建自己的类或使用现有的类。此外,在测试 Lucene 时,你可能希望创建一个基于上面 SampleData 类的简单静态数据源存储库,你可以将该代码放入你刚刚创建的同一个 SampleData.cs 文件中。

using System.Collections.Generic;
using System.Linq;

namespace MvcLuceneSampleApp.Search {
public static class SampleDataRepository {
public static SampleData Get(int id) {
    return GetAll().SingleOrDefault(x => x.Id.Equals(id));
}
public static List<SampleData> GetAll() {
    return new List<SampleData> {
        new SampleData {Id = 1, Name = "Belgrad", Description = "City in Serbia"},
        new SampleData {Id = 2, Name = "Moscow", Description = "City in Russia"},
        new SampleData {Id = 3, Name = "Chicago", Description = "City in USA"},
        new SampleData {Id = 4, Name = "Mumbai", Description = "City in India"},
        new SampleData {Id = 5, Name = "Hong-Kong", Description = "City in Hong-Kong"},
    };
}}}   

步骤摘要

我们已经创建了带有通用数据类 SampleData 和用于检索我们静态数据的示例存储库 SampleDataRepository 的示例数据源。

步骤 2 - 创建基本的空 Lucene 搜索类

现在让我们创建一个空的 LuceneSearch.cs 文件,并将以下内容复制到其中。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
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 Version = Lucene.Net.Util.Version;

namespace MvcLuceneSampleApp.Search {
    public static class LuceneSearch {  
        //todo: we will add required Lucene methods here, step-by-step...
    }
}  

我们将在此类中添加执行所有搜索相关任务所需的所有方法。此时,你可以通过构建你的网站来确保所有引用都正确,如果构建失败,请修复你的引用。

步骤摘要

我们已经创建了一个空的 LuceneSearch 类。

步骤 3 - 添加 Lucene 搜索索引目录处理器

所以,让我们看看我们现在有什么 - SampleData 类,它代表一些数据,以及 LuceneSearch 类,它应该执行搜索。但它是空的。所以,它需要一些代码来完成工作,对吧?

先做个小小的准备。Lucene.Net 需要构建其搜索索引,如前所述,这基本上是 Lucene 在某个本地目录中生成的一组文件。所以,我们需要向 LuceneSearch 类添加一个特殊属性,该属性代表一个本地目录的处理器,该目录将存储搜索索引

private static string _luceneDir =
Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "lucene_index");
private static FSDirectory _directoryTemp;
private static FSDirectory _directory {
get {
    if (_directoryTemp == null) _directoryTemp = FSDirectory.Open(new DirectoryInfo(_luceneDir));
    if (IndexWriter.IsLocked(_directoryTemp)) IndexWriter.Unlock(_directoryTemp);
    var lockFilePath = Path.Combine(_luceneDir, "write.lock");
    if (File.Exists(lockFilePath)) File.Delete(lockFilePath);
    return _directoryTemp;
}}  

这里 _luceneDir 是文件夹的完整物理路径,而 "lucene_index" 是该文件夹的名称,它位于应用程序根目录下。因此,你自然也需要手动创建此目录,或编写一些代码自动创建它。

然后,_directoryLucene.NetFSDirectory 的一个实例,并将被所有搜索方法用来访问搜索索引

步骤摘要

我们已经添加了Lucene 搜索索引目录处理器,使我们的 LuceneSearch 类准备好添加搜索方法。

步骤 4 - 添加向 Lucene 搜索索引添加数据的方��

Lucene 将根据实际数据创建搜索索引,在我们的情况下,它将是具有多个记录的 List<SampleData>,或单个 SampleData 记录。

我们需要的第一种方法是一个 private 方法,它根据我们的数据创建一个单个搜索索引条目,并且将被我们稍后添加的公共方法重用。

private static void _addToLuceneIndex(SampleData sampleData, IndexWriter writer) {
    // remove older index entry
    var searchQuery = new TermQuery(new Term("Id", sampleData.Id.ToString()));
    writer.DeleteDocuments(searchQuery);

    // add new index entry
    var doc = new Document();

    // add lucene fields mapped to db fields
    doc.Add(new Field("Id", sampleData.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
    doc.Add(new Field("Name", sampleData.Name, Field.Store.YES, Field.Index.ANALYZED));
    doc.Add(new Field("Description", sampleData.Description, Field.Store.YES, Field.Index.ANALYZED));

    // add entry to index
    writer.AddDocument(doc);
} 

基本上,它接受一个 SampleData 类的记录,将其映射到 LuceneDocument,然后使用 IndexWriter 将其添加到搜索索引。请注意 NameDescription 字段如何使用 Field.Index.ANALYZED 参数,而 Id 使用 Field.Index.NOT_ANALYZED 参数。基本上,你只想在文本或单个字符串属性上使用 ANALYZED,而在像整数 ID 这样的单个值上使用 NOT_ANALYZED

现在让我们添加一个 public 方法,它将使用 _addToLuceneIndex() 来将记录列表添加到搜索索引。

public static void AddUpdateLuceneIndex(IEnumerable<SampleData> sampleDatas) {
    // init lucene
    var analyzer = new StandardAnalyzer(Version.LUCENE_30);
    using (var writer = new IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED)) {
    // add data to lucene search index (replaces older entry if any)
    foreach (var sampleData in sampleDatas) _addToLuceneIndex(sampleData, writer);

    // close handles
    analyzer.Close();    
    writer.Dispose();
}} 

另外,让我们添加另一个 public 方法来将单个记录添加到搜索索引。

public static void AddUpdateLuceneIndex(SampleData sampleData) {
    AddUpdateLuceneIndex(new List<SampleData> {sampleData});
} 

这两个方法的用法模式很简单 - 一次添加所有数据库记录。

// add all existing records to Lucene search index
LuceneSearch.AddUpdateLuceneIndex(SampleDataRepository.GetAll()); 

然后,每当向数据库添加新记录时,调用相同的方法,只给它一个记录。

var new_record = new SampleData {Id = X, Name = "SomeName", Description = "SomeDescription"};
// todo: add record to database...

// add record to Lucene search index
LuceneSearch.AddUpdateLuceneIndex(new_record);  

步骤摘要

现在我们可以创建整个Lucene 搜索索引或向其中添加单个记录。

步骤 5 - 添加从 Lucene 搜索索引删除和优化数据的方��

每当删除数据库记录时,它们也必须从Lucene 搜索索引中删除,否则你的搜索将返回可能不存在于数据库中的记录。让我们首先添加一个简单的方法来按记录的 Id 字段从 Lucene 搜索索引中删除单个记录。

public static void ClearLuceneIndexRecord(int record_id) {
    // init lucene
    var analyzer = new StandardAnalyzer(Version.LUCENE_30);
    using (var writer = new IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED)) {
        // remove older index entry
        var searchQuery = new TermQuery(new Term("Id", record_id.ToString()));
        writer.DeleteDocuments(searchQuery);

        // close handles
        analyzer.Close();        
        writer.Dispose();
    }
}  

上面的代码基本上通过 Id 字段(当然你可以使用任何字段)搜索记录,从索引中获取搜索结果,并将它们全部从索引中删除,在我们的例子中,它通常会删除单个记录,只要你始终提供完整且唯一的 Id 值。

注意:主 Lucene 搜索方法将在稍后添加,当然也会更详细地解释。

其次,每当数据库架构更改时,或者你只想快速清除整个索引时,你都需要一个方法来清除所有索引,所以我们也添加这个。

public static bool ClearLuceneIndex() {
    try {
        var analyzer = new StandardAnalyzer(Version.LUCENE_30);
        using (var writer = new IndexWriter(_directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED)) {
            // remove older index entries
            writer.DeleteAll();

            // close handles
            analyzer.Close();            
            writer.Dispose();
        }
    }
    catch (Exception) {
        return false;
    }
return true;
}

此方法通过 Lucene IndexWriter 中的内置方法简单地删除整个Lucene 搜索索引

现在可能是时候提到 Lucene 会在搜索索引文件上放置一个“”,以便在更新或搜索它们时,它们不会被更改。此外,重要的是,每个文件都必须“解锁”,因为如果某些文件被手动或通过某些代码删除,然后你尝试搜索/更新,这将导致你看到很多错误,而我们不希望那样,对吧?

因此,为了避免尴尬并让我们的最终用户免受对我们自己的愤怒,我们始终需要 .Close().Dispose() 任何 Lucene 处理器,如 IndexWriterStandardAnalyzer

此外,定期运行 Lucene 搜索索引优化将有利于加快搜索速度,特别是如果你的索引越来越大。所以,让我们添加一个小方法来做这个。

public static void Optimize() {
    var analyzer = new StandardAnalyzer(Version.LUCENE_30);
    using (var writer = new IndexWriter(_directory, analyzer, IndexWriter.MaxFieldLength.UNLIMITED)) {
        analyzer.Close();
        writer.Optimize();        
        writer.Dispose();
    }
} 

步骤摘要

我们添加了三个方法 - ClearLuceneIndexRecord() 用于从Lucene 搜索索引中删除单个记录,ClearLuceneIndex() 用于删除索引中的所有记录,以及 Optimize() 方法用于优化大型索引以加快搜索速度。

步骤 6 - 添加将 Lucene 搜索索引数据映射到 SampleData 的方��

坚持住,伙计们,这是我们添加主要搜索方法之前的最后一步!

现在,在我们可以搜索之前,你还记得我们在步骤 4 中的 _addToLuceneIndex() 方法是如何将我们的数据库数据映射到Lucene 搜索索引的吗?嗯,为了将我们的搜索结果以 List<SampleData> 或类似的形式返回,我们需要一个函数来将索引映射到我们的 SampleData 类,就是这个。

private static SampleData _mapLuceneDocumentToData(Document doc) {
    return new SampleData {
        Id = Convert.ToInt32(doc.Get("Id")),
        Name = doc.Get("Name"),
        Description = doc.Get("Description")
    };
}  

因此,上面的方法将从索引中获取Lucene Document h(其中每个字段都表示为字符串),并将其映射到 SampleData。很简单,对吧?

此外,我们还需要另外两个方法来映射由不同 Lucene 搜索方法返回的 Lucene Document 列表和 Lucene ScoreDoc 列表,这将在步骤 7 和 8 中详细介绍。这两个方法都重用了我们上面定义的 _mapLuceneDocumentToData() 方法。

private static IEnumerable<SampleData> _mapLuceneToDataList(IEnumerable<Document> hits) {
    return hits.Select(_mapLuceneDocumentToData).ToList();
}
private static IEnumerable<SampleData> _mapLuceneToDataList(IEnumerable<ScoreDoc> hits,
    IndexSearcher searcher) {
    return hits.Select(hit => _mapLuceneDocumentToData(searcher.Doc(hit.Doc))).ToList();
}

步骤摘要

我们添加了将 Lucene 返回的结果映射到我们的数据类的方法,以便在我们的网站上重用。方法 _mapLuceneDocumentToData() Lucene Document 和来自索引的搜索结果映射到我们的类 SampleData,而 _mapLuceneToDataList() 方法则依次映射 Lucene DocumentScoreDoc 的列表。

步骤 7 - 添加主搜索方法

最后是主搜索方法。它将根据我们提供的字段名称(*Id、Name 或 Description*)搜索Lucene 搜索索引,或者,它将搜索所有三个字段,这是通用搜索的基础,有点像*你最喜欢的*互联网搜索引擎。你可能会注意到它仍然是一个私有方法。原因是此方法对于任何 Lucene 查询都是通用的。

Lucene 查询不仅仅是你正在搜索的文本。基本示例是当查询看起来像“Mumbai”时,Lucene 将精确匹配此单词,如果查询像“Mum*”则返回所有以“Mum”开头的单词的字段作为搜索结果。肯定有更多方法可以编写高级Lucene 查询,但这将在本文中不予介绍。

在我们的例子中,查询将由一个公共方法提供,该方法将格式化你的搜索请求以用于特定的搜索场景,它将在步骤 8 中添加。我们的场景是私有的搜索方法在下面不会有太大变化,只有公共方法会根据我们的搜索需求进行调整。

作为小小的准备,先添加这个方法。

private static Query parseQuery(string searchQuery, QueryParser parser) {
    Query query;
    try {
        query = parser.Parse(searchQuery.Trim());
    }
    catch (ParseException) {
        query = parser.Parse(QueryParser.Escape(searchQuery.Trim()));
    }
    return query;
} 

这个方法基本上会将你的搜索查询 string 解析成 Lucene Query 对象,如果解析失败,它会修复导致失败的任何符号并返回修复后的 Query 对象。

注意:如果你希望 Lucene 查找相似的单词,你需要使用 FuzzyQuery 而不是常规 Query,请参见此处(感谢 M.R.P!): https://codeproject.org.cn/Messages/4643090/Re-Find-similar-Words.aspx 

现在让我们添加我们的主搜索方法。

private static IEnumerable<SampleData> _search
    (string searchQuery, string searchField = "") {
    // validation
    if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", ""))) return new List<SampleData>();

    // set up lucene searcher
    using (var searcher = new IndexSearcher(_directory, false)) {
        var hits_limit = 1000;
        var analyzer = new StandardAnalyzer(Version.LUCENE_30);

        // search by single field
        if (!string.IsNullOrEmpty(searchField)) {
            var parser = new QueryParser(Version.LUCENE_30, searchField, analyzer);
            var query = parseQuery(searchQuery, parser);
            var hits = searcher.Search(query, hits_limit).ScoreDocs;
            var results = _mapLuceneToDataList(hits, searcher);
            analyzer.Close();            
            searcher.Dispose();
            return results;
        }
        // search by multiple fields (ordered by RELEVANCE)
        else {
            var parser = new MultiFieldQueryParser
                (Version.LUCENE_30, new[] { "Id", "Name", "Description" }, analyzer);
            var query = parseQuery(searchQuery, parser);
            var hits = searcher.Search
            (query, null, hits_limit, Sort.RELEVANCE).ScoreDocs;
            var results = _mapLuceneToDataList(hits, searcher);
            analyzer.Close();            
            searcher.Dispose();
            return results;
        }
    }
} 

当然,我们的私有 _search() 方法有很多需要调整和优化的地方,这取决于你根据具体需求进行调整。

你注意到 var hits_limit = 1000; 了吗?正如我在步骤 5 中提到的,当 Lucene 获得超过 1000 个搜索结果时,它的速度会越来越慢,所以你想将其限制在你��情况下相关的数量。

如果你向索引添加新字段,别忘了��多字段搜索中的这一行添加要搜索的字段名,如下所示。

var parser = new MultiFieldQueryParser
    (Version.LUCENE_30, new[] { "Id", "Name", "Description", "NEW_FIELD" }, analyzer); 

请记住,_search() 方法返回的结果将按 Sort.RELEVANCE 排序,这意味着更精确的结果会先返回。另一个选项是 Sort.INDEXORDER,它按搜索索引中添加的顺序返回结果。但对于大多数情况,Sort.RELEVANCE 已经足够了。

步骤摘要

我们添加了主要的私有 _search() 方法,该方法将根据提供的搜索查询,在 Lucene 搜索索引中按单个字段或多个字段进行搜索。

步骤 8(也是最后一步)- 添加调用主搜索方法的公共方��

我们的小搜索引擎现在几乎完成了。现在是时候添加最后一个方法来与我们的网站或应用程序进行交互了。

第一个方法只是格式化 Lucene 搜索查询并调用主私有搜索方法 _search()

public static IEnumerable<SampleData> Search(string input, string fieldName = "") {
    if (string.IsNullOrEmpty(input)) return new List<SampleData>();
            
    var terms = input.Trim().Replace("-", " ").Split(' ')
        .Where(x => !string.IsNullOrEmpty(x)).Select(x => x.Trim() + "*");
    input = string.Join(" ", terms);

    return _search(input, fieldName);
}  

它会替换搜索请求中的所有连字符“-”,并在每个单词后添加“*”(星号),以便你可以按部分单词进行搜索。

所以,基本上,上面的 Search() 方法几乎是你定制查询以获得完美搜索结果的主要游乐场。

此外,为了尝试原生Lucene 搜索查询,我们可以添加默认搜索方法 SearchDefault(),它不会以任何方式格式化你的查询。

public static IEnumerable<SampleData> SearchDefault(string input, string fieldName = "") {
    return string.IsNullOrEmpty(input) ? new List<SampleData>() : _search(input, fieldName);
} 

在网上搜索关于编写高级��精确Lucene 搜索查询的内容,使用 SearchDefault() 函数尝试它们,然后你可以修改 Search() 方法以更好地满足你的需求。

正如我在步骤 5 中提到的,现在我们也添加了一个返回整个Lucene 搜索索引的方法。

public static IEnumerable<SampleData> GetAllIndexRecords() {
    // validate search index
    if (!System.IO.Directory.EnumerateFiles(_luceneDir).Any()) return new List<SampleData>();

    // set up lucene searcher
    var searcher = new IndexSearcher(_directory, false);
    var reader = IndexReader.Open(_directory, false);
    var docs = new List<Document>();
    var term = reader.TermDocs();
    while (term.Next()) docs.Add(searcher.Doc(term.Doc));
    reader.Dispose();    
    searcher.Dispose();
    return _mapLuceneToDataList(docs);
}

请记住,要明智地使用它,因为索引越大,加载所有内容所需的时间越长。

步骤摘要

我们添加了两个方法,目前完成了我们基本的 LuceneSearch 类 - 第一个方法是 Search(),它格式化 Lucene 搜索查询,并按所有字段或单个字段进行搜索。第二个方法是 GetAllIndexRecords(),它只是返回搜索索引中的所有记录。

Using the Code

恭喜!如果你阅读到这里,意味着你可能已经准备好并将你��新的 LuceneSearch 类投入测试。或者你可能已经一路测试过并理解了所有内容,现在正在研究 Lucene 在线文档)。

为了演示所有内容,连同简单的UI,我已经创建了一个适用于 Visual Studio 2012 的示例项目(包括 MVCWebForms 示例),该项目使用了本文中的所有代码,并为 Lucene.Net 提供了一个简单的接口。

或者,如果你安装了 Git(如果没有,请阅读如何在 Windows 上设置 Git),请在bash 控制台中运行以下命令来创建项目的本地克隆(副本)(创建一个文件夹,右键单击它,选择“在此处 Git Bash”,复制下面的命令,然后通过 Shift+Insert 粘贴到控制台中)。

git clone git@github.com:mikhail-tsennykh/Lucene.Net-search-MVC-sample-site.git  

我想这就是本文的结尾了。我真诚地希望 Lucene.Net 能加快你的搜索速度,并使你的生活更轻松!

希望本文至少有所帮助!告诉我你的想法!

参考文献 

我使用了这些文章作为 Lucene.Net 的灵感和知识来源。它们已经过时了,但你可以找到相当多的关于 Lucene 的理论和深入知识(经过对最新 Lucene.Net 的调整): 

更不用说,简单的网络搜索 - 永远是你最好的朋友!

关注点

在撰写本文时,我不知何故与 Git 建立了一种温暖而真诚的关系))

因此,我谦虚地建议 - 通过阅读官方 Git 网站上的内容或Git - 简单指南来发现你内心的 Git

历史

  • 2013/1/2 - 更新了文章和示例项目以涵盖最新的 Lucene.Net 3.0.3,将示例项目转换为 Visual Studio 2012.NET 4.5
  • 2012/2/23 - 添加了更好的方法来解析 Lucene 搜索查询(感谢 Gavin Harriss 提供的提示!),在示例搜索站点中添加了 SearchDefault() 方法以使用原始 Lucene 查询进行搜索,因此示例搜索站点的版本为v.1.3
  • 2012/2/9 - 从搜索方法中删除了 writer.Optimize(),因为它可能会降低搜索性能,并将其放入单独的 Optimize() 方法中,以便手动或按计划调用(感谢 dave.dolan 提供的提示!)。还��几个方法添加了 analyzer.Close() 行,因为未关闭的 analyzer 在某些情况下会导致错误。示例搜索站点已更新至v.1.2
  • 2012/2/7 - ClearLuceneIndex() 方法已更新为内置的清除整个Lucene 搜索索引的方法(感谢 ENOTTY 提供的这个提示!),示例搜索站点已更新至v.1.1
  • 2012/2/2 - 清理并更新了附带的示例搜索站点,以及一些小的文章更新。
  • 2012/2/1 - 发布了关于使用 Lucene.Net 2.9.4 的初始文章,以及示例搜索站点v.1.0
© . All rights reserved.