如何在 .NET 应用程序中使用 Elasticsearch 实现全文搜索





5.00/5 (7投票s)
了解如何使用 NEST 在 C# 中读取和写入具有自定义全文查询的文档。
为什么选择 Elastic Search?
Elasticsearch 是一个分布式、开源的搜索引擎,可以管理各种数据。但是,为什么 Elasticsearch 是全文搜索的最佳解决方案呢?
2009 年,当我在论文中不得不为数据推荐系统实现搜索算法时,我开始尝试全文搜索。这次经历非常具有教育意义,但从头开始是一场恶战。我第一次有机会使用一个库时,我尝试了 Apache Lucene 来实现全文搜索。随着应用程序架构变得复杂(例如,需要共享索引数据的多个服务器),Solr 提供了一个可扩展的解决方案。它是一个基于 API 的开源搜索引擎(基于 Lucene)。在使用这些库之后,我使用了 Elasticsearch,它现在是市场领导者。它有一个本地免费版本,并且可以在云端使用。它可以从简单的安装扩展到巨大的环境。所以问题是:为什么不呢?
示例应用程序
我成功地在生产环境和我的 开源无头 CMS RawCMS 上使用了 Elasticsearch。为了展示 Elasticsearch 的工作原理,我创建了一个示例应用程序,其中实现了两个主要功能:
- 创建索引并将数据添加到其中
- 使用全文查询读取数据
示例代码可在 GitHub 上找到。要运行和测试它,只需下载、编译并执行
dotnet ElasticSearchTest.dll create -f divina_commedia.txt -h https://:9300
> Index created in 30338ms with 14006 element.
dotnet ElasticSearchTest.dll search -i divinacommediatxt
-h https://:9300 -q "dante AND virgi*"
> Searching for $dante AND virgi*
> "Dante, perché Virgilio se ne vada,
> "Dante, perché Virgilio se ne vada,
控制台应用程序使用库 ConsoleLineParser
以一种人性化的方式解析输入。所以我只是添加了两个类用于动词属性,以及控制台动词和要运行的代码之间的映射。
private static void Main(string[] args)
{
object x = CommandLine.Parser.Default.ParseArguments<CreateOptions, SearchOptions>(args)
.MapResult(
(CreateOptions opts) => DoCreate(opts),
(SearchOptions opts) => DoSearch(opts),
errs => 1);
}
基于用户输入的动词(搜索或创建),将启动相应的过程并传递参数。
如何编写文档
编写部分非常简单。事实上,对于 Elasticsearch,有两种选择。使用低级框架,您可以获得 elastic API 的封装实现。这有助于避免手动绑定和组合 JSON 负载。但是,如果您想处理数据,一个不错的选择是 NEST。NEST 是高级框架,如果您是 ORM 方面的专家,这应该不足为奇。
您只需要为要保存的文档创建类,并使用注释定义如何保存属性,然后调用保存 API。
我不认为这太复杂,而且听起来更像一个普通的例程。这是类定义的代码片段。在本例中,我为每个文档只使用一个字段,其中包含一行文本。
public class LogDocument
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Body { get; set; }
}
下一步是创建索引。在这一步中,我们将索引与类关联起来。这可以手动完成,指定存储设置,或使用自动映射。在我们的示例中,“Id
”字段会自动映射到文档的唯一标识符。
client.Indices.Create(indexName, c => c
.Map<LogDocument>(m => m
.AutoMap<LogDocument>()
)
);
最后,我们有了代码中最愚蠢的部分:写入数据。因为我们想将所有诗句的行保存到许多文档中,每行一个文档,所以我们只有一个迭代。
string[] lines = File.ReadAllLines(filepath);
int items = 0;
Parallel.ForEach(lines, (line) =>
{
if (!string.IsNullOrWhiteSpace(line))
{
client.CreateDocument<LogDocument>(new LogDocument()
{
Body = line.Trim()
});
items++;
}
});
请注意,通过 API 使用外部系统,我们可以使用并行结构来提高性能。
如何查询文档
这部分非常简单,而且非常清晰——至少我希望如此。访问文档的基本方法是使用常规的流畅 LINQ 语法。这是基本用法,我更倾向于将此演示集中在未得到充分记录的全文数据搜索用例上。
Elastic 允许使用原始查询在字段数据上查找。为此,您可以使用 Search
方法的正确重载,配置原始查询
var searchResponse = client.Search<LogDocument>(s => s
.Size(10)
.Query(q => q.QueryString(
qs => qs.Query(searchStr)
.AllowLeadingWildcard(true)
)
)
);
var docs = searchResponse.Documents;
带走什么
Elasticsearch 是领先的搜索引擎解决方案。它为应用程序提供了丰富的功能,例如全文搜索或文档索引。它可以用作服务或本地部署。无论哪种情况,对于基本用法,它都非常容易配置。
NEST 框架允许我们像通过 LINQ 访问简单数据库一样存储和访问 Elasticsearch,这使一切变得非常简单。
对于希望让最终用户编写查询的复杂场景,您可以使用原始查询并将结果映射到类。
资源
历史
- 2020 年 5 月 6 日:初始版本