Elasticsearch全量数据增量遍历实现原理
0、需求
針對鳳凰網財經版塊的新聞數據和評論數據, 1個索引存儲采集鳳凰網財經版塊的新聞數據;1個索引存儲相關的財經數據評論結果。?
統計:?
1)某條新聞的評論數的多少??
2)某條評論屬于哪條新聞??
3)當前已采集數據的所有評論、評論數匯總,按照評論數逆序排序,以便于圖形化展示。
1、問題分解
1.1 數據如何存儲,方案選型?
方案一:類似需求,1個索引ifeng_index存儲新聞數據;1個索引ifeng_comm_index存儲評論數據。?
二者之間通過唯一值建立關聯:評論數據中其來源新聞的唯一id值。?
優點:數據分開存儲,不存在交叉問題;?
缺點:如果實現需求3),會非常復雜,做全局兩通道的遍歷和統計。
方案二:借助2.X-5.X版本ES中特有的父子文檔實現。?
注意:由于6.X版本以后,一個索引下只能存儲一個type,所以父子文檔也就不再可以使用。?
所謂父子文檔,可以理解為:?
1)統一索引下的兩個type,1個父type存儲鳳凰網新聞數據;1個子type存儲鳳凰網評論數據;?
2)其中子type的Mapping定義要特殊處理;?
3)其中子type的每條鳳凰網評論數據都要關聯唯一的父type的相關ID值。?
優點:可以以相對較小的復雜度滿足需求1)、2)、3)?
缺點:以上方案二,ES6.X+都不再適用。?
注意:?
ES6.X已經移除父子文檔的相關實現:http://t.cn/RE07V5A?
但是轉換為新的join的實現方式:http://t.cn/RE07IG1?
綜上分析,我是5.X的版本,采取方案二。
1.2 所需要技術支撐
1)父子文檔技術?
父子文檔定義:?
用于兩個索引之間通過某一個特殊字段建立關聯的場景。?
在1對多的場景,尤其適用。如:1個父文檔下有多個子文檔。?
缺點: 查詢速度會比同等的嵌套查詢慢5到10倍,詳見:http://t.cn/ROir5rQ
父子文檔實現:?
建立父-子文檔映射關系時只需要指定某一個文檔 type 是另一個文檔 type 的父親。 該關系可以在如下兩個時間點設置:1)創建索引時;2)在子文檔 type 創建之前更新父文檔的 mapping。
2)全局遍歷技術?
借助Scroll實現。之前的博文也有說明,http://t.cn/RE068mD?
【scroll機制】:相對于from和size的分頁來說,使用scroll可以模擬一個傳統數據的游標,記錄當前讀取的文檔信息位置。這個分頁的用法,不是為了實時查詢數據,而是為了一次性查詢大量的數據(甚至是全部的數據)。?
假設某索引下共有8個document,document中由code字段標記不同,0,1,2….8區分。
假設仍在的有效時間1min內,繼續查詢,返回結果:空。?
若超時,繼續scroll_id請求,則會返回類似如下的錯誤:
3)增量遍歷統計計數?
對修改字段打flag標記,可以通過ES中update_by_query方法,對ES中數據進行更新操作。?
如果:不存在flag字段,遍歷到該條記錄的時候,新增flag字段且flag置為1。?
如果:存在flag字段,代表該條記錄已經被遍歷過。?
這樣的好處,防止數據被循環遍歷。?
其實:scroll機制已經預防了這一點,以防萬一。
2、具體原理
2.1 scroll實現遍歷DSL實現
步驟1:scroll查詢。?
基于特定的字段進行排序如下:
返回結果:
{"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAFcOGqFllFRGNIdVQ2Ui1LaFJRblJKOWVDNkEAAAAABXDhqxZZRURjSHVUNlItS2hSUW5SSjllQzZBAAAAAAPXB3EWTllZcVhfUlNSRUN5M3NueUJ2YkVXUQAAAAAD1wd0Fk5ZWXFYX1JTUkVDeTNzbnlCdmJFV1EAAAAAA9cHchZOWVlxWF9SU1JFQ3kzc255QnZiRVdR","took": 4,"timed_out": false,"_shards": {"total": 5,"successful": 5,"failed": 0},"hits": {"total": 8,"max_score": null,"hits": [{"_index": "scroll_index","_type": "scroll_type","_id": "0","_score": null,"_source": {"code": 0},"sort": [0]},{"_index": "scroll_index","_type": "scroll_type","_id": "1","_score": null,"_source": {"code": 1},"sort": [1]},{"_index": "scroll_index","_type": "scroll_type","_id": "2","_score": null,"_source": {"code": 2},"sort": [2]}]} }步驟2:基于Scroll_id查詢
POST /_search/scroll {"scroll" : "1m","scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAFcOGqFllFRGNIdVQ2Ui1LaFJRblJKOWVDNkEAAAAABXDhqxZZRURjSHVUNlItS2hSUW5SSjllQzZBAAAAAAPXB3EWTllZcVhfUlNSRUN5M3NueUJ2YkVXUQAAAAAD1wd0Fk5ZWXFYX1JTUkVDeTNzbnlCdmJFV1EAAAAAA9cHchZOWVlxWF9SU1JFQ3kzc255QnZiRVdR" }步驟3:循環執行,直至遍歷結束。?
主要注意的時間。
2.3 增量部分java如何實現?
在延遲指定時間后以指定的間隔時間循環執行定時任務。?
借助Java Timer類實現。 Timer 是一種定時器工具,用來在一個后臺線程計劃執行指定任務。
2.5 父子文檔的實現。
步驟1:定義索引,同常規定義索引一致。
但,要規劃好父子文檔,通過:type類型區分。?
如,父文檔的type定義為:fenghuang_type, 子文檔定義為ifeng_comm_type。
步驟2:插入子文檔數據。
父文檔數據插入和傳統導入數據方式一致。?
舉例如下:?
PUT /ifeng_index/ifeng_comm_type/1?parent=XVFBASDE!?
注意: 父子文檔關聯建立的關鍵是:在導入子文檔數據的時候通過加入參數parent=父文檔的_id。
步驟3:基于父文檔查詢子文檔。
POST ifeng_index/ifeng_comm_type/_search {"query": {"has_parent": {"type": "ifeng_type","query": {"match": {"title": "世錦賽-墨西哥錦標賽移動日精彩集錦"}}}} }步驟4:基于子文檔查詢父文檔。
POST ifeng_index/ifeng_type/_search {"query": {"has_child": {"type": "ifeng_comm_type","score_mode": "max","query": {"match": {"title": "很精彩,棒極啦!"}}}} }步驟5: 查看索引中每個父文檔下有多少個子文檔
POST /ifeng_index/ifeng_type/ {"size": 0,"aggs": {"ifeng_key_agg": {"terms": {"field": "_key","order": {"ifeng_comm_type": "desc"}},"aggs": {"ifeng_comm_type": {"children": {"type": "ifeng_comm_type"}}}}} }3、小結
通過父子文檔,實現了1對多數據的關聯;?
通過scroll可以實現遍歷操作,實現全量遍歷;?
通過scroll+java定時任務Timer,實現增量遍歷。
總結
以上是生活随笔為你收集整理的Elasticsearch全量数据增量遍历实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你必须知道的23个最有用的Elastic
- 下一篇: 《深入理解Elasticsearch》读