Elasticsearch.net client NEST 5.x 使用总结

引用

NEST.dll
Elasticsearch.Net.dll  
Newtonsoft.Json.dll

 

调试

  1. 本地debug时 可以通过fiddler抓取到请求es服务的http请求。
  2. 也可可以在代码中抓取到request和response
            var settings = new ConnectionSettings(pool);
            //在创建client时开启设置; //正式环境建议关闭,占用资源 settings.DisableDirectStreaming(true); var client=new ElasticClient(settings);   var result=client.Search(....);   var requestStr = System.Text.Encoding.Default.GetString(result.ApiCall.RequestBodyInBytes); var responseStr = System.Text.Encoding.Default.GetString(result.ApiCall.ResponseBodyInBytes); _log.Debug(requestStr + " " + responseStr);

存储结构:

在Elasticsearch中,文档(Document)归属于一种类型(type),而这些类型存在于索引(index)中. 

类比传统关系型数据库:

Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices   -> Types  -> Documents -> Fields
DB使用过程:创建数据库->创建表(主要是设置各个字段的属性)->写入数

ES使用过程:创建索引->为索引maping一个Type(同样是设置类型中字段的属性)->写入数

客户端语法

 

链式lambda 表达式( powerful query DSL)语法

s => s.Query(q => q
    .Term(p => p.Name, "elasticsearch") )

对象初始化语法

var searchRequest = new SearchRequest<VendorPriceInfo>
{
  Query = new TermQuery { Field = "name", Value = "elasticsearch" } };

Connection链接

//单node
Var node = new Uri(“……”); var settings = new ConnectionSettings(node);   //多uris Var uris = new Uri [] { new Uri(“……”), new Uri(“……”) }; var pool = new StaticConnectionPool(uris);   //多node Var nodes = new Node [] { new Node (new Uri(“……”)), new Node (new Uri(“……”)) }; //链接池 var pool = new StaticConnectionPool(nodes);   var settings = new ConnectionSettings(pool);   var client = new ElasticClient(settings);

注:nest默认字段名首字母小写,如果要设置为与Model中一致,在创建client时按如下设置。(强烈建议使用该设置,避免造成字段不一致)

var settings = new ConnectionSettings(node).DefaultFieldNameInferrer((name) => name);

Connection Settings

            var settings = new ConnectionSettings(pool);
            //验证 未开启 //settings.BasicAuthentication("username", "password"); //验证证书 //settings.ClientCertificate(""); //settings.ClientCertificates(new X509CertificateCollection()); //settings.ServerCertificateValidationCallback();   //开启 第一次使用时进行嗅探,需链接池支持 //settings.SniffOnStartup(false);   //链接最大并发数 //settings.ConnectionLimit(80); //标记为死亡节点的超时时间 //settings.DeadTimeout(new TimeSpan(10000)); //settings.MaxDeadTimeout(new TimeSpan(10000)); //最大重试次数 //settings.MaximumRetries(5); //重试超时时间 默认是RequestTimeout //settings.MaxRetryTimeout(new TimeSpan(50000)); //禁用代理自动检测 //settings.DisableAutomaticProxyDetection(true);   //禁用ping 第一次使用节点或使用被标记死亡的节点进行ping settings.DisablePing(false); //ping 超时设置 //settings.PingTimeout(new TimeSpan(10000)); //选择节点 //settings.NodePredicate(node => //{ // // return true; // //}); //默认操作索引 //settings.DefaultIndex(""); //字段名规则 与model字段同名 //settings.DefaultFieldNameInferrer(name => name); //根据Type 获取类型名 //settings.DefaultTypeNameInferrer(name => name.Name); //请求超时设置 //settings.RequestTimeout(new TimeSpan(10000)); //调试信息 settings.DisableDirectStreaming(true); //调试信息 //settings.EnableDebugMode((apiCallDetails) => //{ // //请求完成 返回 apiCallDetails   //}); //抛出异常 默认false,错误信息在每个操作的response中 settings.ThrowExceptions(true); //settings.OnRequestCompleted(apiCallDetails => //{ // //请求完成 返回 apiCallDetails //}); //settings.OnRequestDataCreated(requestData => //{ // //请求的数据创建完成 返回请求的数据   //}); return new ElasticClient(settings);

不同的连接池类型

            //支持ping 说明能够发现节点的状态
            //支持嗅探 说明能够发现新的节点
 
            //应用于已知集群,请求时随机请求各个正常节点,支持ping 不支持嗅探
            IConnectionPool pool = new StaticConnectionPool(nodes); //推荐使用   //IConnectionPool pool=new SingleNodeConnectionPool(nodes[0]);   //可动态嗅探集群 ,随机请求 支持嗅探、ping //IConnectionPool pool = new SniffingConnectionPool(nodes);   //选择一个可用节点作为请求主节点,支持ping 不支持嗅探 //IConnectionPool pool = new StickyConnectionPool(nodes);   //选择一个可用节点作为请求主节点,支持ping 支持嗅探 //IConnectionPool pool=new StickySniffingConnectionPool(nodes);

操作目标索引/类型选择

 

指定索引

//执行操作时指定索引
client.Search<VendorPriceInfo>(s => s.Index("test-index")); client.Index(data,o=>o.Index("test-index")); ....  

指定类型

默认类型为索引数据的类名(自动转换为全小写,规则可自定义)。 
如果特性设置Name[ElasticsearchType(Name = “datatype”)]则使用该名称。

//主动指定
client.Index(data, o => o.Type(new TypeName() { Name = "datatype", Type = typeof(VendorPriceInfo) }));

数据模型特性

特性可以设置数据在es中的类型、名称、是否索引、分词、格式化等信息。

应用于第一次创建索引后进行映射时。


重要特性:

  • [ElasticsearchType(Name = “文档的类型”,IdProperty = “文档的唯一键字段名”)]
  • [Number(NumberType.Long,Name = “Id”)] 数字类型 +名称
  • [Keyword(Name = “Name”,Index = true)]不需要分词的字符串,name=名称,index=是否建立索引
  • [Text(Name = “Dic”, Index = true,Analyzer = “ik_max_word”)]需要分词的字符串,name=名称,index=是否建立索引,Analyzer=分词器
    /// <summary>
    /// 5.x 特性
    /// </summary>
    [ElasticsearchType(Name = "TestModel",IdProperty = "Id")] public class TestModel5 { [Number(NumberType.Long,Name = "Id")] public long Id { get; set; } /// <summary> /// keyword 不分词 /// </summary> [Keyword(Name = "Name",Index = true)] public string Name { get; set; } /// <summary> /// text 分词,Analyzer = "ik_max_word" /// </summary> [Text(Name = "Dic", Index = true)] public string Dic { get; set; }   [Number(NumberType.Integer,Name = "State")] public int State { get; set; }   [Boolean(Name = "Deleted")] public bool Deleted { get; set; } [Date(Name = "AddTime")] public DateTime AddTime { get; set; }   [Number(NumberType.Float,Name = "PassingRate")] public float PassingRate { get; set; }   [Number(NumberType.Double, Name = "Dvalue")] public double Dvalue { get; set; } }  

索引操作

 

创建

client.CreateIndex("test2"); //基本配置 IIndexState indexState=new IndexState() { Settings = new IndexSettings() { NumberOfReplicas = 1,//副本数 NumberOfShards = 5//分片数 } }; //创建索引 先不maping client.CreateIndex("test2", p => p.InitializeUsing(indexState));   //创建并Mapping client.CreateIndex("test-index3", p => p.InitializeUsing(indexState).Mappings(m => m.Map<VendorPriceInfo>(mp => mp.AutoMap())));

注:索引名称必须小写

判断

client.IndexExists("test2");

删除

client.DeleteIndex("test2");

索引创建、maping、设置别名、别名操作

        /// <summary>
        /// 创建索引
        /// </summary>
        private void CreateIndex(string indexName) { if (!_client.IndexExists(indexName).Exists) {   IndexState indexState = new IndexState { Settings = new IndexSettings { NumberOfReplicas = _replicas, //副本数 NumberOfShards = _shards //分片数 } }; //创建并设置 _client.CreateIndex(indexName, p => p .InitializeUsing(indexState) .Mappings(m => m.Map<EsDataModel>(mps => mps.AutoMap())) .Aliases(a => a.Alias(_indexAliase + "_manager")) ); //map //_client.Map<EsDataModel>(m => m.Index(indexName).AutoMap());     #region 别名操作   Action addAlias = () => { _client.Alias(a => a.Add(d => d.Index(indexName).Alias(_indexAliase))); }; //该别名是否存在 if (!_client.AliasExists(s => s.Name(_indexAliase)).Exists) { addAlias(); return; } var result = _client.GetAlias(a => a.Name(_indexAliase)); //该别名下所有 索引 if (result.Indices == null) { addAlias(); return; } var indices = result.Indices.Select(index => index.Key).Select(dummy => (IndexName)dummy).ToArray(); //该别名下所有 索引 if (indices.Length <=0) { addAlias(); return; } //删除其它老的索引的别名 //添加到新的索引上 Func<AliasRemoveDescriptor, IAliasRemoveAction> removeSelector = d => { foreach (var index in indices) { d.Alias(_indexAliase).Index(index.Name); } return d; }; _client.Alias(a => a // 删除 别名 .Remove(removeSelector) //添加 别名 .Add(d => d.Index(indexName).Alias(_indexAliase)) ); #endregion } }

映射

如果创建索引时没有进行maping操作,可以再单独maping,已经确定类型的字段无法更改,可以新增。

           //根据对象类型自动映射
            var result = _client.Map<TestModel5>(m => m.AutoMap()); //手动指定 var result1 = _client.Map<TestModel5>(m => m.Properties(p => p.Keyword(s => s.Name(n => n.Name).Index(true))));//Keyword 类型

新增映射字段

            //新增字段
            var result = _client.Map<TestModel5>(m => m .Index(indexName) .Properties(p => p .Keyword(s => s .Name("NewField") .Index(true)) .Text(s=>s .Name("NewFieldText") .Index(false)) ) );

注:映射时已存在的字段将无法重新映射,只有新加的字段能映射成功。所以最好在首次创建索引后先进性映射再索引数据。 
注:映射时同一索引中,多个类型中如果有相同字段名,那么在索引时可能会出现问题(会使用第一个映射类型)。 
注:如果没有特殊需求,且字段没有过多的重叠,一个索引建议只存放一个类型的数据。

数据

 

添加单条数据

            //写入数据,指定索引
            _client.Index(data, s => s.Index(indexName)); //指定索引、类型 _client.Index(data,s=>s.Index(indexName).Type("TestModel5"));   //写入数据,指定索引 _client.IndexMany(datas, indexName); //指定索引、类型 _client.IndexMany(datas, indexName, "TestModel5");

删除数据

            DocumentPath<TestModel5> deletePath = new DocumentPath<TestModel5>(7); _client.Delete(deletePath,s=>s.Index(indexName)); _client.Delete(deletePath,s=>s.Index(indexName).Type(typeof(TestModel5))); _client.Delete(deletePath,s=>s.Index(indexName).Type("TestModel5"));   IDeleteRequest request = new DeleteRequest(indexName, typeof(TestModel5), 7); _client.Delete(request);     //1.x中有 2.x中需要安装插件 5.x中又回来了 _client.DeleteByQuery<TestModel5>( s =>s .Index(indexName) .Type("TestModel5") .Query(q =>q.Term(tm => tm.Field(fd => fd.State).Value(1))));

更新数据

 

更新所有字段

DocumentPath<VendorPriceInfo> deletePath=new DocumentPath<VendorPriceInfo>(2); Var response=client.Update(deletePath,(p)=>p.Doc(new VendorPriceInfo(){vendorName = "test2update..."})); //或 IUpdateRequest<VendorPriceInfo, VendorPriceInfo> request = new UpdateRequest<VendorPriceInfo, VendorPriceInfo>(deletePath) { Doc = new VendorPriceInfo() { priceID = 888, vendorName = "test4update........" } }; var response = client.Update<VendorPriceInfo, VendorPriceInfo>(request);  

更新部分字段

IUpdateRequest<VendorPriceInfo, VendorPriceInfoP> request = new UpdateRequest<VendorPriceInfo, VendorPriceInfoP>(deletePath) { Doc = new VendorPriceInfoP() { priceID = 888, vendorName = "test4update........" }   }; var response = client.Update(request);  

更新部分字段

IUpdateRequest<VendorPriceInfo, object> request = new UpdateRequest<VendorPriceInfo, object>(deletePath) { Doc = new { priceID = 888, vendorName = " test4update........" } }; var response = client.Update(request); //或 client.Update<VendorPriceInfo, object>(deletePath, upt => upt.Doc(new { vendorName = "ptptptptp" }));  

注:更新时根据唯一id更新

更新时使用本版号加锁机制

           //查询到版本号
            var result = _client.Search<TestModel5>( s => s.Index(indexName) .Query(q => q.Term(tm => tm.Field(fd=>fd.State).Value(1))).Size(1) .Version()//结果中包含版本号 ); foreach (var s in result.Hits) { Console.WriteLine(s.Id + " - " + s.Version); }   var path = new DocumentPath<TestModel5>(1); //更新时带上版本号 如果服务端版本号与传入的版本好相同才能更新成功 var response = _client.Update(path, (p) => p .Index(indexName) .Type(typeof(TestModel5)) .Version(2)//限制es中版本号为2时才能成功 .Doc(new TestModel5() { Name = "测测测" + DateTime.Now }) );

搜索

 

基本搜索

var result = _client.Search<TestModel5>( s => s .Explain() //参数可以提供查询的更多详情。 .FielddataFields(fs => fs //对指定字段进行分析 .Field(p => p.Name) .Field(p => p.Dic) ) .From(0) //跳过的数据个数 .Size(50) //返回数据个数 .Query(q => q.Term(p => p.State, 100) // 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型): && q.Term(p => p.Name.Suffix("temp"), "姓名") //用于自定义属性的查询 && q.Bool( //bool 查询 b => b //must should mushnot .Must(mt => mt //所有分句必须全部匹配,与 AND 相同 .TermRange(p => p.Field(f => f.State).GreaterThan("0").LessThan("1"))) //指定范围查找 .Should(sd => sd //至少有一个分句匹配,与 OR 相同 .Term(p => p.State, 32915), sd => sd.Terms(t => t.Field(fd => fd.State).Terms(new[] { 10, 20, 30 })), //多值 //|| //sd.Term(p => p.priceID, 1001) //|| //sd.Term(p => p.priceID, 1005) sd => sd.TermRange(tr => tr.GreaterThan("10").LessThan("12").Field(f => f.State)), //出入的时间必须指明时区 sd => sd.DateRange(tr => tr.GreaterThan(DateTime.Now.AddDays(-1)).LessThan(DateTime.Now).Field(f => f.CreateTime))   ) .MustNot(mn => mn//所有分句都必须不匹配,与 NOT 相同 .Term(p => p.State, 1001) , mn => mn.Bool( bb => bb.Must(mt => mt .Match(mc => mc.Field(fd => fd.Name).Query("至尊")) )) ) ) )//查询条件 

猜你喜欢

转载自blog.csdn.net/qq_18145031/article/details/79743903
今日推荐