dotNet Core 3.1 使用 Elasticsearch

Elasticsearch 是基于 Lucene 的搜索引擎。可以非常方便地實現(xiàn)分布式的全文搜索,本文介紹在 dotNet Core 3.1 中怎樣使用 ?Elasticsearch 。
版本
- dotnet Core :3.1
- Elasticsearch:7.6.1
- Kibana:7.6.1
- NEST:7.10.1
- Docker:19.03.13
Docker 安裝 Elasticsearch
為了方便,我們以 Docker 的方式來進行安裝,這里使用的版本為 7.6.1,首先執(zhí)行下面命令進行鏡像的拉取:
docker?pull?elasticsearch:7.6.1
注意:這里需要指定相關版本,版本可以在 dockerhub 上進行查詢 ,否則拉鏡像的時候可能出現(xiàn) 下面錯誤:
Error?response?from?daemon:?manifest?for?elasticsearch:latest?not?found:?manifest?unknown:?manifest?unknown
鏡像成功拉取后,執(zhí)行 docker run 命令構建容器,命令如下:
docker?run?-d?--name?myes?-p?9200:9200?-p?9300:9300?-e?"discovery.type=single-node"?-e?"ES_JAVA_OPTS=-Xms512m?-Xmx512m"?elasticsearch:7.6.1
為了更好地進行中文的搜索,需要安裝中文分詞插件,本文中安裝的中文分詞插件為 ik ,版本和 Elasticsearch 一致,安裝方法如下:
進入 Elasticsearch 容器后執(zhí)行:
./bin/elasticsearch-plugin?install?[https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.6.1/elasticsearch-analysis-ik-7.6.1.zip](https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip)
安裝成功后的如下圖所示:

Docker 安裝 Kibana
Kibana 是一個免費的用戶界面,能夠讓您對 Elasticsearch 數(shù)據(jù)進行可視化,不是必須,但可以更好地查看數(shù)據(jù)。
執(zhí)行下面命令進行鏡像的拉取,版本和 Elasticsearch 一致:
docker?pull?kibana:7.6.1
在宿主機創(chuàng)建 /root/data/elk/ 目錄并創(chuàng)建配置文件 kibana.yml ,內容如下:
#?Default?Kibana?configuration?for?docker?target
server.name:?kibana
server.host:?"0"
elasticsearch.hosts:?[?"http://172.17.0.6:9200"?]
xpack.monitoring.ui.container.elasticsearch.enabled:?true
elasticsearch.hosts 配置為 Elasticsearch 的訪問地址。
執(zhí)行下面命令進行容器的創(chuàng)建
docker?run?-d?--restart=always?--log-driver?json-file?--log-opt?max-size=100m?--log-opt?max-file=2?--name?mykibana?-p?5601:5601?-v?/root/data/elk/kibana.yml:/usr/share/kibana/config/kibana.yml?kibana:7.6.1
創(chuàng)建成功后,可以通過 5601 端口進行訪問。
Elasticsearch 的 API
Elasticsearch 提供 API 的方式來進行數(shù)據(jù)操作,非常方便,常用的三個接口:
- 插入數(shù)據(jù)
- 獲取單條數(shù)據(jù)
- 查詢數(shù)據(jù)
插入數(shù)據(jù)
http://10.211.55.6:9200/index/oec2003/1

- index:我的理解是相當于數(shù)據(jù)庫表的概念;
- oec2003:在 Elasticsearch 的 index 中有個 Type 的概念,相當于分組,當前的 7.6.1 版本中一個 index ?中只能有一個 Type ,所以相當于可以忽略;
- 1:單條記錄的 id;
- 接口為 Post 方式,數(shù)據(jù)內容為 Json 格式,字段可以隨便定義,而且每條數(shù)據(jù)的字段可以不相同。
獲取單條數(shù)據(jù)
http://10.211.55.6:9200/index/oec2003/1

搜索數(shù)據(jù)
http://10.211.55.6:9200/index/oec2003/_search

- 查詢接口為 Post 方式;
- 查詢表達式也是 Json 格式,如果熟悉 MongoDB 的 Document ,應該會感覺很熟悉。
在 dotNet Core 3.1 中使用
1、在 VS 2019 中創(chuàng)建 dotNet Core 3.1 ?的 WebAPI 項目 ElasticsearchWebAPIDemo ;
2、引用 Nuget 包 NEST;
3、創(chuàng)建一個 Elasticsearch 的客戶端連接接口和類,代碼如下:
class?ESClientProvider?:?IESClientProvider
{
????private?ElasticClient?_client;
????public?ESClientProvider()
????{
????}
????public?ElasticClient?GetClient()
????{
????????if?(_client?!=?null)
????????????return?_client;
????????InitClient();
????????return?_client;
????}
????private?void?InitClient()
????{
????????var?node?=?new?Uri("http://10.211.55.6:9200");
????????_client?=?new?ElasticClient(new?ConnectionSettings(node).DefaultIndex("artiles"));
????}
}
public?interface?IESClientProvider
{
????ElasticClient?GetClient();
}
4、在 Startup 類的 ConfigureServices 方法中將 ESClientProvider 類注冊為單例
public?void?ConfigureServices(IServiceCollection?services)
{
????services.AddSingleton();
????services.AddSwaggerGen(c?=>
????{
????????c.SwaggerDoc("v1",?new?OpenApiInfo?{?Title?=?"My?API",?Version?=?"v1"?});
????});
????services.AddControllers();
}
5、創(chuàng)建 Article 實體類
[ElasticsearchType(IdProperty?=?"Id")]
public?class?Article
{
???[Keyword]
???public?string?Id?{?get;?set;?}
???[Keyword]
???public?string?Title?{?get;?set;?}
???[Keyword]
???public?string?Auther?{?get;?set;?}
???[Keyword]
???public?string?SubTitle?{?get;?set;?}
}?
6、創(chuàng)建 ESController,添加創(chuàng)建 index 的方法
[HttpGet]
[Route("CreateIndex")]
public?bool?CreateIndex(string?indexName)
{
????var?res?=?_client.Indices.Create(indexName,?c?=>?c.Map(h?=>?h.AutoMap().Properties(ps?=>?ps
????.Text(s?=>?s
?????????.Name(n?=>?n.Title)
?????????.Analyzer("ik_smart")
?????????.SearchAnalyzer("ik_smart")
?????????)
????.Text(s?=>?s
?????????.Name(n?=>?n.SubTitle)
?????????.Analyzer("ik_smart")
?????????.SearchAnalyzer("ik_smart")
?????????)
????)
????));
????return?res.IsValid;
}
- 對什么字段進行索引需要進行指定
- 字段的分詞器和搜索關鍵字的分詞器建議使用相同,否則可能搜索不到數(shù)據(jù),例如上面代碼中都指定為 ik_smart
7、添加 AddArticles 的方法
[HttpPost]
[Route("AddArticles")]
public?bool?AddArticles()
{
????//?獲取數(shù)據(jù)批量進行插入
????List?listArticle?=?GetArticles();
???
????return?_client.IndexMany(listArticle).IsValid;
}
8、添加高亮搜索的方法 SearchHighlight
[HttpPost]
[Route("SearchHighlight")]
public?List?SearchHighlight(string?key,?int?pageIndex?=?0,?int?pageSize?=?10)
{
????var?searchAll?=?_client.Search(s?=>?s
??????.From(pageIndex)
??????.Size(pageSize)
??????.Query(q?=>?q
????????????.QueryString(qs?=>?qs
????????????.Query(key)
????????????.DefaultOperator(Operator.Or)))
??????.Highlight(h?=>?h
????????????.PreTags("")
????????????.PostTags("")
????????????.Encoder(HighlighterEncoder.Html)
????????????.Fields(
????????????????fs?=>?fs.Field(p?=>?p.Title),
????????????????fs?=>?fs?.Field(p?=>?p.SubTitle)
????????????)
????????)
??????);
????foreach?(var?hit?in?searchAll.Hits)
????{
????????foreach?(var?highlightField?in?hit.Highlight)
????????{
????????????if?(highlightField.Key?==?"title")
????????????{
????????????????foreach?(var?highlight?in?highlightField.Value)
????????????????{
????????????????????hit.Source.Title?=?highlight.ToString();
????????????????}
????????????}
????????????else?if?(highlightField.Key?==?"subTitle")
????????????{
????????????????foreach?(var?highlight?in?highlightField.Value)
????????????????{
????????????????????hit.Source.SubTitle?=?highlight.ToString();
????????????????}
????????????}
????????}
????}
????return?searchAll.Documents.ToList();
}
在 Kibana 中查看數(shù)據(jù)
Kibana 容器運行起來后,可以通過端口 5601 進行訪問,進行簡單配置就可以查看數(shù)據(jù)了,具體步驟如下:
1、進入 Management→ Index Management ,如下圖:

在改功能中可以維護所有的 idnex ,也可以看看我們創(chuàng)建的 index 有沒有在里面顯示:

2、在 Index Patterns 中進行 index pattern 的添加,名字可以進行模糊匹配:

3、在 Discover 菜單中進行數(shù)據(jù)查看,在這里可以選擇之前創(chuàng)建的 index pattern:

總結
本文只是很簡單的一個示例,帶你入門,有了基本概念后,深入學習更多的高級用法就很容易了,文章中部分示例代碼來自團隊中的王同學,在此感謝!
希望本文對您有所幫助!
