(精华)2020年8月18日 C#基础知识点 搜索引擎ElasticSearch的使用
(精华)2020年8月18日 C#基础知识点 搜索引擎ElasticSearch的使用
项目需要添加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配置类
public class EsConfig : IOptions<EsConfig>
{<!-- -->
public List<string> Urls {<!-- --> get; set; }
public EsConfig Value => this;
}
2)创建ElasticSearch提供者接口以及类
/// <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);
}
}
---------用户密码验证(注释部分),可以配置在EsConfig中---------
/// <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类
/// <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操作基类
/// <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;
}
}
3)、具体操作类(示例)
/// <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;
}
}
address类
[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 "EsConfig": {<!-- -->
2 "ConnectionStrings": [ "http://127.0.0.1:9200/" ]
3 }
2)、注入ElasticSearch
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类中使用
[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);
}
}
4、测试(略)
当然es还有很多操作的,聚合查询、不同条件的查询(范围查询、匹配查询等等)、分词等。具体可以去查看其官方文档对应实现!