
链接:cnblogs.com/linbin524/p/15389516.html
前言
在线文档:http://doc.yc-l.com/#/README
在线演示地址:http://yc.yc-l.com/#/login
源码github:https://github.com/linbin524/yc.boilerplate
源码gitee:https://gitee.com/linxuanming/yc.boilerplate
大数据套件 ElasticSearch
简介
为了提升YC.Boilerlate 在大数据量的处理能力,引入ES组件,封装对应的模块、实现租户拆分、仓储、集群、大数据上亿级别以上数据的检索、统计、分析,并提供千万级别分词搜索等演示示例。
ES基础介绍
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,是PB级别大数据解决方案组件之一。Elasticsearch是基于Lucense的搜索服务器,,基于RESTful web接口。Elasticsearch是Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
ES解决什么问题
对海量数据进行近实时的处理
ES自动可以将海量数据分散到多台服务器上去存储和检索,通过内置搜索引擎、分词、实现 千万级别数据秒级查询、统计、分析等,相对传统关系型数据库的模糊查询在速度有着质的飞跃。
ES 适用场景
ES 常用组合
ES 和常规关系型数据库差异
ES中有几个基本概念:索引(index)、类型(type)、文档(document)、映射(mapping)等。我们将这几个概念与传统的关系型数据库中的库、表、行、列等概念进行对比,如下表:

常规问题
put /tenant_1_books/_settings
{
"index.max_result_window" :"1000000"
}
还可以采用searchAfer、scroll等方案。
集群部署
在本地或者服务器上搭建3个es节点,形成集群,针对elasticsearch.yml进行节点配置,最后启动服务,并安装对应的kibana组件【可视化】。

配置
在项目的YC.ServiceWebApi 中的配置文件 DefaultConfig.json,做如下配置,其中node是对应的es节点。
"ElasticSearchSetting": {
///elasticSearch节点集群
"Nodes": [
{ "node": "http://127.0.0.1:9200" },
{ "node": "http://127.0.0.1:9201" },
{ "node": "http://127.0.0.1:9202" }
]
}
在项目的YC.ServiceWebApi 找到 ElasticSearchAutofacModule.cs该文件是相关的IOC 注入配置,在Startup.cs中进行如下注入操作:
// elasticSearch 注入
builder.RegisterModule(new ElasticSearchAutofacModule());
ES 模块调用
在示例演示 BookAppService 中可以直接使用对应的注入调用es组件。
private IElasticSearchRepository<Book> _elasticSearchRepository;
public BookAppService(
IHttpContextAccessor httpContextAccessor, ICacheManager cacheManager, IMapper mapper, IElasticSearchRepository<Book> elasticSearchRepository) : base(httpContextAccessor, cacheManager)
{
_cacheManager = cacheManager;
_mapper = mapper;
_elasticSearchRepository = elasticSearchRepository;
}
/// <summary>
/// 查查默认1页10条
/// </summary>
/// <returns>返回数据集合</returns>
public async Task<ApiResult<List<BookAddOrEditDto>>> GetAllAsync()
{
var res = new ApiResult<List<BookAddOrEditDto>>();
var data = await _elasticSearchRepository.GetAllAsync();
var entityDtoList = _mapper.Map<List<BookAddOrEditDto>>(data);
return res.Ok(entityDtoList);
}
YC.ElasticSearch 模块介绍
模块包含有请求上下文、以及默认仓储,其中仓储封装了常规crud、聚合查询、searchAfter查询等常规操作异步方法,并在仓储上提供一个公开请求上下文对象,用于自定义化es操作,模块配套对应的单元测试,提供基础调用示例。



es 其他使用介绍
使用 kibana 操作,对指定的Index进行分片
//创建表 对应的分片,需要表还没创建时候设置
put /tenant_1_books_0
{
"settings":{
"number_of_shards":2
}
}
//创建新的索引数据库,并指定字段映射类型,tenant_1_books_0 中的bookName 类型改为keyword
PUT tenant_1_books_0
{
"mappings": {
"properties": {
"bookName":{
"type":"keyword"
}
}
}
}
//迁移数据,将tenant_1_books 数据迁移到tenant_1_books_1
POST _reindex
{
"source": {
"index": "tenant_1_books"
},
"dest": {
"index": "tenant_1_books_1"
}
}
//查看tenant_1_books所有数据【默认会分页】
GET tenant_1_books/_search
{
"track_total_hits": true,
"query": {
"match_all": {}
}
}
//深度分页方案1 扩大分页限制
//允许深度分页,限制在10w
put /tenant_1_books/_settings
{
"index.max_result_window" :"1000000"
}
//查询数据 分页,track_total_hits=真实的总数
GET tenant_1_books/_search
{
"track_total_hits": true,
"from" : 99000, "size" : 100,
"query": {
"match_all": {}
}
}
结果如下:


配套的net单元测试代码如下:
/// <summary>
/// 深度分页查询 searchAfter
/// </summary>
/// <returns></returns>
[Fact]
public async Task GetPageByQuerySearchAfterTest()
{
int size = 100;
// "bookName" : {
//"type" : "keyword"
//},
//1、BookName 修改为keyword 所有必须完整匹配,不分词
Func<QueryContainerDescriptor<Book>, QueryContainer> query1 = q => q.Term(t => t.BookName, "吞噬星空");
Func<QueryContainerDescriptor<Book>, QueryContainer> query2 = q => q.Match(mq =>
mq.Field(f => f.BookName).Query("哈利波特").Operator(Operator.And)
);//由于类型为 keyword,所以Match 查找不出来,只能使用Term 精确查询
//2.全字匹配+ 分词查询
Func<QueryContainerDescriptor<Book>, QueryContainer> query3 = q => q
.Term(t => t.BookName, "吞噬星空")
|| q.Match(mq =>
mq.Field(f => f.BookContent).Query("哈利波特").Operator(Operator.And)
);
//排序
Func<SortDescriptor<Book>, IPromise<IList<ISort>>> sort = s => s.Ascending(a => a.CreateDate).Descending(d=>d.Price);
var result1=await _elasticSearchRepository.GetPageByQuerySearchAfterAsync(query3, sort, 100, null);
//使用上一次查询得到SearchAfter 作为下一次查询的游标
var result2 = await _elasticSearchRepository.GetPageByQuerySearchAfterAsync(query3, sort, 100, result1.SearchAfter);
Assert.NotNull(result2.List);
}
//深度分页方案3 scroll,者每次查询大量的文档,但是对实时性要求并不高,
//后面的每次滚屏(或者叫翻页)都是基于这个快照的结果,也就是即使有新的数据进来也不会别查询到。
//1. 查询
POST tenant_1_books/_search?scroll=1m
{
"size": 1000,
"query": {
"match_all" : {
}
}
}
//2. 上一次查询所得到结果,作为游标
POST _search/scroll
{
"scroll" : "1m",
"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmJpVWRZVWQ3UkItejk2UUx5bC15bFEAAAAAAAMv2xZyZURRWkowelF6S0NnRjMzWjhfQTh3"
}
//聚合获取该字段的所有统计
get /tenant_1_books/_search
{
"aggs":{
"extended_stats_price":{"extended_stats":{"field":"price"}}
}
}
//聚合 总和统计
get /tenant_1_books/_search
{
"aggs":{
"total_price":{"sum":{"field":"price"}}
}
}
YC.ElasticSearch 大数据检索示例
在http://yc.yc-l.com/ 演示站点中,默认使用租户1 作为es 检索演示,内置1000多万条测试数据,通过 书名、书内容关键词、发布时间范围等可进行查询,价格 查询在演示站点中关闭了,无法查询,请注意。
备注:演示站点默认使用10000条数据查询上限边界。
