大家好,我是Edison。
上一篇:Logstash数据采集
写在开头
有了前面10篇的基础,我们大概清楚了ES的基本概念和使用(主要是查询),这也是我们作为Developer应该了解的范畴,而至于更深入的聚合分析、运维管理就不在本系列的范畴中。有童鞋说,讲讲如何在.NET应用中集成和使用ES吧,额,这个其实网上也有很多教程了。不过你既然提了,那还是得安排上。
在.NET应用中集成ES一般涉及两个方面:
(1)将ES当存储用,类似于MongoDB,做文档的增删查改,这一类操作偏CRUD。
(2)对ES中的数据做查询分析,聚合统计、分组等等,这一类操作偏查询分析。
针对这两类操作,我们今天先来搞定CRUD!
准备工作
创建一个Web API应用程序,这里我选择的是.NET 6版本。
项目结构如下图所示:
其中,我们对Elastic的集成主要放在了Infrastructure目录中,里面存放了我们定义的Repository进而帮助我们在Controller中使用其提供的持久化能力。
在appsetting中我们定义了如下配置指明Elastic的相关信息(URL地址 和 默认索引):
{
......
"Elastic": {
"ServerUrl": "http://edt-elastic:9200",
"DefaultIndex": "app-logs"
}
}
定义模型
我们这里定义一个Model,假设叫AppLog,来模拟日志文档的CRUD到ES:
public class AppLog : ElasticModelBase
{
public string LogLevel { get; set; } = "Info";
public string Message { get; set; } = string.Empty;
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.Now;
public AppLog()
{
this.Id = Guid.NewGuid().ToString();
}
public AppLog(string id)
{
this.Id = id;
}
}
public class ElasticModelBase
{
public virtual string Id { get; set; }
}
定义ElasticProxy
我们知道,.NET应用要操作Elastic得使用Elastic的.NET客户端,因此按照国际惯例我们对其进行一个小封装,以便于可以在Repository中使用。
对于ES 7.x版本的集群,推荐使用NEST这个客户端包(目前已停止更新):
dotnet add package NEST
对于ES 8.x及以上版本的集群,则推荐使用Elastic.Clients.Elasticsearch:
dotnet add package Elastic.Clients.Elasticsearch
这里因为我自己搭的实验ES集群环境是7.x版本,所以我使用的实NEST,不过操作都是类似的。
在Infrastructure目录下,定义一个ElasticProxy用于获取Elastic的.NET客户端:
public interface IElasticProxy
{
IElasticClient GetClient(string indexName = null);
}
public class ElasticProxy : IElasticProxy
{
private readonly string ElasticServerUrl;
private readonly string DefaultIndexName;
public ElasticProxy(IConfiguration configuration)
{
ElasticServerUrl = configuration["Elastic:ServerUrl"] ?? throw new ArgumentNullException();
DefaultIndexName = configuration["Elastic:DefaultIndex"] ?? throw new ArgumentNullException();
}
public IElasticClient GetClient(string indexName = null)
{
var settings = new ConnectionSettings(new Uri(ElasticServerUrl))
.DefaultIndex(indexName ?? DefaultIndexName);
return new ElasticClient(settings);
}
}
定义ElasticRepository基类
为了方便后续定义具体的Repository,我们这里先定义一个ElasticRepository的基类,帮我们把CRUD操作做一个基础的实现。
public interface IElasticRepositoryBase<T> where T : ElasticModelBase
{
Task AddAsync(T item);
Task UpdateAsync(T item);
Task DeleteAsync(string id);
Task<Tuple<int, IList<T>>> QueryAsync(int page, int limit);
}
public abstract class ElasticRepositoryBase<T> : IElasticRepositoryBase<T> where T : ElasticModelBase
{
private readonly IElasticProxy _elasticProxy;
public ElasticRepositoryBase(IElasticProxy elasticProxy)
{
_elasticProxy = elasticProxy;
}
protected abstract string IndexName { get; }
protected IElasticClient Client => _elasticProxy.GetClient(IndexName);
public virtual async Task AddAsync(T item)
{
await this.Client.IndexAsync(item, x => x.Index(this.IndexName));
}
public virtual async Task DeleteAsync(string id)
{
await this.Client.DeleteAsync<T>(id, x => x.Index(this.IndexName));
}
public virtual async Task UpdateAsync(T item)
{
await this.Client.UpdateAsync<T>(item.Id, x => x.Index(this.IndexName).Doc(item));
}
public virtual async Task<Tuple<int, IList<T>>> QueryAsync(int page, int limit)
{
var query = await this.Client.SearchAsync<T>(x => x.Index(this.IndexName)
.From((page -1) * limit)
.Size(limit));
return new Tuple<int, IList<T>>(Convert.ToInt32(query.Total), query.Documents.ToList());
}
}
有了上面的基类,我们再去实现具体的Repository就方便的多啦。
实现AppLogRepository
下面我们可以很方便的实现一个AppLogRepository啦,是不是很方便!
public class AppLogRepository : ElasticRepositoryBase<AppLog>, IAppLogRepository
{
public AppLogRepository(IElasticProxy elasticProxy) : base(elasticProxy)
{
}
protected override string IndexName => "app-logs";
}
定义依赖注入
下面我们把要用到的ElasticProxy和Repository注入到ServiceCollection中,后面Controller就可以用了!这里我们在Infrastructure中实现一个扩展方法,便于在Program.cs中使用。
public static class InfraServiceExtensions
{
public static void AddApplicationInfrastructure(this IServiceCollection services)
{
services.AddSingleton<IElasticProxy, ElasticProxy>();
services.AddSingleton<IProductRepository, ProductRepository>();
services.AddSingleton<IAppLogRepository, AppLogRepository>();
}
}
然后在Program.cs中使用这个扩展方法:
......
// Add infra services / repositories
builder.Services.AddApplicationInfrastructure();
实现AppLogController
下面我们就可以快速实现一个Controller来调用Repository实现ES的CRUD操作啦:
[ApiController]
[Route("[controller]")]
public class AppLogController : ControllerBase
{
private readonly IAppLogRepository _appLogRepository;
public AppLogController(IAppLogRepository appLogRepository)
{
_appLogRepository = appLogRepository;
}
[HttpGet]
public async Task<IActionResult> QueryAsync(int page = 1, int limit = 10)
{
var result = await _appLogRepository.QueryAsync(page, limit);
return Ok(new
{
total = result.Item1,
items = result.Item2
});
}
[HttpPost]
public async Task<IActionResult> AddAsync([FromBody] AppLog log)
{
await _appLogRepository.AddAsync(log);
return Ok("Success");
}
[HttpPut]
public async Task<IActionResult> UpdateAsync([FromBody] AppLog log)
{
await _appLogRepository.UpdateAsync(log);
return Ok("Success");
}
[HttpDelete]
public async Task<IActionResult> DeleteAsync([Required] string id)
{
await _appLogRepository.DeleteAsync(id);
return Ok("Success");
}
}
快速测试
下面我们就可以打开Swagger来做一个测试啦:
通过Post方式创建一个applog,然后我们通过Get方式查询一下结果如下:
这时我们还可以通过在ES中通过Query DSL来验证一下:
GET app-logs/_search
查询结果如下图所示:
至于Put和Delete就留给你去验证吧。
小结
本篇,我们了解了如何在ASP.NET 6应用中集成ElasticSearch,并通过示例了解了如何做CRUD操作,并通过一定的封装提高了复用性。
下一篇我们了解下如何在ASP.NET 6应用对ES中的数据进行查询 和 聚合。
源码
Github:https://github.com/Coder-EdisonZhou/ElasticSamples
参考资料
博客园,包子wxl,《ElasticSearch使用系列-.NET6对接ES》:https://www.cnblogs.com/wei325/p/15881650.html
CSDN,阿星Plus,《.NET Core下使用ES》:
https://blog.csdn.net/meowv/article/details/108613494
CSDN,风神.NET,《如何在ASP.NET Core中集成ES》:https://blog.csdn.net/WuLex/article/details/123354106
极客时间,阮一鸣,《ElasticSearch核心技术与实战》
年终总结:Edison的2023年终总结
数字化转型:我在传统企业做数字化转型
C#刷题:C#刷剑指Offer算法题系列文章目录
.NET面试:.NET开发面试知识体系
.NET大会:2020年中国.NET开发者大会PDF资料