ElasticSearch 是一個開源的搜索引擎,建立在一個全文搜索引擎庫 Apache Lucene™ 基礎之上。 Lucene 可以說是當下最先進、高性能、全功能的搜索引擎庫,無論是開源還是私有。
但是 Lucene 僅僅只是一個庫。為了充分發揮其功能,你需要使用 Java 並將 Lucene 直接集成到應用程序中。 更糟糕的是,您可能需要獲得信息檢索學位才能了解其工作原理。Lucene 非常 復雜。
ElasticSearch 也是使用 Java 編寫的,它的內部使用 Lucene 做索引與搜索,但是它的目的是使全文檢索變得簡單, 通過隱藏 Lucene 的復雜性,取而代之的提供一套簡單一致的 RESTful API。
然而,Elasticsearch 不僅僅是 Lucene,並且也不僅僅只是一個全文搜索引擎。 它可以被下面這樣准確的形容:
- 一個分布式的實時文檔存儲,每個字段 可以被索引與搜索
- 一個分布式實時分析搜索引擎
- 能勝任上百個服務節點的擴展,並支持 PB 級別的結構化或者非結構化數據
官方客戶端在Java、.NET、PHP、Python、Ruby、Nodejs和許多其他語言中都是可用的。根據 DB-Engines 的排名顯示,ElasticSearch 是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基於Lucene。
Elasticsearch文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
Elasticsearch.Net和Nest官方文檔:https://www.elastic.co/guide/en/elasticsearch/client/net-api/7.x/index.html
一.安裝
https://www.elastic.co/cn/downloads/下載elasticsearch和可視化工具kibana (兩個版本號一定要一樣) (下載慢用迅雷或者翻 Q)
1.(這一步忽略 因為我電腦沒安裝JDK 使用es自帶得不香嗎)環境配置 (注:Es自帶jdk,如果沒有特殊情況,可以使用es自帶jdk,把java_home這個環境變量刪除即可)
jdk下載,鏈接為:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
選擇對應版本的JDK

將下載好的jdk解壓安裝(請記住安裝目錄)
配置環境變量

然后點擊系統變量下面的新建 (一定要是系統變量,上面的用戶變量設置了是不會有效果的) 然后進行如下設置,確定好 就OK了,無需重啟

2.下載ElasticSeach並解壓運行
將下載好的Elasticsearch解壓 然后到 bin 目錄下 打開cmd窗口 輸入.\elasticsearch 回車 就開始啟動了,接下來在瀏覽器輸入 localhost:9200,回車,顯示下圖的信息就OK了


在window服務(w+r 輸入services.msc)里面就可以看到elasticsearch的服務了 立即啟動 這樣可以便捷進行啟動的操作。

如果沒有服務在ES文件夾的Bin目錄下。打開cmd(同上方啟動es的方法一致)輸入.\elasticsearch-service.bat install 然后安裝即可
如果不行輸入 .\elasticsearch-service-x64 install 就會出現出現服務不能啟動 報錯 其中一種方法(安裝java 1.8.0 jdk 再執行.\elasticsearch-service.bat install)
Es開啟外網訪問
9200端口開放外網訪問,並修改配置文件。
修改配置文件:
打開根目錄下的config文件夾,找到elasticsearch.yml
開啟:
cluster.name: my-application
node.name: node-1
network.host: 0.0.0.0
http.port: 9200
cluster.initial_master_nodes: ["node-1"]
開啟上面5個參數。注意host要修改成0.0.0.0。這五個參數必須都要開啟。
3.安裝Kibana到Window上(elasticsearch的可視化工具,類似於navicate)
Kibana 必須和你之前下載的 elasticsearch 版本一致。將下載好的kibana解壓到你的 Elasticsearch的目錄下

然后相同的方式,到kibana 的bin 目錄下打開cmd 啟動kibana就好了 輸入 .\kibana.bat 操作完后。瀏覽器打開 localhost:5601 就可以訪問kibana了
4.(可以不要)把Kibana安裝成WindowSever
(1)下載NSSM,下載地址:http://www.nssm.cc/download
(2)將NSSM解壓並將nssm.exe拷貝到kibana的bin\目錄下
(3)cmd命令進入到kibana的bin文件夾下
(4)執行安裝命令nssm install kibana。文件路徑選中kibana.bat

點擊安裝即可
安裝完成后就可以在服務里面看到該sever了
注:剛啟動Kiabana時,出現 Kibana server is not ready yet 這個錯誤的話不要慌,稍等下再訪問即可,該錯誤的意思是服務還沒有完全啟動。
Kibana開啟外網訪問 以及開啟中文
到config文件夾下找到kibana.yml該配置文件
修改或者添加如下配置
server.port: 5601
server.host: "0.0.0.0"
i18n.locale: "zh-CN"
5.Elasticsearch 裝完后可以打開 kibana 進行創建節點及測試使用了。部署完es的地址后。可以進行 .Net Core的部署了
6.IK分詞器
下載對應的ik中文分詞(https://github.com/medcl/elasticsearch-analysis-ik/releases)和英文分詞(https://github.com/medcl/elasticsearch-analysis-pinyin/releases)拼音分詞器:https://github.com/medcl/elasticsearch-analysis-pinyin
下載后復制到es的plugins 目錄下,解壓就行了

ik也可以自定義分詞自己建一個文件放詞語(詳見github上的示例)

安裝完成后需要重啟 elasticsearch,然后測試分詞器是否OK 有兩種參考https://www.cnblogs.com/MrHSR/p/12258466.html
官方mapping制圖文檔 https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/fluent-mapping.html
//如果不存在該索引 就添加mapping制圖的分詞 if (!(await IndexExistsAsync(index))) { var createIndexResponse = _elasticClient.Indices.Create(index, c => c .Map<BlogInfo>(m => m .Properties(ps => ps .Text(s => s.Name(s => s.Title).Analyzer("ik_smart"))//有兩種ik_max_word .Text(s => s.Name(s => s.Content).Analyzer("ik_smart")) ) ) ); } var response = await _elasticClient.IndexAsync(entity, s => s.Index(index));
常用命令
GET _cat/indices 所有索引 GET blog/_search {} 獲取blog索引全部的文檔 PUT /index 建立索引 POST /blog/_mapping { "properties": { "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" } } } 給ik搜索設置ik_max_word DELETE blog 刪除索引
GET blog查看當前索引
二.在Asp.netcore 上使用ElasticSearch
1..安裝NuGet包,搜索Nest 並安裝

2.開始使用
這里是以服務的方式進行實現的,經過測試ElasticSearch訪問性能最高的是注冊成單例服務,請求時要使用異步。這樣性能可以提升到極致。
直接上代碼
public interface IElasticsearchProvider { IElasticClient GetClient(); }
public class ElasticsearchProvider : IElasticsearchProvider { public IElasticClient GetClient() { var url = AppSettings.Configuration["ElasticSearchContext:Url"]; //如果有多個節點以|分開 //var urls = url.Split('|').Select(x => new Uri(x)).ToList(); //單個節點 var connectionSettings = new ConnectionSettings(new Uri(url)); //多個節點 //var connectionPool = new SniffingConnectionPool(urls); //var connectionSetting = new ConnectionSettings(connectionPool).DefaultIndex(""); //如果有賬號密碼 //connectionSettings.BasicAuthentication(UserName, Password); return new ElasticClient(connectionSettings); } }
public interface IElasticsearchService { /// <summary> /// 是否存在索引 /// </summary> /// <param name="index"></param> /// <returns></returns> Task<bool> IndexExistsAsync(string index = "blog"); /// <summary> /// 新增數據 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="index"></param> Task InsertAsync(BlogInfo entity, string index = "blog"); /// <summary> /// 批量新增 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="entity"></param> /// <param name="index"></param> Task InsertRangeAsync(IEnumerable<BlogInfo> entity, string index = "blog"); /// <summary> /// 根據索引刪除數據 /// </summary> /// <param name="index"></param> /// <returns></returns> Task RemoveIndex(string index = "blog"); /// <summary> /// 根據索引刪除數據 ID /// </summary> /// <param name="Id">實體ID</param> /// <param name="index"></param> /// <returns></returns> Task DeleteAsync(string Id,string index = "blog"); /// <summary> /// 修改 /// </summary> /// <param name="Id"></param> /// <param name="index"></param> /// <returns></returns> Task UpdateAsync(BlogInfo entity, string index = "blog"); /// <summary> /// 查詢 /// </summary> /// <param name="page"></param> /// <param name="limit"></param> /// <param name="index"></param> /// <returns></returns> Task<Tuple<int, IList<BlogInfo>>> QueryAsync(int page, int limit, string index = "blog"); }
public class ElasticsearchService : IElasticsearchService { private readonly IElasticClient _elasticClient; public ElasticsearchService(IElasticsearchProvider esClientProvider) { _elasticClient = esClientProvider.GetClient(); } public async Task<bool> IndexExistsAsync(string index="blog") { return (await _elasticClient.Indices.ExistsAsync(index)).Exists; } public async Task InsertAsync(BlogInfo entity, string index = "blog") { //這里可判斷是否存在 var response = await _elasticClient.IndexAsync(entity, s => s.Index(index)); if (!response.IsValid) throw new Exception("新增數據失敗:" + response.OriginalException.Message); } public async Task InsertRangeAsync(IEnumerable<BlogInfo> entity, string index = "blog") { var bulkRequest = new BulkRequest(index) { Operations = new List<IBulkOperation>() }; var operations = entity.Select(o => new BulkIndexOperation<BlogInfo>(o)).Cast<IBulkOperation>().ToList(); bulkRequest.Operations = operations; var response = await _elasticClient.BulkAsync(bulkRequest); if (!response.IsValid) throw new Exception("批量新增數據失敗:" + response.OriginalException.Message); } public async Task UpdateAsync(BlogInfo entity, string index = "blog") { var response = await _elasticClient.UpdateAsync<BlogInfo>(entity.ID, x => x.Index(index).Doc(entity)); if (!response.IsValid) throw new Exception("更新失敗:" + response.OriginalException.Message); } public async Task DeleteAsync(string Id, string index = "blog") { await _elasticClient.DeleteAsync<BlogInfo>(Id, x => x.Index(index)); } public async Task RemoveIndex(string index = "blog") { var exists = await IndexExistsAsync(index); if (!exists) return; var response = await _elasticClient.Indices.DeleteAsync(index); if (!response.IsValid) throw new Exception("刪除index失敗:" + response.OriginalException.Message); } public async Task<Tuple<int, IList<BlogInfo>>> QueryAsync(int page, int limit, string index = "blog") { var query = await _elasticClient.SearchAsync<BlogInfo>(x => x.Index(index) .From((page - 1) * limit) .Size(limit) .Sort(x => x.Descending(v => v.CreateDate))); return new Tuple<int, IList<BlogInfo>>(Convert.ToInt32(query.Total), query.Documents.ToList()); } }
3.在startup里面在ConfigureServices下面添加如下代碼即可
services.AddScoped<IElasticsearchProvider, ElasticsearchProvider>();
services.AddTransient<IElasticsearchService, ElasticsearchService>();
按照新增、更新、刪除、查詢的順序依次調用接口。新增可以多來幾次,因為默認是沒有數據的,多添加一點可以測試分頁是否ok,這里就不再演示了。
3.1查詢指定字段
var search = client.Search<AllInformationViewModel>(s => s .Index(indexName) .From(page) .Size(10) .Query(q => q .Match(m => m .Field(f => f.Title) .Query(keyword))
3.2全文檢索(包括全部字段我都查找,標題啊,描述啊,摘要啊)
var searchAll = client.Search<AllInformationViewModel>(s => s .Index(indexName) .From(page) .Size(10) .Query(q => q .QueryString(qs => qs .Query(keyword).DefaultOperator(Operator.And))
3.3全文檢索查的標題,描述都得給我高亮
#方法1 .Highlight(h => h .PreTags("<em>") .PostTags("</em>") .Encoder(HighlighterEncoder.Html) .Fields( fs => fs .Field(p => p.Title), fs => fs .Field(p => p.Content) ) ) #方法2 .Highlight(h => h .Fields( fs => fs .Field(p => p.Title) .PreTags("<em>") .PostTags("</em>"), fs => fs .Field(p => p.Content) .PreTags("<em>") .PostTags("</em>") ) )
3.4高亮查詢
public ActionResult Index(string keywords="") { var settings = new ConnectionSettings(new Uri("http://192.168.3.8:9200/")).DefaultIndex("article"); var client = new ElasticClient(settings); var search = client.Search<Article>(s => s .From(0) .Size(10) .Query(q => q .Match(m => m .Field(f => f.Title) .Query(keywords)) ) .Highlight(h => h.Fields(e => e.Field("title") .PreTags("<b style='color:red'>") .PostTags("</b>"))) //.Sort(r => r.Descending(q => q.CreateDate)) //在工作中把<b style='color:red'>這個換成em標簽就可以了,然后在css里面給em加上高亮即可 ); foreach (var hit in search.Hits) { foreach (var highlightField in hit.Highlight) { if (highlightField.Key == "title") { foreach (var highlight in highlightField.Value) { hit.Source.Title = highlight.ToString(); } } } } return View(search.Documents); }
如果你有安裝kibana,現在可以滿懷驚喜的去查看一下剛才添加的數據。
GET _cat/indices GET visitlogs/_search {}

已經有大佬寫好ES的增刪改查的一個基礎類庫 (EasyElasticSearch)項目地址: https://github.com/wmchuang/EasyElasticSearch 博客地址https://www.cnblogs.com/mchuang/p/13678080.html
默認分詞是一元分詞 可以自己擴展就像以前的盤古分詞一樣 目前有個IK分詞器https://github.com/medcl/elasticsearch-analysis-pinyin
搜索命令https://www.dazhuanlan.com/2019/09/14/1603cbb548bc/ https://www.cnblogs.com/yunquan/p/12934209.html
參考地址https://www.cnblogs.com/meowv/p/13614455.html
