net core 3.1使用ElasticSearch 全文搜索引擎

ElasticSearch 是一個開源的搜索引擎,創建在一個全文搜索引擎庫 Apache Lucene™ 基礎之上。 Lucene 能夠說是當下最早進、高性能、全功能的搜索引擎庫,不管是開源仍是私有。java

可是 Lucene 僅僅只是一個庫。爲了充分發揮其功能,你須要使用 Java 並將 Lucene 直接集成到應用程序中。 更糟糕的是,您可能須要得到信息檢索學位才能瞭解其工做原理。Lucene 很是 複雜。node

ElasticSearch 也是使用 Java 編寫的,它的內部使用 Lucene 作索引與搜索,可是它的目的是使全文檢索變得簡單, 經過隱藏 Lucene 的複雜性,取而代之的提供一套簡單一致的 RESTful API。git

然而,Elasticsearch 不只僅是 Lucene,而且也不只僅只是一個全文搜索引擎。 它能夠被下面這樣準確的形容:github

  • 一個分佈式的實時文檔存儲,每一個字段 能夠被索引與搜索
  • 一個分佈式實時分析搜索引擎
  • 能勝任上百個服務節點的擴展,並支持 PB 級別的結構化或者非結構化數據

官方客戶端在Java、.NET、PHP、Python、Ruby、Nodejs和許多其餘語言中都是可用的。根據 DB-Engines 的排名顯示,ElasticSearch 是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基於Lucene。api

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.htmloracle

一.安裝

https://www.elastic.co/cn/downloads/下載elasticsearch和可視化工具kibana (兩個版本號必定要同樣) (下載慢用迅雷或者翻 Q)app

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訪問性能最高的是註冊成單例服務,請求時要使用異步。這樣性能能夠提高到極致。

直接上代碼

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
public interface IElasticsearchProvider
    {
        IElasticClient GetClient();
    }
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
複製代碼
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);
        }
    }
複製代碼
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
複製代碼
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");
    }
複製代碼
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
複製代碼
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高亮查詢

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= View Code

若是你有安裝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

相關文章
相關標籤/搜索