当前位置: 首页 > news >正文

使用c#操作elasticsearch8

注意事项

若Es的客户端版本是8.x以下,建议用NEST或者Elasticsearch.Net,这两个包最高只支持7.x系列。

若Es的客户端是8.x以上,则推荐使用Elastic.Clients.Elasticsearch。

注意选择版本的时候最好和客户端版本保持一致。

1

2

创建项目

安装nuget包

创建两个项目,一个WebApi,一个类库项目,其中类库项目安装以下三个包

  • Elastic.Clients.Elasticsearch:版本和本地ES的版本保持一致即可。
  • Microsoft.Extensions.Configuration.Abstractions:8.0.0。
  • Microsoft.Extensions.DependencyInjection.Abstractions:8.0.2。
  • Microsoft.Extensions.Logging.Abstractions:8.0.3。
  • Microsoft.Extensions.Options.ConfigurationExtensions:8.0.0

3

Api项目引用类库项目。

4

类库模块
  1. 创建数据实体类Movie
public class Movie
{public int Id { get; set; }public string Name { get; set; }public int Year { get; set; }public string Country { get; set; }
}
  1. 创建配置信息实体类
 public class EsOptions{/// <summary>/// es集群连接/// </summary>public string[] ConnectionUrls { get; set; }/// <summary>/// es 用户名/// </summary>public string SecurityUserName { get; set; }/// <summary>/// es 密码/// </summary>public string SecurityPassword { get; set; }}
  1. 创建ESServiceExtension类文件,将配置节点绑定到实体,然后注册Es操作服务。
public static class ESServiceExtension
{public static IServiceCollection AddEsSetup(this IServiceCollection services, IConfiguration configuration){services.Configure<EsOptions>(configuration.GetSection(nameof(EsOptions)));services.AddSingleton<IESCurd, ESCurd>();return services;}
}
  1. 创建Es操作接口IESCurd
public interface IESCurd
{/// <summary>/// 根据文档id获取文档/// </summary>/// <typeparam name="Document"></typeparam>/// <param name="id">文档id</param>/// <param name="action"></param>/// <param name="cancellationToken"></param>/// <returns></returns>Task<GetResponse<Document>> GetByIdAsync<Document>(Id id, Action<GetRequestDescriptor<Document>> action, CancellationToken cancellationToken = default(CancellationToken));/// <summary>/// 搜索文档/// </summary>/// <typeparam name="Document"></typeparam>/// <param name="action"></param>/// <param name="cancellationToken"></param>/// <returns></returns>Task<SearchResponse<Document>> SearchAsync<Document>(Action<SearchRequestDescriptor<Document>> action, CancellationToken cancellationToken = default(CancellationToken));/// <summary>/// 创建文档/// </summary>/// <typeparam name="Document"></typeparam>/// <param name="document">文档对象</param>/// <param name="index">索引名称</param>/// <param name="cancellationToken"></param>/// <returns></returns>Task<IndexResponse> IndexAsync<Document>(Document document, IndexName index, CancellationToken cancellationToken = default(CancellationToken));/// <summary>/// 批量创建文档/// </summary>/// <typeparam name="Document"></typeparam>/// <param name="documents">文档对象集合</param>/// <param name="index">索引名称</param>/// <param name="cancellationToken"></param>/// <returns></returns>Task<BulkResponse> IndexManyAsync<Document>(IEnumerable<Document> documents, IndexName index, CancellationToken cancellationToken = default(CancellationToken)) where Document : class;/// <summary>/// 更新文档/// </summary>/// <typeparam name="Document"></typeparam>/// <typeparam name="PartialDocument"></typeparam>/// <param name="index">索引名称</param>/// <param name="id">文档id</param>/// <param name="configureRequest"></param>/// <param name="cancellationToken"></param>/// <returns></returns>Task<UpdateResponse<Document>> UpdateAsync<Document, PartialDocument>(IndexName index, Id id, Action<UpdateRequestDescriptor<Document, PartialDocument>> configureRequest, CancellationToken cancellationToken = default(CancellationToken));/// <summary>/// 删除文档/// </summary>/// <typeparam name="Document"></typeparam>/// <param name="index">索引名称</param>/// <param name="id">文档id</param>/// <param name="cancellationToken"></param>/// <returns></returns>Task<DeleteResponse> DeleteAsync<Document>(IndexName index, Id id, CancellationToken cancellationToken = default(CancellationToken));
}
  1. 创建Es操作具体实现类ESCurd
 public class ESCurd : IESCurd{private ElasticsearchClient client;private ILogger<ESCurd> logger;public ESCurd(IOptions<EsOptions> options, ILogger<ESCurd> logger){if (options.Value == null){logger.LogError("es配置参数为null");throw new ArgumentNullException(nameof(IOptions<EsOptions>));}ElasticsearchClientSettings settings = null;string[] connIpArray = options.Value.ConnectionUrls;string userName = options.Value.SecurityUserName;string passWord = options.Value.SecurityPassword;int length = connIpArray.Length;if (connIpArray.Length == 1){settings = new ElasticsearchClientSettings(new Uri(connIpArray[0])).ServerCertificateValidationCallback((sender, certificate, chain, errors) => true) //跳过SSL证书验证(仅开发环境使用).Authentication(new BasicAuthentication(userName, passWord)); //配置身份验证}else{Uri[] nodes = options.Value.ConnectionUrls.Select(x => new Uri(x)).ToArray();var pool = new StaticNodePool(nodes);settings = new ElasticsearchClientSettings(pool).ServerCertificateValidationCallback((sender, certificate, chain, errors) => true) //跳过SSL证书验证(仅开发环境使用).Authentication(new BasicAuthentication(userName, passWord));}client = new ElasticsearchClient(settings);}public async Task<DeleteResponse> DeleteAsync<Document>(IndexName index, Id id, CancellationToken cancellationToken){return await client.DeleteAsync(index, id, cancellationToken);}public async Task<GetResponse<Document>> GetByIdAsync<Document>(Id id, Action<GetRequestDescriptor<Document>> action, CancellationToken cancellationToken){return await client.GetAsync(id, action, cancellationToken);}public async Task<IndexResponse> IndexAsync<Document>(Document document, IndexName index, CancellationToken cancellationToken){return await client.IndexAsync(document, index, null, cancellationToken);}public async Task<BulkResponse> IndexManyAsync<Document>(IEnumerable<Document> documents, IndexName index, CancellationToken cancellationToken = default(CancellationToken)) where Document : class{return await client.IndexManyAsync(documents, index, cancellationToken);}public async Task<SearchResponse<Document>> SearchAsync<Document>(Action<SearchRequestDescriptor<Document>> action, CancellationToken cancellationToken){return await client.SearchAsync(action, cancellationToken);}public async Task<UpdateResponse<Document>> UpdateAsync<Document, PartialDocument>(IndexName index, Id id, Action<UpdateRequestDescriptor<Document, PartialDocument>> configureRequest, CancellationToken cancellationToken){// 创建更新请求描述符var descriptor = new UpdateRequestDescriptor<Document, PartialDocument>(index, id);// 应用外部配置(这里会包含 Doc 或 Script 等更新内容)configureRequest(descriptor);return await client.UpdateAsync<Document, PartialDocument>(descriptor, cancellationToken);}
Api模块
  1. 添加Es配置节点
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"AllowedHosts": "*","EsOptions": {//es集群连接"ConnectionUrls": [ "https://localhost:9200" ],//es 用户名"SecurityUserName": "elastic",//es 密码"SecurityPassword": "123456"}
}
  1. 配置swagger注释显示服务,调用类库的注册服务
using ElasticSearchService.Core;
using System.Reflection;namespace ElasticSearchService.Api
{public class Program{public static void Main(string[] args){var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen(options =>{options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo(){Title = "ElasticSearch Demo",Description = ".net8集成Es",Version = "v1"});string xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Assembly.GetExecutingAssembly().GetName().Name + ".xml");options.IncludeXmlComments(xmlPath, true);});builder.Services.AddEsSetup(builder.Configuration);var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI(options =>{options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");});}app.UseAuthorization();app.MapControllers();app.Run();}}
}
  1. 添加文档控制器
using Elastic.Clients.Elasticsearch;
using Elastic.Clients.Elasticsearch.Core.Search;
using ElasticSearchService.Core;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static System.Reflection.Metadata.BlobBuilder;namespace ElasticSearchService.Api.Controllers
{/// <summary>/// es文档/// </summary>[Route("api/[controller]")][ApiController]public class ESDocumentController : ControllerBase{private readonly IESCurd eSCurd;private readonly ILogger<ESDocumentController> logger;/// <summary>/// 构造函数/// </summary>/// <param name="eSCurd"></param>/// <param name="logger"></param>public ESDocumentController(IESCurd eSCurd, ILogger<ESDocumentController> logger){this.eSCurd = eSCurd;this.logger = logger;}/// <summary>/// 获取指定文档/// </summary>/// <param name="id">文档id</param>/// <returns></returns>[HttpGet("{id}")]public async Task<IActionResult> GetAsync([FromRoute] string id){var response = await eSCurd.GetByIdAsync<Movie>(id, action => action.Index(nameof(Movie).ToLower()));if (response.IsValidResponse){return Ok(response.Source);}return NotFound($"未查询到索引{nameof(Movie).ToLower()}");}/// <summary>/// 分页查询排序获取文档/// </summary>/// <param name="pageIndex">当前页</param>/// <param name="pageSize">每页条数</param>/// <param name="search">查询内容</param>/// <returns></returns>[HttpGet("Search")]public async Task<IActionResult> SearchAsync([FromQuery] int pageIndex, [FromQuery] int pageSize, [FromQuery] string? search){SearchResponse<Movie> response = await eSCurd.SearchAsync<Movie>(action =>{action.Indices(nameof(Movie).ToLower()).From((pageIndex - 1) * pageSize).Size(pageSize);if (!string.IsNullOrEmpty(search)){action.Query(q => q.Match(m => m.Field(f => f.Country).Query(search)));}else{action.Query(q => q.MatchAll());}action.Highlight(config =>config.Fields(f =>{f.Add(new Field("country"), new HighlightField(){PreTags = new[] { "<span style='color:red'>" },PostTags = new[] { "</span>" }});})).Sort(sort =>{sort.Field(s => s.Id).Doc(s =>{s.Order(SortOrder.Asc);});});});if (response.IsValidResponse){List<Movie?> list = response.Hits.Select(item => item.Source).ToList();//Movie movie = response.Hits.FirstOrDefault().Source;//var hit = response.Hits.FirstOrDefault().Highlight;return Ok(list);}return NotFound();}/// <summary>/// 更新文档/// </summary>/// <param name="id">文档id</param>/// <param name="movie">文档对象</param>/// <returns></returns>[HttpPut("{id}")]public async Task<IActionResult> UpdateAsync([FromRoute] string id, [FromBody] Movie movie){UpdateResponse<Movie> response = await eSCurd.UpdateAsync<Movie, Movie>(nameof(Movie).ToLower(), id, u => u.Doc(movie));if (response.IsValidResponse){return Ok("文档更新成功.");}return NotFound();}/// <summary>/// 创建文档/// </summary>/// <param name="movie">文档对象</param>/// <returns></returns>[HttpPost]public async Task<IActionResult> IndexAsync([FromBody] Movie movie){IndexResponse response = await eSCurd.IndexAsync<Movie>(movie, nameof(Movie).ToLower());if (response.IsValidResponse){return Ok($"文档创建成功,ID:{response.Id}.");}return BadRequest();}/// <summary>/// 批量创建文档/// </summary>/// <param name="movies">文档对象集合</param>/// <returns></returns>[HttpPost("bulkinsert")]public async Task<IActionResult> IndexManyAsync([FromBody] List<Movie> movies){BulkResponse response = await eSCurd.IndexManyAsync<Movie>(movies, nameof(Movie).ToLower());if (response.IsValidResponse){return Ok($"文档批量创建成功.");}return BadRequest();}/// <summary>/// 删除文档/// </summary>/// <param name="id">文档id</param>/// <returns></returns>[HttpDelete("{id}")]public async Task<ActionResult> DeleteAsync([FromRoute] string id){var response = await eSCurd.DeleteAsync<Movie>(nameof(Movie).ToLower(), id);if (response.IsValidResponse){return Ok("文档删除成功.");}return NotFound();}}
}
  1. 添加索引控制器
using Elastic.Clients.Elasticsearch;
using Elastic.Clients.Elasticsearch.Nodes;
using ElasticSearchService.Core;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;namespace ElasticSearchService.Api.Controllers
{/// <summary>/// es索引/// </summary>[Route("api/[controller]")][ApiController]public class ESIndexController : ControllerBase{private readonly IESCurd eSCurd;private readonly ILogger<ESIndexController> logger;/// <summary>/// 构造函数/// </summary>/// <param name="eSCurd"></param>/// <param name="logger"></param>public ESIndexController(IESCurd eSCurd, ILogger<ESIndexController> logger){this.eSCurd = eSCurd;this.logger = logger;}/// <summary>/// 创建索引/// </summary>/// <param name="indexName">索引名称</param>/// <returns></returns>[HttpPost]public async Task<IActionResult> CreateIndexAsync([FromBody] string indexName){var response = await eSCurd.CreateIndexAsync(indexName);if (response.IsValidResponse){return Ok($"索引创建成功,Index:{response.Index}.");}return BadRequest();}/// <summary>/// 删除索引/// </summary>/// <param name="indexName">索引名称</param>/// <returns></returns>[HttpDelete]public async Task<IActionResult> DeleteIndexAsync([FromBody] string indexName){var response = await eSCurd.DeleteIndexAsync(indexName);if (response.IsValidResponse){return Ok($"索引删除成功.");}return BadRequest();}}
}

效果预览

5

创建文档

6

7

批量创建文档

8

9

更新文档

10

26

删除文档

11

获取指定文档

12

24

分页获取文档数据

不带查询条件

13

14

23

15

带查询条件:按国家查询

16

17

注意:由于代码用的是match查询,查询的时候中文会被分词处理,所以如果输入“美国”,则查询的结果不仅仅只有美国,带“美”和带“国”的数据都会被查出来,如下图所示。

18

创建索引

19

20

删除索引

21

22

http://www.hskmm.com/?act=detail&tid=27635

相关文章:

  • CF45C Dancing Lessons 题解
  • APUE学习笔记之文件IO(三) - Invinc
  • note
  • 供应链优化技术助力应对疫情挑战
  • 搜索关键词 - 呓语
  • 阅读《构建之法》产生的问题
  • 每日反思
  • 每日反思(2025.10.09)
  • 软件工程学习日志2025.10.9
  • 骄傲 雨伞边缘处的暗槽 从最原初裂缝开凿 被碰触和温暖击倒 停止思考
  • 1.1.1.2 直接融资vs间接融资的区别
  • 柳高国庆小小说创作比赛的构思和成文(未完成)
  • 骄傲 孔雀羽翎上的暗槽 从最肮脏裂缝开凿 被爱意和现实击倒 停止创造
  • 10.9 CSP-S模拟28 改题记录
  • 所以相信我初登场 不会让任何人失望 无论地位不管成败 全都逃不出神的覆掌
  • 被彼此笼罩 任歌声将我们缠绕 立下誓言后再自嘲 重复仲夏夜的舞蹈 吞下这毒药
  • 朝圣显像 不及那人将门扉轻轻叩响 欢迎来到我的城市 嗅玫瑰绽放
  • Git克隆项目运行指南
  • webpack library - 指南
  • 2025.10.9 月考游寄 - Amy
  • 被彼此笼罩 任回忆将我们缠绕 狂欢者戴上了镣铐 得益者撕裂了嘴角 吞下这毒药
  • QGIS导出TIF栅格图层
  • 七层协议
  • 20251009
  • 单调栈
  • 各种B站客户端
  • 10.9正式恢复
  • CSP-S模拟27
  • 模型训练技巧 - -一叶知秋
  • 20232324 2025-2026-1 《网络与系统攻防技术》实验一实验报告