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;
}