線上文件: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
視訊教程:
元磁之力框架開源初心和框架設計介紹(上): https://www.bilibili.com/video/BV1VM4y1G7hC/
元磁之力框架開源初心和框架設計介紹(下): https://www.bilibili.com/video/BV15h411s7w6/
元磁之力框架資料庫表和程式碼生成使用教程實戰: https://www.bilibili.com/video/BV1oM4y137D5/
QQ群:1060819005
後續:關於框架demo和細節技巧,會在QQ群中釋出,就不撰文說明。
大資料套件 ElasticSearch
簡介
為了提升YC.Boilerlate
在大資料量的處理能力,引入ES元件,封裝對應的模組、實現租戶拆分、倉儲、叢集、大資料上億級別以上資料的檢索、統計、分析,並提供千萬級別分詞搜尋等演示示例。
ES基礎介紹
Elasticsearch 是一個分散式、RESTful 風格的搜尋和資料分析引擎,是PB級別大資料解決方案元件之一。
Elasticsearch是基於Lucense的搜尋伺服器,,基於RESTful web介面。Elasticsearch是Java語言開發的,並作為Apache許可條款下的開放原始碼釋出,是一種流行的企業級搜尋引擎。Elasticsearch用於雲端計算中,能夠達到實時搜尋,穩定,可靠,快速,安裝使用方便。
ES解決什麼問題
對海量資料進行近實時的處理
ES自動可以將海量資料分散到多臺伺服器上去儲存和檢索,通過內建搜尋引擎、分詞、實現
千萬級別資料秒級查詢、統計、分析等,相對傳統關係型資料庫的模糊查詢在速度有著質的飛躍。
ES 適用場景
-
維基百科,類似百度百科,牙膏,牙膏的維基百科,全文檢索,高亮,搜尋推薦
-
The Guardian(國外新聞網站),類似搜狐新聞,使用者行為日誌(點選,瀏覽,收藏,評論)+社交網路資料(對某某新聞的相關看法),資料分析,給到每篇新聞文章的作者,讓他知道他的文章的公眾反饋(好,壞,熱門,垃圾,鄙視,崇拜)
-
Stack Overflow(國外的程式異常討論論壇),IT問題,程式的報錯,提交上去,有人會跟你討論和回答,全文檢索,搜尋相關問題和答案,程式報錯了,就會將報錯資訊貼上到裡面去,搜尋有沒有對應的答案
-
GitHub(開原始碼管理),搜尋上千億行程式碼
-
電商網站,檢索商品
-
日誌資料分析,logstash採集日誌,ES進行復雜的資料分析(ELK技術,elasticsearch+logstash+kibana)
-
商品價格監控網站,使用者設定某商品的價格閾值,當低於該閾值的時候,傳送通知訊息給使用者,比如說訂閱牙膏的監控,如果高露潔牙膏的家庭套裝低於50塊錢,就通知我,我就去買
-
BI系統,商業智慧,Business Intelligence。比如說有個大型商場集團,BI,分析一下某某區域最近3年的使用者消費金額的趨勢以及使用者群體的組成構成,產出相關的數張報表,**區,最近3年,每年消費金額呈現100%的增長,而且使用者群體85%是高階白領,開一個新商場。ES執行資料分析和挖掘,Kibana進行資料視覺化國內
-
國內:站內搜尋(電商,招聘,門戶,等等),IT系統搜尋(OA,CRM,ERP,等等),資料分析(ES熱門的一個使用場景)
ES 常用組合
-
ELK :Elasticsearch是與名為Logstash的資料收集和日誌解析引擎以及名為Kibana的分析和視覺化平臺一起開發的。這三個產品被設計成一個整合解決方案。
Elasticsearch可以用於搜尋各種文件。它提供可擴充套件的搜尋,具有接近實時的搜尋,並支援多租戶。Elasticsearch是分散式的,這意味著索引可以被分成分片,每個分片可以有0個或多個副本。每個節點託管一個或多個分片,並充當協調器將操作委託給正確的分片。再平衡和路由是自動完成的。相關資料通常儲存在同一個索引中,該索引由一個或多個主分片和零個或多個複製分片組成。一旦建立了索引,就不能更改主分片的數量。 -
阿里巴巴開發的canal:基於Mysql的binlog日誌訂閱:binlog日誌是Mysql用來記錄資料實時的變化。這裡主要的是binlog同步元件,目前實現的有國內的。
github地址:https://github.com/alibaba/canal -
go-mysql-elasticsearch:go-mysql-elasticsearch是一款使用go語言開發的同步資料到ES的工具。 go-mysql-elasticsearch也是基於Mysql的binlog訂閱,也可以使用使用mysqldump的方式。目前還不支援ES6.x及以上的版本,也不支援mysql8.x版本,同時該專案目前還不夠穩定,也在開發中。
專案github地址:https://github.com/siddontang/go-mysql-elasticsearch
ES 和常規關係型資料庫差異
ES中有幾個基本概念:索引(index)、型別(type)、文件(document)、對映(mapping)等。我們將這幾個概念與傳統的關係型資料庫中的庫、表、行、列等概念進行對比,如下表:
常規問題
-
記憶體:es 的預設配置在常規伺服器上大部分都有記憶體使用率的問題,需要根據實際情況合理調優。
-
版本:ES 每個版本配套元件有極強耦合,無法做到各個版本相容,所以jdk、以及其他元件需要指定適配。
-
分詞:es除了內建standard分詞,還可以其他分片語件,對中文支援比較好的有:es-ik。
-
分片(shard): 因為 ES 是個分散式的搜尋引擎, 所以索引通常都會分解成不同部分, 而這些分佈在不同節點的資料就是分片. ES自動管理和組織分片, 並在必要的時候對分片資料進行再平衡分配, 所以使用者基本上不用擔心分片的處理細節.
-
副本(replica): ES 預設為一個索引建立 5 個主分片, 並分別為其建立一個副本分片. 也就是說每個索引都由 5 個主分片成本, 而每個主分片都相應的有一個 copy。對於分散式搜尋引擎來說, 分片及副本的分配將是高可用及快速搜尋響應的設計核心.主分片與副本都能處理查詢請求,它們的唯一區別在於只有主分片才能處理索引請求.副本對搜尋效能非常重要,同時使用者也可在任何時候新增或刪除副本。額外的副本能給帶來更大的容量, 更高的呑吐能力及更強的故障恢復能力。
-
深度查詢:在Elasticsearch中如果需要做分頁查詢,我們通常使用form和size實現。form指定從有序哪一行開始,size表示從當前開始讀取多少行。但是我們發現查詢結果最大隻能到10000,這是因為Elasticsearch中的size的預設值在index.max_result_window 中設定,並且預設值就是10000,如果需要擴充套件,可以通過如下操作【擴大查詢最大值】其中1000000是標識擴大為10萬:
put /tenant_1_books/_settings
{
"index.max_result_window" :"1000000"
}
還可以採用searchAfer、scroll等方案。
YC.ElasticSearch 模組實戰
叢集部署
在本地或者伺服器上搭建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": {}
}
}
結果如下:
- 深度查詢 searchAfter
配套的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);
}
- scroll 查詢
//深度分頁方案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條資料查詢上限邊界。