C# Elasticsearch帮助类
ElasticsearchConfig
/// <summary> /// ES 连接配置 /// </summary> public class ElasticsearchConfig { /// <summary> /// 节点列表 /// </summary> public IEnumerable<ElasticsearchNode> Nodes { get; set; } /// <summary> /// 连接池类型 /// </summary> public ElasticsearchConnectionPoolType PoolType { get; set; } = ElasticsearchConnectionPoolType.Static; /// <summary> /// 用户名 /// </summary> public string UserName { get; set; } /// <summary> /// 密码 /// </summary> public string Password { get; set; } /// <summary> /// 显示调试信息 /// </summary> public bool DisableDebugInfo { get; set; } = true; /// <summary> /// 抛出异常。默认false,错误信息在每个操作的response中 /// </summary> public bool ThrowExceptions { get; set; } = false; /// <summary> /// 是否禁用Ping。禁用ping 第一次使用节点或使用被标记死亡的节点进行ping /// </summary> public bool DisablePing { get; set; } = true; }
ElasticsearchConfigProvider
/// <summary> /// Elasticsearch 配置提供程序 /// </summary> public class ElasticsearchConfigProvider : IElasticsearchConfigProvider { /// <summary> /// 配置 /// </summary> private readonly ElasticsearchConfig _config; /// <summary> /// 初始化一个<see cref="ElasticsearchConfigProvider"/>类型的实例 /// </summary> /// <param name="config">Elasticsearch 连接配置</param> public ElasticsearchConfigProvider(ElasticsearchConfig config) { _config = config; } /// <summary> /// 获取配置 /// </summary> /// <returns></returns> public Task<ElasticsearchConfig> GetConfigAsync() { return Task.FromResult(_config); } }
ElasticsearchConnectionPoolType
/// <summary> /// ES 连接池类型。 /// 支持ping-说明能够发现节点的状态; /// 支持嗅探-说明能够发现新的节点 /// </summary> public enum ElasticsearchConnectionPoolType { /// <summary> /// 静态连接池。推荐使用,应用于已知集群,请求时随机请求各个正常节点,支持ping,不支持嗅探 /// </summary> Static, /// <summary> /// 单节点连接池 /// </summary> SingleNode, /// <summary> /// 嗅探连接池。可动态嗅探集群,随机请求,支持嗅探、ping /// </summary> Sniffing, /// <summary> /// 固定连接池。选择一个可用节点作为请求主节点,支持ping,不支持嗅探 /// </summary> Sticky, /// <summary> /// 固定嗅探连接池。选择一个可用节点作为请求主节点,支持ping,支持嗅探 /// </summary> StickySniffing }
ElasticsearchNode
/// <summary> /// Elasticsearch 节点 /// </summary> public class ElasticsearchNode { /// <summary> /// 主机 /// </summary> public string Host { get; set; } /// <summary> /// 端口号 /// </summary> public uint Port { get; set; } /// <summary> /// 输出字符串 /// </summary> /// <returns></returns> public override string ToString() { var port = Port == 0 ? "" : $":{Port}"; var result = $"{Host}{port}".ToLowerInvariant(); return result.IndexOf("http", StringComparison.OrdinalIgnoreCase) > -1 ? result : $"http://{result}"; } }
IElasticsearchConfigProvider
public interface IElasticsearchConfigProvider { /// <summary> /// 获取配置 /// </summary> /// <returns></returns> Task<ElasticsearchConfig> GetConfigAsync(); }
ElasticClientExtensions
/// <summary> /// ES客户端(<see cref="IElasticClient"/>) 扩展 /// </summary> internal static class ElasticClientExtensions { /// <summary> /// 初始化索引映射 /// </summary> /// <param name="client">ES客户端</param> /// <param name="indexName">索引名</param> public static async Task InitializeIndexMapAsync(this IElasticClient client, string indexName) { var newName = indexName + DateTime.Now.Ticks; var result = await client.CreateIndexAsync(newName, t => t.Index(newName).Settings(x => x.NumberOfShards(1).NumberOfReplicas(1).Setting("max_result_window", int.MaxValue))); if (result.Acknowledged) { await client.AliasAsync(x => x.Add(o => o.Index(newName).Alias(indexName))); return; } throw new ElasticsearchException($"创建索引 {indexName} 失败:{result.ServerError.Error.Reason}"); } /// <summary> /// 初始化索引映射 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="client">ES客户端</param> /// <param name="indexName">索引名</param> public static async Task InitializeIndexMapAsync<T>(this IElasticClient client, string indexName) where T : class { var newName = indexName + DateTime.Now.Ticks; var result = await client.CreateIndexAsync(newName, t => t.Index(newName) .Settings(o => o.NumberOfShards(1).NumberOfReplicas(1) .Setting("max_result_window", int.MaxValue)) .Mappings(m => m.Map<T>(mm => mm.AutoMap()))); if (result.Acknowledged) { await client.AliasAsync(x => x.Add(o => o.Index(newName).Alias(indexName))); return; } throw new ElasticsearchException($"创建索引 {indexName} 失败:{result.ServerError.Error.Reason}"); } /// <summary> /// 初始化索引映射 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="client">ES客户端</param> /// <param name="indexName">索引名</param> public static async Task InitializeIndexMapAsync<T>(this IElasticClient client, string indexName, int numberOfShards, int numberOfReplicas) where T : class { var newName = indexName + DateTime.Now.Ticks; var result = await client.CreateIndexAsync(newName, x => x.Index(newName) .Settings(o => o.NumberOfShards(numberOfShards) .NumberOfReplicas(numberOfReplicas) .Setting("max_result_window", int.MaxValue)) .Mappings(m => m.Map<T>(mm => mm.AutoMap()))); if (result.Acknowledged) { await client.AliasAsync(x => x.Add(o => o.Index(newName).Alias(indexName))); return; } throw new ElasticsearchException($"创建索引 {indexName} 失败:{result.ServerError.Error.Reason}"); } }
HighlightParam
public class HighlightParam { /// <summary> /// 高亮字段 /// </summary> public string[] Keys { get; set; } /// <summary> /// 高亮标签 /// </summary> public string PreTags { get; set; } = "<em>"; /// <summary> /// 高亮标签 /// </summary> public string PostTags { get; set; } = "</em>"; /// <summary> /// 高亮字段前缀。 /// 例如:title 高亮值赋值给 h_title /// </summary> public string PrefixOfKey { get; set; } = string.Empty; /// <summary> /// 是否替换原来的值 /// </summary> public bool ReplaceAuto { get; set; } = true; }
IPageParam
public interface IPageParam { /// <summary> /// 页数,即第几页,从1开始 /// </summary> int Page { get; set; } /// <summary> /// 每页显示行数 /// </summary> int PageSize { get; set; } /// <summary> /// 关键词 /// </summary> string Keyword { get; set; } /// <summary> /// 获取跳过的行数 /// </summary> /// <returns></returns> int GetSkipCount(); /// <summary> /// 运算符 /// </summary> Nest.Operator Operator { get; set; } /// <summary> /// 高亮参数 /// </summary> HighlightParam Highlight { get; set; } } /// <summary> /// 分页参数 /// </summary> public class PageParam : IPageParam { /// <summary> /// 页数,即第几页,从1开始 /// </summary> public int Page { get; set; } /// <summary> /// 每页显示行数 /// </summary> public int PageSize { get; set; } /// <summary> /// 关键词 /// </summary> public string Keyword { get; set; } /// <summary> /// 获取跳过的行数 /// </summary> /// <returns></returns> public int GetSkipCount() => (Page - 1) * PageSize; /// <summary> /// 运算符 /// </summary> public Nest.Operator Operator { get; set; } = Nest.Operator.And; /// <summary> /// 高亮参数 /// </summary> public HighlightParam Highlight { get; set; } } /// <summary> /// 指定字段查询 /// </summary> public class PageParamWithSearch : PageParam { /// <summary> /// 查询字段列表 /// </summary> public string[] SearchKeys { get; set; } }
IQueryResult
/// <summary> /// 查询结果 /// </summary> /// <typeparam name="T">实体类型</typeparam> public interface IQueryResult<T> { /// <summary> /// 总行数 /// </summary> long TotalCount { get; set; } /// <summary> /// 查询占用时间 /// </summary> long Took { get; set; } /// <summary> /// 数据 /// </summary> IEnumerable<T> Data { get; } } /// <summary> /// 自定义查询结果 /// </summary> /// <typeparam name="T">实体类型</typeparam> public class CustomQueryResult<T> : IQueryResult<T> { /// <summary> /// 总行数 /// </summary> public long TotalCount { get; set; } /// <summary> /// 查询占用时间 /// </summary> public long Took { get; set; } /// <summary> /// 数据 /// </summary> public IEnumerable<T> Data { get; set; } }
ElasticsearchClient
/// <summary> /// ES客户端 /// </summary> public class ElasticsearchClient : IElasticsearchClient { /// <summary> /// ES客户端生成器 /// </summary> private ElasticsearchClientBuilder _builder; /// <summary> /// 配置提供程序 /// </summary> private IElasticsearchConfigProvider _configProvider; /// <summary> /// 初始化一个<see cref="ElasticsearchClient"/>类型的实例 /// </summary> /// <param name="configProvider">配置提供程序</param> public ElasticsearchClient(IElasticsearchConfigProvider configProvider) { _configProvider = configProvider ?? throw new ArgumentNullException(nameof(configProvider)); _builder = new ElasticsearchClientBuilder(configProvider); } /// <summary> /// 是否存在指定索引 /// </summary> /// <param name="indexName">索引名</param> /// <returns></returns> public async Task<bool> ExistsAsync(string indexName) { var client = await _builder.GetClientAsync(); var result = await client.IndexExistsAsync(indexName); return result.Exists; } /// <summary> /// 添加索引。不映射 /// </summary> /// <param name="indexName">索引名</param> public async Task AddAsync(string indexName) { var client = await _builder.GetClientAsync(); if (await ExistsAsync(indexName)) return; await client.InitializeIndexMapAsync(indexName); } /// <summary> /// 添加索引。自动映射实体属性 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> public async Task AddAsync<T>(string indexName) where T : class { var client = await _builder.GetClientAsync(); if (await ExistsAsync(indexName)) return; await client.InitializeIndexMapAsync<T>(indexName); } /// <summary> /// 添加索引。自动映射实体属性并赋值 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="entity">实体</param> public async Task AddAsync<T>(string indexName, T entity) where T : class { var client = await _builder.GetClientAsync(); if (!await ExistsAsync(indexName)) await client.InitializeIndexMapAsync<T>(indexName); var response = await client.IndexAsync(entity, x => x.Index(indexName)); if(!response.IsValid) throw new ElasticsearchException($"新增数据[{indexName}]失败 : {response.ServerError.Error.Reason}"); } /// <summary> /// 更新索引。 /// 由于是普通的简单更新,当ID已经存在时,则会更新文档,所以这里直接调用index方法(复杂方法待研究) /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="entity">实体</param> public async Task UpdateAsync<T>(string indexName, T entity) where T : class =>await AddAsync<T>(indexName, entity); /// <summary> /// 删除索引 /// </summary> /// <param name="indexName">索引名</param> public async Task DeleteAsync(string indexName) { var client = await _builder.GetClientAsync(); var response = await client.DeleteIndexAsync(indexName); if (response.Acknowledged) return; } /// <summary> /// 删除索引 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="entity">实体</param> public async Task DeleteAsync<T>(string indexName, T entity) where T : class { var client = await _builder.GetClientAsync(); var response = await client.DeleteAsync(new DeleteRequest(indexName, typeof(T), new Id(entity))); if (response.ServerError == null) return; throw new ElasticsearchException($"删除索引[{indexName}]失败 : {response.ServerError.Error.Reason}"); } /// <summary> /// 删除索引 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="id">主键ID</param> public async Task DeleteAsync<T>(string indexName, long id) where T : class { var client = await _builder.GetClientAsync(); var response = await client.DeleteAsync(DocumentPath<T>.Id(new Id(id)), x => x.Type<T>().Index(indexName)); if (response.ServerError == null) return; throw new ElasticsearchException($"删除索引[{indexName}]失败 : {response.ServerError.Error.Reason}"); } /// <summary> /// 查询实体 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="id">主键ID</param> /// <returns></returns> public async Task<T> FindAsync<T>(string indexName, long id) where T : class { var client = await _builder.GetClientAsync(); var response = await client.GetAsync<T>(id, x => x.Type<T>().Index(indexName)); return response?.Source; } /// <summary> /// 查询。单一条件查询,一般是精确查询 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="field">字段名</param> /// <param name="value">查询值</param> /// <returns></returns> public async Task<IEnumerable<T>> QueryAsync<T>(string indexName, string field, object value) where T : class { if (string.IsNullOrWhiteSpace(field)) return null; var client = await _builder.GetClientAsync(); var searchRequest = new SearchDescriptor<T>() .Index(indexName) .PostFilter(t => t.Term(x => x.Field(field).Value(value))); var response = await client.SearchAsync<T>(searchRequest); return response.Documents; } /// <summary> /// 查找实体列表 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="ids">主键值</param> /// <returns></returns> public async Task<IEnumerable<T>> FindByIdsAsync<T>(string indexName, params long[] ids) where T : class { var client = await _builder.GetClientAsync(); var searchRequest = new SearchDescriptor<T>().Index(indexName).Query(t => t.Ids(x => x.Values(ids))); var response = await client.SearchAsync<T>(searchRequest); return response.Documents; } /// <summary> /// 查找实体列表 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="ids">主键值</param> /// <returns></returns> public async Task<IEnumerable<T>> FindByIdsAsync<T>(string indexName, params string[] ids) where T : class { var client = await _builder.GetClientAsync(); var searchRequest = new SearchDescriptor<T>().Index(indexName).Query(t => t.Ids(x => x.Values(ids))); var response = await client.SearchAsync<T>(searchRequest); return response.Documents; } /// <summary> /// 查找实体列表 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="ids">主键值</param> /// <returns></returns> public async Task<IEnumerable<T>> FindByIdsAsync<T>(string indexName, params Guid[] ids) where T : class { var client = await _builder.GetClientAsync(); var searchRequest = new SearchDescriptor<T>().Index(indexName).Query(q => q.Ids(x => x.Values(ids))); var response = await client.SearchAsync<T>(searchRequest); return response.Documents; } /// <summary> /// 分页查询 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="param">分页参数</param> /// <param name="indexName">索引名</param> /// <returns></returns> public async Task<IQueryResult<T>> PageQueryAsync<T>(IPageParam param, string indexName) where T : class { if (param == null) { param = new PageParam() { Page = 1, PageSize = 20 }; } var searchRequest = new SearchDescriptor<T>() .Type<T>() .Index(indexName) .From(param.GetSkipCount()) .Size(param.PageSize); if (param is PageParamWithSearch pageSearch) ConfigPageRequest(pageSearch, ref searchRequest); else if(param is PageParam pageParam) ConfigPageRequest(pageParam, ref searchRequest); // 是否需要高亮 bool hasHighlight = param.Highlight?.Keys?.Length > 0; if(hasHighlight) BuildHighLightQuery(param, ref searchRequest); var client = await _builder.GetClientAsync(); var response = await client.SearchAsync<T>(x => searchRequest); //if (hasHighlight) //{ // var listWithHightlight = new List<T>(); // response.Hits.ToList().ForEach(x => // { // if (x.Highlights?.Count > 0) // { // PropertyInfo[] properties = typeof(T).GetProperties(); // foreach (string key in pageParams.Highlight?.Keys) // { // //先得到要替换的内容 // if (x.Highlights.ContainsKey(key)) // { // string value = string.Join("", x.Highlights[key]?.Highlights); // PropertyInfo info = properties.FirstOrDefault(p => p.Name == pageParams.Highlight.PrefixOfKey + key); // //没找到带前缀的属性,则替换之前的 // if (info == null && pageParams.Highlight.ReplaceAuto) // { // info = properties.FirstOrDefault(p => p.Name == key); // } // if (info?.CanWrite == true) // { // if (!string.IsNullOrEmpty(value)) // { // //如果高亮字段不为空,才赋值,否则就赋值成空 // info.SetValue(x.Source, value); // } // } // } // } // } // listWithHightlight.Add(x.Source); // }); //} return new CustomQueryResult<T>() { Data = response.Documents, Took = response.Took, TotalCount = response.Total }; } /// <summary> /// 配置指定字段的分页请求 /// </summary> private void ConfigPageRequest<T>(PageParamWithSearch param, ref SearchDescriptor<T> searchRequest) where T : class { searchRequest = searchRequest.Query(t=> t.QueryString(x => x.Fields(param.SearchKeys) .Query(param.Keyword) .DefaultOperator(param.Operator))); } /// <summary> /// 配置分页请求 /// </summary> private void ConfigPageRequest<T>(PageParam param, ref SearchDescriptor<T> searchRequest) where T : class { searchRequest= searchRequest.Query( t=>t.QueryString(q=>q.Query(param.Keyword) .DefaultOperator(param.Operator))); } /// <summary> /// 构造高亮查询 /// </summary> private void BuildHighLightQuery<T>(IPageParam param, ref SearchDescriptor<T> searchRequest) where T : class { var keysLength = param.Highlight?.Keys?.Length ?? 0; var fieldDescriptor = new Func<HighlightFieldDescriptor<T>, IHighlightField>[keysLength]; var keysIndex = 0; foreach (var key in param.Highlight?.Keys) { fieldDescriptor[keysIndex] = hf => hf.Field(key) .HighlightQuery(q => q.Match(m => m.Field(key).Query(param.Keyword))); keysIndex++; } IHighlight highlight = new HighlightDescriptor<T>() .PreTags(param.Highlight.PreTags) .PostTags(param.Highlight.PostTags) .Fields(fieldDescriptor); searchRequest = searchRequest.Highlight(s => highlight); } /// <summary> /// 批量保存 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="entities">实体列表</param> public async Task BulkSaveAsync<T>(string indexName, IEnumerable<T> entities) where T : class { var client = await _builder.GetClientAsync(); if (!await ExistsAsync(indexName)) { await client.InitializeIndexMapAsync<T>(indexName); } var bulk = new BulkRequest(indexName) { Operations = new List<IBulkOperation>() }; foreach (var entity in entities) { bulk.Operations.Add(new BulkIndexOperation<T>(entity)); } var response = await client.BulkAsync(bulk); if (response.Errors) { throw new ElasticsearchException($"批量保存文档在索引 {indexName} 失败:{response.ServerError.Error.Reason}"); } } }
ElasticsearchClientBuilder
/// <summary> /// ES客户端生成器 /// </summary> internal class ElasticsearchClientBuilder { /// <summary> /// ES客户端 /// </summary> private IElasticClient _client; /// <summary> /// 配置提供程序 /// </summary> private readonly IElasticsearchConfigProvider _configProvider; /// <summary> /// 对象锁 /// </summary> private static object _lock = new object(); /// <summary> /// 初始化一个<see cref="ElasticsearchClientBuilder"/>类型的实例 /// </summary> /// <param name="configProvider">配置提供程序</param> public ElasticsearchClientBuilder(IElasticsearchConfigProvider configProvider) { _configProvider = configProvider; } /// <summary> /// 获取ES客户端 /// </summary> /// <returns></returns> public async Task<IElasticClient> GetClientAsync() { if (_client == null) { var config = await _configProvider.GetConfigAsync(); lock (_lock) { if (_client == null) { if (config.Nodes == null) throw new ArgumentException("请设置ES客户端节点"); _client = CreateClient(config); } } } return _client; } /// <summary> /// 创建ES客户端 /// </summary> /// <param name="config">配置</param> /// <returns></returns> private IElasticClient CreateClient(ElasticsearchConfig config) { var connectionPool = CreateConnectionPool(config); var settings = new ConnectionSettings(connectionPool); ConfigSettings(settings, config); return new ElasticClient(settings); } /// <summary> /// 创建连接池 /// </summary> /// <param name="config"></param> /// <returns></returns> private IConnectionPool CreateConnectionPool(ElasticsearchConfig config) { var nodes = config.Nodes.Select(t => new Uri(t.ToString())).ToList(); switch (config.PoolType) { case ElasticsearchConnectionPoolType.Static: return new StaticConnectionPool(nodes); case ElasticsearchConnectionPoolType.SingleNode: return new SingleNodeConnectionPool(nodes.FirstOrDefault()); case ElasticsearchConnectionPoolType.Sniffing: return new SniffingConnectionPool(nodes); case ElasticsearchConnectionPoolType.Sticky: return new StickyConnectionPool(nodes); case ElasticsearchConnectionPoolType.StickySniffing: return new StickySniffingConnectionPool(nodes, x => 1.0F); default: return new StaticConnectionPool(nodes); } } /// <summary> /// 配置连接设置 /// </summary> /// <param name="settings">连接设置</param> /// <param name="config">配置</param> private void ConfigSettings(ConnectionSettings settings, ElasticsearchConfig config) { // 启用验证 if (!string.IsNullOrWhiteSpace(config.UserName) && !string.IsNullOrWhiteSpace(config.Password)) settings.BasicAuthentication(config.UserName, config.Password); // 验证证书 //settings.ClientCertificate(""); //settings.ClientCertificates(new System.Security.Cryptography.X509Certificates.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(config.DisablePing); // 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(config.DisableDebugInfo); //settings.EnableDebugMode((apiCallDetails) => //{ // // 请求完成 返回 apiCallDetails //}); // 抛出异常,默认false,错误信息在每个操作的response中 settings.ThrowExceptions(config.ThrowExceptions); //settings.OnRequestCompleted(apiCallDetails => //{ // // 请求完成 返回apiCallDetails //}); //settings.OnRequestDataCreated(requestData => //{ // // 请求的数据创建完成 返回请求的数据 //}); } }
ElasticsearchException
/// <summary> /// Elasticsearch 异常 /// </summary> [Serializable] public class ElasticsearchException : Exception { /// <summary> /// 初始化一个<see cref="ElasticsearchException"/>类型的实例 /// </summary> public ElasticsearchException() { } /// <summary> /// 初始化一个<see cref="ElasticsearchException"/>类型的实例 /// </summary> /// <param name="serializationInfo">序列号信息</param> /// <param name="context">流上下文</param> public ElasticsearchException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { } /// <summary> /// 初始化一个<see cref="ElasticsearchException"/>类型的实例 /// </summary> /// <param name="message">错误消息</param> public ElasticsearchException(string message) : base(message) { } /// <summary> /// 初始化一个<see cref="ElasticsearchException"/>类型的实例 /// </summary> /// <param name="message">错误消息</param> /// <param name="innerException">内部异常</param> public ElasticsearchException(string message, Exception innerException) : base(message, innerException) { } }
IElasticsearchClient
/// <summary> /// ES客户端 /// </summary> public interface IElasticsearchClient { /// <summary> /// 是否存在指定索引 /// </summary> /// <param name="indexName">索引名</param> /// <returns></returns> Task<bool> ExistsAsync(string indexName); /// <summary> /// 添加索引。不映射 /// </summary> /// <param name="indexName">索引名</param> Task AddAsync(string indexName); /// <summary> /// 添加索引。自动映射实体属性 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> Task AddAsync<T>(string indexName) where T : class; /// <summary> /// 添加索引。自动映射实体属性并赋值 /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="entity">实体</param> /// <returns></returns> Task AddAsync<T>(string indexName, T entity) where T : class; /// <summary> /// 更新索引。 /// 由于是普通的简单更新,当ID已经存在时,则会更新文档,所以这里直接调用index方法(复杂方法待研究) /// </summary> /// <typeparam name="T">实体类型</typeparam> /// <param name="indexName">索引名</param> /// <param name="entity">实体</param> Task UpdateAsync<T>(string indexName, T entity) where T : class; }