.Net Core中使用NEST简单操作Elasticsearch

x33g5p2x  于9个月前 转载在 .NET  
字(5.7k)|赞(0)|评价(0)|浏览(400)

C# 中访问 Elasticsearch 主要通过两个包 NESTElasticsearch.NetNEST 用高级语法糖封装了 Elasticsearch.Net 可以通过类 Linq 的方式进行操作,而 Elasticsearch.Net 相比之下更为原始直接非常自由。

注意: ES8.X 以上的版本有新的包 Elastic.Clients.Elasticsearc 支持。

此处使用 NEST ,我们通过 Nuget 安装,如下图:

1、准备结构

准备以下实体

  1. public classCompany
  2. {
  3. public string Id { get; set; }
  4. public string Name { get; set; }
  5. public string Description { get; set; }
  6. public User User { get; set; }
  7. }
  8. public classUser
  9. {
  10. public string Name { get; set; }
  11. public int Gender { get; set; }
  12. }

2、连接ES

如果是单机连接如下代码,可以直接在 Uri 上指定账号密码,也可以使用 ConnectionSettingsBasicAuthentication 来配置账号密码:

  1. var singleNode = new Uri("http://elastic:123456@localhost:9200");
  2. var connSettings =new ConnectionSettings(singleNode);
  3.   //connSettings.BasicAuthentication("elastic", "123456");
  4. var esClient = new ElasticClient(connSettings);

如果是多个节点集群则如下代码:

  1. var nodes =new Uri[]
  2. {
  3. new Uri("http://esNode1:9200"),
  4. new Uri("http://esNode2:9200"),
  5. new Uri("http://esNode3:9200")
  6. };
  7. var pool =new StaticConnectionPool(nodes);
  8. var settings =new ConnectionSettings(pool);
  9. var client = new ElasticClient(settings);

3、创建索引

索引名称必须符合规则否则创建会失败,比如索引只能小写,具体代码如下:

  1. var indexName = "my_index1";//索引名称
  2. var res = await esClient.Indices.CreateAsync(indexName, o => o.Map(g => g.AutoMap<Company>()));//映射结构

也可以在向索引插入数据的时候自动判断是否存在索引,不存在会自动创建。索引结构字段映射一但创建就无法修改,可以通过新建索引然后转移数据的方式修改索引结构,但是可以往里面新增字段映射,比如修改了实体结构新的字段将会被映射。

4、插入数据

使用 IndexDocumentAsync 方法插入单条数据需要在 ConnectionSettingsDefaultIndex 方法设置默认索引。使用 IndexAsync 插入单条数据时需要选择指定索引,如下:

  1. var singleNode = new Uri("http://localhost:9200");
  2. var connSettings = newConnectionSettings(singleNode);
  3. connSettings.BasicAuthentication("elastic", "123456");
  4. var esClient = new ElasticClient(connSettings.DefaultIndex("my_index1"));
  5. var indexName = "my_index1";
  6. var company = newCompany()
  7. {
  8. Name = "超级公司bulk",
  9. Description = "超级描述bulk",
  10. };
  11. var res1 = awaitesClient.IndexDocumentAsync(company);
  12. var res2 = await esClient.IndexAsync(company, g => g.Index(indexName))

如果需要批量插入需要用 BulkDescriptor 对象包裹,然后使用 BulkAsync 方法插入,或者不要包裹直接用 IndexManyAsync 方法插入,具体如下:

  1. var company = newCompany()
  2. {Name = "超级公司bulk",
  3. Description = "超级描述bulk"});
  4. BulkDescriptor descriptor = newBulkDescriptor();
  5. descriptor.Index<Company>(op =>op.Document(company).Index(indexName));
  6. var res = awaitesClient.BulkAsync(descriptor);
  7. //var list = new List<Company>();
  8. //list.Add(company);
  9. //var res = await esClient.IndexManyAsync(list, indexName);

如果实体有 Id 则会使用 Id 的值做为 _id 的索引文档唯一值,或者可以通过手动指定如 await esClient.IndexAsync(company, g => g.Index(indexName).Id(company.Id)) ,如果id相同执行插入操作则为更新不会重复插入。在新增后是会返回id等信息可以加以利用。

5、删除数据

删除指定单条数据需要知道数据的 id ,如下两种方式:

  1. DocumentPath<Company> deletePath = new DocumentPath<Company>(Guid.Empty);
  2. var delRes = await esClient.DeleteAsync(deletePath, g =>g.Index(indexName));
  3. //或者
  4. IDeleteRequest request = new DeleteRequest(indexName, "1231");
  5. var delRes = await esClient.DeleteAsync(request);

多条删除使用 DeleteByQueryAsync 方法进行匹配删除,下面两种方式等价,删除 Description 字段模糊查询有 描述 的数据(最多10条):

  1. var req = new DeleteByQueryRequest<Company>(indexName)
  2. {
  3. MaximumDocuments = 10,//一次最多删几条
  4. Query = newMatchQuery()
  5. {
  6. Field = "description",
  7. Query = "描述"}
  8. };
  9. var result = awaitesClient.DeleteByQueryAsync(req);
  10. //等价于
  11. var result = await esClient.DeleteByQueryAsync<Company>(dq =>dq.MaximumDocuments(10).Query(
  12. q => q.Match(tr => tr.Field(fd => fd.Description).Query("描述"))).Index(indexName)
  13. );

** 6、更新数据**

除了上述插入数据时自动根据 id 进行更新外还有以下的主动更新。

根据 id 更新单条数据以下代码等价,可以更新部分字段值,但是 _id 是确定就不会更改的虽然对应的 Id 字段已被修改:

  1. DocumentPath<Company> deletePath = new DocumentPath<Company>("1231");
  2. var res = await esClient.UpdateAsync(deletePath ,(p) =>p.Doc(company).Index(indexName));
  3. //等价于
  4. IUpdateRequest<Company, Company> request = new UpdateRequest<Company, Company>(indexName, "1231")
  5. {
  6. Doc = newCompany()
  7. {
  8. Id = "888",
  9. Description = "11111",
  10. }
  11. };
  12. var res = await esClient.UpdateAsync(request);

如果有多个 id 更新多条数据可以用如下方法:

  1. var res = esClient.Bulk(b => b.UpdateMany(new List<Company>() { newCompany()
  2. {
  3. Id="1231",
  4. } }, (b, u) => b.Id(u.Id).Index(indexName).Doc(new Company { Name = "我无语了" })));

通过条件批量更新如下,

  1. var req = new UpdateByQueryRequest<Company>(indexName)
  2. {
  3. MaximumDocuments = 10,//一次最多更新几条
  4. Query = newMatchQuery()
  5. {
  6. Field = "description",
  7. Query = "66",
  8. },
  9. Script = newScriptDescriptor()
  10. .Source($"ctx._source.description = params.description;")
  11. .Params(new Dictionary<string, object>{
  12. { "description","小时了123123123"}
  13. }),
  14. Refresh = true};
  15. var result = await esClient.UpdateByQueryAsync(req);

** 7、数据查询**

上文中的更新等都用到了查询过滤,此处就用网上的这个例子吧:

  1. var result = client.Search<VendorPriceInfo>(
  2. s =>s
  3. .Explain() //参数可以提供查询的更多详情。
  4. .FielddataFields(fs => fs //对指定字段进行分析
  5. .Field(p =>p.vendorFullName)
  6. .Field(p =>p.cbName)
  7. )
  8. .From(0) //跳过的数据个数
  9. .Size(50) //返回数据个数
  10. .Query(q =>q.Term(p => p.vendorID, 100) //主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型):
  11. &&q.Term(p => p.vendorName.Suffix("temp"), "姓名") //用于自定义属性的查询 (定义方法查看MappingDemo)
  12. &&q.Bool( //bool 查询
  13. b =>b
  14. .Must(mt => mt //所有分句必须全部匹配,与 AND 相同
  15. .TermRange(p => p.Field(f => f.priceID).GreaterThan("0").LessThan("1"))) //指定范围查找
  16. .Should(sd => sd //至少有一个分句匹配,与 OR 相同
  17. .Term(p => p.priceID, 32915),
  18. sd => sd.Terms(t => t.Field(fd => fd.priceID).Terms(new[] {10, 20, 30})),//多值
  19. //||
  20. //sd.Term(p => p.priceID, 1001)
  21. //||
  22. //sd.Term(p => p.priceID, 1005)
  23. sd => sd.TermRange(tr => tr.GreaterThan("10").LessThan("12").Field(f =>f.vendorPrice))
  24. )
  25. .MustNot(mn => mn//所有分句都必须不匹配,与 NOT 相同
  26. .Term(p => p.priceID, 1001)
  27. ,
  28. mn =>mn.Bool(
  29. bb=>bb.Must(mt=>mt
  30. .Match(mc=>mc.Field(fd=>fd.carName).Query("至尊"))
  31. ))
  32. )
  33. )
  34. )//查询条件
  35. .Sort(st => st.Ascending(asc => asc.vendorPrice))//排序
  36. .Source(sc => sc.Include(ic =>ic
  37. .Fields(
  38. fd =>fd.vendorName,
  39. fd =>fd.vendorID,
  40. fd =>fd.priceID,
  41. fd => fd.vendorPrice))) //返回特定的字段
  42. );

相关文章

最新文章

更多