NET ElasticSearch 简单入门 docker 安装方式

ElasticSearch 官网

简介

Elasticsearch是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。
Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)。
Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。Elasticsearch是分布式的,这意味着索引可以被分成分片,每个分片可以有0个或多个副本。每个节点托管一个或多个分片,并充当协调器将操作委托给正确的分片。再平衡和路由是自动完成的。相关数据通常存储在同一个索引中,该索引由一个或多个主分片和零个或多个复制分片组成。一旦创建了索引,就不能更改主分片的数量。
Elasticsearch使用Lucene,并试图通过JSON和Java API提供其所有特性。它支持facetting和percolating,如果新文档与注册查询匹配,这对于通知非常有用。另一个特性称为“网关”,处理索引的长期持久性;例如,在服务器崩溃的情况下,可以从网关恢复索引。Elasticsearch支持实时GET请求,适合作为NoSQL数据存储,但缺少分布式事务
来自百度百科

 

本文环境

Windows 10 +Docker 4.11.1 +NET Framework4.8+SqlSugar.Net 5.1.2+elasticsearch:8.2.3+kibana:8.2.3+ik8.2.3

最好有科学与上网方式,否则网速抓狂,容器地址可以换成国内的,下载速度会快很多。

Docker容器服务:不懂就百度, Docker没安装请自行去官网下载

kibana:elasticsearch数据可视化服务,相当于管理控制台,在上面可安装插件

ik:中文分词器,在2022-08-17的时候也只更到8.2.3,elasticsearch这时已经更新到8.3.3,注意版本号变化

SqlSugar :国产ORM,只用于查询数据库数据使用,没有也可以,只是不好一下子查询太多数据
 

一、安装环境

ElasticSearch官网Docker安装教程

Elastic kibana 官网Docker安装教程

 

注意!!!

无中文IK按官网版本没问题,但是要用ik中文分词,如果版本不一致,会出现docker无法启动的问题

 

1.1安装elasticsearch

windows键+R,打开PowerShell(管理员)

先下载 elasticsearch

docker pull docker.elastic.co/elasticsearch/elasticsearch:8.2.3  //下载elasticsearch,

可以同时下载kibana

docker pull docker.elastic.co/kibana/kibana:8.2.3

下载ik

ikelasticsearch-analysis-ik-8.2.3.zip

 

创建网关

docker network create elastic

创建容器elasticsearch

docker run --name es-node01 --network elastic -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 -t docker.elastic.co/elasticsearch/elasticsearch:8.2.3

成功后会打出下列文字,用个记事本全部记录起来

-> Elasticsearch security features have been automatically configured!
-> Authentication is enabled and cluster connections are encrypted.

->  Password for the elastic user (reset with `bin/elasticsearch-reset-password -u elastic`):
  jx*tYsjgg=lRhMkiV=XP

->  HTTP CA certificate SHA-256 fingerprint:
  589ecfaf4ea4afd376e195c02d956ba4c6f93426b1f156d1e7ce9a4cf6addb4a

->  Configure Kibana to use this cluster:
* Run Kibana and click the configuration link in the terminal when Kibana starts.
* Copy the following enrollment token and paste it into Kibana in your browser (valid for the next 30 minutes):
  eyJ2ZXIiOiI4LjIuMyIsImFkciI6WyIxNzIuMTkuMC4yOjkyMDAiXSwiZmdyIjoiNTg5ZWNmYWY0ZWE0YWZkMzc2ZTE5NWMwMmQ5NTZiYTRjNmY5MzQyNmIxZjE1NmQxZTdjZTlhNGNmNmFkZGI0YSIsImtleSI6InVfemZwWUlCaV94cHgxaVhuSktfOjExdHZyN1JDVHZlZlF6M2lxeDBmcUEifQ==

-> Configure other nodes to join this cluster:
* Copy the following enrollment token and start new Elasticsearch nodes with `bin/elasticsearch --enrollment-token <token>` (valid for the next 30 minutes):
  eyJ2ZXIiOiI4LjIuMyIsImFkciI6WyIxNzIuMTkuMC4yOjkyMDAiXSwiZmdyIjoiNTg5ZWNmYWY0ZWE0YWZkMzc2ZTE5NWMwMmQ5NTZiYTRjNmY5MzQyNmIxZjE1NmQxZTdjZTlhNGNmNmFkZGI0YSIsImtleSI6InVmemZwWUlCaV94cHgxaVhuSktrOjN3X09NSjlsVDEyYnRycW9zMVdUaWcifQ==

  If you're running in Docker, copy the enrollment token and run:
  `docker run -e "ENROLLMENT_TOKEN=<token>" docker.elastic.co/elasticsearch/elasticsearch:8.2.3`
------------------------------------------------------------------------------------------------------------------------

安装完后打开https://localhost:9200/

这时会弹出证书不安全提示,继续。关于证书问题,本人尝试过解决,学艺未精,行不通

尝试解决https不安全问题,这个可以不看

复制容器里的证书到本地,执行下面这句会复制到C盘,记住用管理员账号

docker cp es-node01:/usr/share/elasticsearch/config/certs/http_ca.crt /

 

 

 

 

 

 

 

 

 

 点完成后网上说有用,但真没用。。

 

 

 

 

 

 

 

 

 

 

 

  要求输入账号密码

 

 

 

 

 账号默认:elastic

密码初始时随机:

 

 

 就是系统弹出的提示,在里面找

登录后得到json

 

走到这一步,Elasticsearch已经算是安装完成了。

但是没管理工具有些抓瞎,所以要安装

但是我们是要用中文分词,所以得把ik复制进去

 

1.2安装kibana

 新打开PowerShell,用同一个网关

docker run --name kib-01 --net elastic -p 5601:5601 docker.elastic.co/kibana/kibana:8.2.3

 

 

 

 

 成功后看到上面有个code,别急着关掉,code有用

打开http://localhost:5601/  ,注意这里是http,不是https

弹出填token,填上第一步的token,下一步,账号密码用 elastic与刚刚的随机密码

 

 

 进入这一页,kibana就算安装完成,具体使用请参考别的教程

 

 

 

 

 

1.3 安装ik

教程

解压到一个空目录,然后建个叫ik 的文件夹,把内容都拖进ik

 

 

 在ik这一层文件夹打开cmd,把ik复制到docker里面

docker cp ik es-node01:/usr/share/elasticsearch/plugins/ik/
es-node01就是刚刚安装的容器名称

 

重启docker:es-node01

我喜欢在docker DeskTop重启,如果10秒后还在运行,说明ik已成功安装

如果停止了,进去看日志并百度吧,资料很少。我是靠用相同版本的ES和IK解决启动不了的问题,这里是8.2.3

 

 

 

 

 

 

 

二、NET测试

新建个控制台程序

1.1 用nuget安装好

Elasticsearch.Net

NEST 

SqlSugar

 

1.2新建Model类

using Nest;
using System;   
[ElasticsearchType(Name = "material", IdProperty = "MaterialID")]
    public class tl_MaterialModel
    {
        /// <summary>
        /// 主键ID[编辑]
        /// </summary>        
        public Guid MaterialID { get; set; }
        /// <summary>
        /// 材料分类ID[新增、编辑]
        /// </summary>        
        public Guid MaterialTypeID { get; set; }
        /// <summary>
        /// 分类名称[新增、编辑] 
        /// </summary>        
        public string MaterialTypeName { get; set; }
        /// <summary>
        /// 材料名称[新增、编辑]
        /// </summary>        
        public string MaterialName { get; set; }
        /// <summary>
        /// 材料名称[新增、编辑]
        /// </summary>    
        public string MaterialName { get; set; }
        /// <summary>
        /// 材料编码[新增、编辑]
        /// </summary>        
        public string MaterialCode { get; set; }
        /// <summary>
        /// 型号[新增、编辑]
        /// </summary>        
        public string Pattern { get; set; }
        /// <summary>
        /// 品牌[新增、编辑]
        /// </summary>        
        public string Brand { get; set; }
        /// <summary>
        /// 以逗号分割的档次ID[新增、编辑]
        /// </summary>        
        public string Grades { get; set; }
        /// <summary>
        /// 以逗号分割的色系ID[新增、编辑]
        /// </summary>        
        public string Colors { get; set; }
        /// <summary>
        /// 创建人
        /// </summary>        
        public Guid CreaterID { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>        
        public DateTime CreateTime { get; set; }
        /// <summary>
        /// 修改人
        /// </summary>        
        public Guid UpdateID { get; set; }
        /// <summary>
        /// 修改时间
        /// </summary>        
        public DateTime UpdateTime { get; set; }
       /// <summary>
        /// 属性字符串
        /// </summary>
        public string AttrValues { get; set; }
         /// <summary>
        /// 关键字
        /// </summary>
        public string Keyword { get; set; }
 }       
View Code

 

1.3 代码

因为这里用的https,并且我本机安装了证书不成功,因而请求会报SSL错误

所以这里另外加了个工具类,http或者真实证书是不需要这么做的

先说几个坑:


1.Util.SetCertificatePolicy();//处理https报错的问题

2.indexName不要用大写,纯小写不会出错

3.需要写账号密码settings.BasicAuthentication("elastic", "jx*tYsjgg=lRhMkiV=XP");

4.如果传过take参数,最好一直传

 

public static class Util
        {
            /// <summary>
            /// Sets the cert policy.
            /// </summary>
            public static void SetCertificatePolicy()
            {
                ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate;
            }

            /// <summary>
            /// Remotes the certificate validate.
            /// </summary>
            private static bool RemoteCertificateValidate(
               object sender, X509Certificate cert,
                X509Chain chain, SslPolicyErrors error)
            {
                // trust any certificate!!!
                System.Console.WriteLine("Warning, trust any certificate");
                return true;
            }
        }
View Code

 

主类代码显得凌乱,本人还未整理出一个合适的工具类,大家将就看看,与其他教程区别在于加了验证,免踩坑

 settings.BasicAuthentication("elastic", "jx*tYsjgg=lRhMkiV=XP");
ES修改删除是根据ID来的,

主类

using Elasticsearch.Net;
using Nest;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

 
//从数据库获取数据
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = "SERVER=xxx;UID=xx;PWD=xxxxx;DATABASE=xxdb;",
                DbType = DbType.SqlServer,
                IsAutoCloseConnection = true//自动释放
            });
            var list = db.Ado.SqlQuery<tl_MaterialModel>("SELECT * FROM tl_Material");

 Util.SetCertificatePolicy();//处理https报错的问题

       //建立单点链接
            var node = new Uri("https://localhost:9200");
            var settings = new ConnectionSettings(node);
            settings.BasicAuthentication("elastic", "jx*tYsjgg=lRhMkiV=XP");//这个版本链接需要加账号密码
            var elasticClient = new ElasticClient(settings);

            string indexName = "material";//定义索引名字


//DeleteIndices(elasticClient, indexName);//删除索引
       
            //批量插入
            //BulkAll(elasticClient, indexName, list);

            //查询所有
            SearchRequest sr = new SearchRequest(indexName);
            var request = new MatchQuery
            {
                Field = "Keyword",
                Query = "铝单板",
            };

            sr.Query = request;
            sr.From = 0;
            sr.Size = 1000;
            var result = elasticClient.Search<tl_MaterialModel>(sr);

    //另外一种写法
 var query = new Nest.SearchDescriptor<tl_MaterialModel>(indexName);
            query.Query(q =>
                            q.Bool(b =>
                                    b.Must(m =>
                                      m.MultiMatch(t => t.Fields(f => f.Field(obj => obj.Keyword)).Query("离风机"))
                         )

                         )
                );
            query.Highlight(h => h
        .PreTags("<b>")
        .PostTags("</b>")
        .Fields(
            f => f.Field(obj => obj.MaterialTypeName),
            f => f.Field(obj => obj.AttrValues),
            f => f.Field(obj => obj.Pattern),
            f => f.Field(obj => obj.Brand),
            f => f.Field(obj => obj.Keyword),
            f => f.Field(obj => obj.MaterialName)
        )
    );

            query.Take(1000);
            query.Sort(x => x.Field(obj => obj.CreateTime, Nest.SortOrder.Ascending));
            result = elasticClient.Search<tl_MaterialModel>(x => query);
            r = result.Documents.ToList();

//单个修改
            var upR = elasticClient.Update<tl_MaterialModel, object>(r[0].MaterialID,
                upt =>
            {
                upt.Index(indexName); upt.Doc(new { MaterialName = "JJJXXX" }); return upt;
            });


 /// <summary>
        /// 批量插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="elasticClient"></param>
        /// <param name="indexName"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool BulkAll<T>(IElasticClient elasticClient, IndexName indexName, IEnumerable<T> list) where T : class
        {
            const int size = 1000;
            List<string> errors = new List<string>();
            int seenPages = 0;
            int requests = 0;
            CancellationTokenSource tokenSource = new CancellationTokenSource();
            ConcurrentBag<BulkResponse> bulkResponses = new ConcurrentBag<BulkResponse>();
            ConcurrentBag<BulkAllResponse> bulkAllResponses = new ConcurrentBag<BulkAllResponse>();
            ConcurrentBag<T> deadLetterQueue = new ConcurrentBag<T>();
            BulkAllObservable<T> observableBulk = elasticClient.BulkAll(list, f => f
                    .MaxDegreeOfParallelism(Environment.ProcessorCount)
                    .BulkResponseCallback(r =>
                    {
                        bulkResponses.Add(r);
                        Interlocked.Increment(ref requests);
                    })
                    .ContinueAfterDroppedDocuments()
                    .DroppedDocumentCallback((r, o) =>
                    {
                        if (r.Error != null)
                            errors.Add(r.Error.Reason);
                        deadLetterQueue.Add(o);
                    })
                    .BackOffTime(TimeSpan.FromSeconds(5))
                    .BackOffRetries(2)
                    .Size(size)
                    .RefreshOnCompleted()
                    .Index(indexName)
                    .BufferToBulk((r, buffer) => r.IndexMany(buffer))
                , tokenSource.Token);

            try
            {
                observableBulk.Wait(TimeSpan.FromMinutes(15), b =>
                {
                    bulkAllResponses.Add(b);
                    Interlocked.Increment(ref seenPages);
                });
            }
            catch (Exception e)
            {
                Console.WriteLine("Exxx => " + e.Message);
            }
            foreach (var err in errors)
            {
                Console.WriteLine("Error : " + err);
            }
            return true;
        }
        /// <summary>
        /// 清空所有索引
        /// </summary>
        /// <param name="elasticClient"></param>
        public static void DeleteIndices(IElasticClient elasticClient)
        {
            var indicesResponse = elasticClient.Cat.Indices(cid => cid.AllIndices());
            foreach (var item in indicesResponse.Records)
            {
                elasticClient.Indices.Delete(item.Index);
            }
        }
        /// <summary>
        /// 清空单个业务索引
        /// </summary>
        /// <param name="elasticClient"></param>
        /// <param name="indexName"></param>
        public static void DeleteIndices(IElasticClient elasticClient, string indexName)
        {
            var indicesResponse = elasticClient.Cat.Indices(cid => cid.Index(indexName));
            foreach (var item in indicesResponse.Records)
            {
                elasticClient.Indices.Delete(item.Index);
            }
        }
        

 

https://localhost:9200/material   

 

 

 

整理返回内容可以参考

https://www.cnblogs.com/yunquan/p/12934209.html#%E5%89%8D%E8%A8%80

 

最后感觉真挺费脑的,头发又少了一撮

 

posted @ 2022-08-17 19:57  清风神剑  阅读(212)  评论(0编辑  收藏  举报