NET ElasticSearch 简单入门 docker 安装方式
简介
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,注意版本号变化
一、安装环境
注意!!!
无中文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
ik:elasticsearch-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; } }
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; } }
主类代码显得凌乱,本人还未整理出一个合适的工具类,大家将就看看,与其他教程区别在于加了验证,免踩坑
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
最后感觉真挺费脑的,头发又少了一撮