.netcore 简单使用ElasticSearch(7.6)
最近在捣鼓学习了下ElasticSearch,在此记录下使用.netcore操作elastic search 的实现(简单的封装,使用)。需要注意的是不同版本的Elastic Search差异可能较大,需要对应版本去封装操作,例如6.x版本的支持1个index下多个Type,而7.x已经开始去掉了type概念,而且查询等操作中必须先指明indexname,否则报错。
项目需要添加Elasticsearch.Net和Nest
相关文档地址
Elasticsearch文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
Elasticsearch.Net和Nest官方文档:https://www.elastic.co/guide/en/elasticsearch/client/net-api/7.x/index.html
1、封装ElasticClient提供者
1)创建ElasticSearch配置类
1 2 3 4 5 6 |
public class EsConfig : IOptions<EsConfig> { public List<string> Urls { get; set; } public EsConfig Value => this; } |
2)创建ElasticSearch提供者接口以及类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
/// <summary> /// ElasticClient 提供者接口 /// </summary> public interface IEsClientProvider { /// <summary> /// 获取ElasticClient /// </summary> /// <returns></returns> ElasticClient GetClient(); /// <summary> /// 指定index获取ElasticClient /// </summary> /// <param name="indexName"></param> /// <returns></returns> ElasticClient GetClient(string indexName); } /// <summary> /// ElasticClient提供者 /// </summary> public class EsClientProvider : IEsClientProvider { private readonly IOptions<EsConfig> _EsConfig; public EsClientProvider(IOptions<EsConfig> esConfig) { _EsConfig = esConfig; } /// <summary> /// 获取elastic client /// </summary> /// <returns></returns> public ElasticClient GetClient() { if (_EsConfig == null || _EsConfig.Value == null || _EsConfig.Value.Urls == null || _EsConfig.Value.Urls.Count < 1) { throw new Exception("urls can not be null"); } return GetClient(_EsConfig.Value.Urls.ToArray(), ""); } /// <summary> /// 指定index获取ElasticClient /// </summary> /// <param name="indexName"></param> /// <returns></returns> public ElasticClient GetClient(string indexName) { if (_EsConfig == null || _EsConfig.Value == null || _EsConfig.Value.Urls == null || _EsConfig.Value.Urls.Count < 1) { throw new Exception("urls can not be null"); } return GetClient(_EsConfig.Value.Urls.ToArray(), indexName); } /// <summary> /// 根据url获取ElasticClient /// </summary> /// <param name="url"></param> /// <param name="defaultIndex"></param> /// <returns></returns> private ElasticClient GetClient(string url, string defaultIndex = "") { if (string.IsNullOrWhiteSpace(url)) { throw new Exception("es 地址不可为空"); } var uri = new Uri(url); var connectionSetting = new ConnectionSettings(uri); if (!string.IsNullOrWhiteSpace(url)) { connectionSetting.DefaultIndex(defaultIndex); } return new ElasticClient(connectionSetting); } /// <summary> /// 根据urls获取ElasticClient /// </summary> /// <param name="urls"></param> /// <param name="defaultIndex"></param> /// <returns></returns> private ElasticClient GetClient(string[] urls, string defaultIndex = "") { if (urls == null || urls.Length < 1) { throw new Exception("urls can not be null"); } var uris = urls.Select(p => new Uri(p)).ToArray(); var connectionPool = new SniffingConnectionPool(uris); var connectionSetting = new ConnectionSettings(connectionPool); if (!string.IsNullOrWhiteSpace(defaultIndex)) { connectionSetting.DefaultIndex(defaultIndex); } return new ElasticClient(connectionSetting); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/// <summary> /// 根据urls获取ElasticClient /// </summary> /// <param name="urls"></param> /// <param name="defaultIndex"></param> /// <returns></returns> public ElasticClient GetClient(string[] urls, string defaultIndex = "") { if (urls == null || urls.Length < 1) { throw new Exception("urls can not be null"); } var uris = urls.Select(p => new Uri(p)).ToArray(); var connectionPool = new SniffingConnectionPool(uris); var connectionSetting = new ConnectionSettings(connectionPool); if (!string.IsNullOrWhiteSpace(defaultIndex)) { connectionSetting.DefaultIndex(defaultIndex); } //connectionSetting.BasicAuthentication("", ""); //设置账号密码 return new ElasticClient(connectionSetting); } |
2、封装操作ElasticSearch实现
1)、扩展ElasticClient类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/// <summary> /// ElasticClient 扩展类 /// </summary> public static class ElasticClientExtension { /// <summary> /// 创建索引 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="elasticClient"></param> /// <param name="indexName"></param> /// <param name="numberOfShards"></param> /// <param name="numberOfReplicas"></param> /// <returns></returns> public static bool CreateIndex<T>(this ElasticClient elasticClient, string indexName = "", int numberOfShards = 5, int numberOfReplicas = 1) where T : class { if (string.IsNullOrWhiteSpace(indexName)) { indexName = typeof(T).Name; } if (elasticClient.Indices.Exists(indexName).Exists) { return false; } else { var indexState = new IndexState() { Settings = new IndexSettings() { NumberOfReplicas = numberOfReplicas, NumberOfShards = numberOfShards, }, }; var response = elasticClient.Indices.Create(indexName, p => p.InitializeUsing(indexState).Map<T>(p => p.AutoMap())); return response.Acknowledged; } } } |
2)、创建ElasticSearch操作基类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/// <summary> /// 接口限定 /// </summary> public interface IBaseEsContext { } /// <summary> /// es操作基类 /// </summary> /// <typeparam name="T"></typeparam> public abstract class BaseEsContext<T> : IBaseEsContext where T : class { protected IEsClientProvider _EsClientProvider; public abstract string IndexName { get; } public BaseEsContext(IEsClientProvider provider) { _EsClientProvider = provider; } /// <summary> /// 批量更新 /// </summary> /// <param name="tList"></param> /// <returns></returns> public bool InsertMany(List<T> tList) { var client = _EsClientProvider.GetClient(IndexName); if (!client.Indices.Exists(IndexName).Exists) { client.CreateIndex<T>(IndexName); } var response = client.IndexMany(tList); //var response = client.Bulk(p=>p.Index(IndexName).IndexMany(tList)); return response.IsValid; } /// <summary> /// 获取总数 /// </summary> /// <returns></returns> public long GetTotalCount() { var client = _EsClientProvider.GetClient(IndexName); var search = new SearchDescriptor<T>().MatchAll(); //指定查询字段 .Source(p => p.Includes(x => x.Field("Id"))); var response = client.Search<T>(search); return response.Total; } /// <summary> /// 根据Id删除数据 /// </summary> /// <returns></returns> public bool DeleteById(string id) { var client = _EsClientProvider.GetClient(IndexName); var response = client.Delete<T>(id); return response.IsValid; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/// <summary> /// 地址操作类 /// </summary> public class AddressContext : BaseEsContext<Address> { /// <summary> /// 索引名称 /// </summary> public override string IndexName => "address"; public AddressContext(IEsClientProvider provider) : base(provider) { } /// <summary> /// 获取地址 /// </summary> /// <param name="province"></param> /// <param name="pageIndex"></param> /// <param name="pageSize"></param> /// <returns></returns> public List<Address> GetAddresses(string province, int pageIndex, int pageSize) { var client = _EsClientProvider.GetClient(IndexName); var musts = new List<Func<QueryContainerDescriptor<Address>, QueryContainer>>(); musts.Add(p => p.Term(m => m.Field(x=>x.Pronvince).Value(province))); var search = new SearchDescriptor<Address>(); // search = search.Index(IndexName).Query(p => p.Bool(m => m.Must(musts))).From((pageIndex - 1) * pageSize).Take(pageSize); search =search.Query(p => p.Bool(m => m.Must(musts))).From((pageIndex - 1) * pageSize).Take(pageSize); var response = client.Search<Address>(search); return response.Documents.ToList(); } /// <summary> /// 获取所有地址 /// </summary> /// <returns></returns> public List<Address> GetAllAddresses() { var client = _EsClientProvider.GetClient(IndexName); var searchDescriptor = new SearchDescriptor<Address>(); // searchDescriptor = searchDescriptor.Index(IndexName).Query(p => p.MatchAll()); searchDescriptor = searchDescriptor.Query(p => p.MatchAll()); var response = client.Search<Address>(searchDescriptor); return response.Documents.ToList(); } /// <summary> /// 删除指定城市的数据 /// </summary> /// <param name="city"></param> /// <returns></returns> public bool DeleteByQuery(string city) { var client = _EsClientProvider.GetClient(IndexName); var musts = new List<Func<QueryContainerDescriptor<Address>, QueryContainer>>(); musts.Add(p=>p.Term(m=>m.Field(f=>f.City).Value(city))); var search = new DeleteByQueryDescriptor<Address>().Index(IndexName); search = search.Query(p => p.Bool(m => m.Must(musts))); var response = client.DeleteByQuery<Address>(p=>search); return response.IsValid; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[ElasticsearchType(IdProperty = "Id")] public class Address { [Keyword] public string Id { get; set; } [Keyword] public string Country { get; set; } [Keyword] public string City { get; set; } [Keyword] public string Pronvince { get; set; } [Keyword] public string Area { get; set; } [Text] public string Address1 { get; set; } } |
3、项目中注入和使用ElasticSearch
1)、配置文件
1 2 3 |
"EsConfig": { "ConnectionStrings": [ "http://127.0.0.1:9200/" ] } |
2)、注入ElasticSearch
1 2 3 4 5 6 7 8 9 10 11 12 13 |
services.Configure<EsConfig>(options => { options.Urls = Configuration.GetSection("EsConfig:ConnectionStrings").GetChildren().ToList().Select(p => p.Value).ToList(); }); services.AddSingleton<IEsClientProvider, EsClientProvider>(); var types = Assembly.Load("John.DotNetCoreStudy.EsCommon").GetTypes().Where(p => !p.IsAbstract && (p.GetInterfaces() .Any(i => i == typeof(IBaseEsContext)))).ToList(); types.ForEach(p => services.AddTransient(p) ); |
3)、Controller类中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
[Route("api/[controller]")] [ApiController] public class AddressController : ControllerBase { private AddressContext _AddressContext; public AddressController(AddressContext context) { _AddressContext = context; } /// <summary> /// 新增或者修改 /// </summary> /// <param name="address"></param> [HttpPost("添加地址")] public void AddAddress(List<Address> addressList) { if (addressList == null || addressList.Count < 1) { return; } _AddressContext.InsertMany(addressList); } /// <summary> /// 删除地址 /// </summary> /// <param name="id"></param> [HttpPost("deleteAddress")] public void DeleteAdress(string id) { _AddressContext.DeleteById(id); } /// <summary> /// 获取所有与地址 /// </summary> /// <returns></returns> [HttpGet("getAllAddress")] public List<Address> GetAllAddress() { return _AddressContext.GetAllAddresses(); } /// <summary> /// 获取地址总数 /// </summary> /// <returns></returns> [HttpGet("getAddressTotalCount")] public long GetAddressTotalCount() { return _AddressContext.GetTotalCount(); } /// <summary> /// 分页获取(可以进一步封装查询条件) /// </summary> /// <param name="province"></param> /// <param name="pageIndex"></param> /// <param name="pageSize"></param> /// <returns></returns> [HttpPost("getAddressByProvince")] public List<Address> GetAddressByProvince(string province,int pageIndex,int pageSize) { return _AddressContext.GetAddresses(province,pageIndex,pageSize); } } |
-------------------------------------
以上当然es还有很多操作的,聚合查询、不同条件的查询(范围查询、匹配查询等等)、分词等。具体可以去查看其官方文档对应实现!