基于scroll滾動(dòng)技術(shù)實(shí)現(xiàn)大數(shù)據(jù)量搜索
如果一次性要查出來(lái)比如10萬(wàn)條數(shù)據(jù),那么性能會(huì)很差,此時(shí)一般會(huì)采取用scroll滾動(dòng)查詢,一批一批的查,直到所有數(shù)據(jù)都查詢完為止。
-
scroll搜索會(huì)在第一次搜索的時(shí)候,保存一個(gè)當(dāng)時(shí)的視圖快照,之后只會(huì)基于該舊的視圖快照提供數(shù)據(jù)搜索,如果這個(gè)期間數(shù)據(jù)變更,是不會(huì)讓用戶看到的
-
采用基于_doc(不使用_score)進(jìn)行排序的方式,性能較高
-
每次發(fā)送scroll請(qǐng)求,我們還需要指定一個(gè)scroll參數(shù),指定一個(gè)時(shí)間窗口,每次搜索請(qǐng)求只要在這個(gè)事件窗口內(nèi)能完成就可以了
# sort默認(rèn)是相關(guān)度排序("sort":[{"FIELD":{"order":"desc"}}]),不按_score排序,按_doc排序 # size設(shè)置的是這批查三條 # 第一次查詢會(huì)生成快照 GET /lib3/user/_search?scroll=1m #這一批查詢?cè)谝环昼妰?nèi)完成 { "query":{ "match":{} }, "sort":[ "_doc" ], "size":3 } # 第二次查詢通過(guò)第一次的快照ID來(lái)查詢,后面以此類推 GET /_search/scroll { "scroll":"1m", "scroll_id":"DnF1ZXJ5VGhIbkXIdGNoAwAAAAAAAAAdFkEwRENOVTdnUUJPWVZUd1p2WE5hV2cAAAAAAAAAHhZBMERDTIU3Z1FCT1|WVHdadIhOYVdnAAAAAAAAAB8WQTBEQ05VN2dRQk9ZVIR3WnZYTmFXZw==" }
基于 scroll 解決深度分頁(yè)問(wèn)題
原理上是對(duì)某次查詢生成一個(gè)游標(biāo) scroll_id , 后續(xù)的查詢只需要根據(jù)這個(gè)游標(biāo)去取數(shù)據(jù),直到結(jié)果集中返回的 hits 字段為空,就表示遍歷結(jié)束。
注意:scroll_id 的生成可以理解為建立了一個(gè)臨時(shí)的歷史快照,在此之后的增刪改查等操作不會(huì)影響到這個(gè)快照的結(jié)果。
使用 curl 進(jìn)行分頁(yè)讀取過(guò)程如下:
-
先獲取第一個(gè) scroll_id,url 參數(shù)包括 /index/_type/ 和 scroll,scroll 字段指定了scroll_id 的有效生存期,以分鐘為單位,過(guò)期之后會(huì)被es 自動(dòng)清理。如果文檔不需要特定排序,可以指定按照文檔創(chuàng)建的時(shí)間返回會(huì)使迭代更高效。
GET /product/info/_search?scroll=2m { "query":{ "match_all":{ } }, "sort":["_doc"] } # 返回結(jié)果 { "_scroll_id": "DnF1ZXJ5VGhIbkXIdGNoAwAAAAAAAAAdFkEwRENOVTdnUUJPWVZUd1p2WE5hV2cAAAAAAAAAHhZBMERDTIU3Z1FCT1|WVHdadIhOYVdnAAAAAAAAAB8WQTBEQ05VN2dRQk9ZVIR3WnZYTmFXZw==", "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "failed": 0 }, "hits":{...} }
-
后續(xù)的文檔讀取上一次查詢返回的scroll_id 來(lái)不斷的取下一頁(yè),如果srcoll_id 的生存期很長(zhǎng),那么每次返回的 scroll_id 都是一樣的,直到該 scroll_id 過(guò)期,才會(huì)返回一個(gè)新的 scroll_id。請(qǐng)求指定的 scroll_id 時(shí)就不需要 /index/_type 等信息了。每讀取一頁(yè)都會(huì)重新設(shè)置 scroll_id 的生存時(shí)間,所以這個(gè)時(shí)間只需要滿足讀取當(dāng)前頁(yè)就可以,不需要滿足讀取所有的數(shù)據(jù)的時(shí)間,1 分鐘足以。
GET /product/info/_search?scroll=DnF1ZXJ5VGhIbkXIdGNoAwAAAAAAAAAdFkEwRENOVTdnUUJPWVZUd1p2WE5hV2cAAAAAAAAAHhZBMERDTIU3Z1FCT1|WVHdadIhOYVdnAAAAAAAAAB8WQTBEQ05VN2dRQk9ZVIR3WnZYTmFXZw== { "query":{ "match_all":{ } }, "sort":["_doc"] } # 返回結(jié)果 { "_scroll_id": "DnF1ZXJ5VGhIbkXIdGNoAwAAAAAAAAAdFkEwRENOVTdnUUJPWVZUd1p2WE5hV2cAAAAAAAAAHhZBMERDTIU3Z1FCT1|WVHdadIhOYVdnAAAAAAAAAB8WQTBEQ05VN2dRQk9ZVIR3WnZYTmFXZw==", "took": 106, "_shards": { "total": 1, "successful": 1, "failed": 0 }, "hits": { "total": 22424, "max_score": 1.0, "hits": [{ "_index": "product", "_type": "info", "_id": "did-519392_pdid-2010", "_score": 1.0, "_routing": "519392", "_source": { .... } } ] } }
-
所有文檔獲取完畢之后,需要手動(dòng)清理掉 scroll_id 。雖然es 會(huì)有自動(dòng)清理機(jī)制,但是 srcoll_id 的存在會(huì)耗費(fèi)大量的資源來(lái)保存一份當(dāng)前查詢結(jié)果集映像,并且會(huì)占用文件描述符。所以用完之后要及時(shí)清理。使用 es 提供的 CLEAR_API 來(lái)刪除指定的 scroll_id。
# 刪掉指定的多個(gè) srcoll_id DELETE /_search/scroll -d { "scroll_id":[ "cXVlcnlBbmRGZXRjaDsxOzg3OTA4NDpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7" ] } # 刪除掉所有索引上的 scroll_id DELETE /_search/scroll/_all # 查詢當(dāng)前所有的scroll 狀態(tài) GET /_nodes/stats/indices/_search?pretty # 返回結(jié)果 { "cluster_name" : "200.200.107.232", "nodes" : { "SC4fYi0CT5mIp274ZgH_fg" : { "timestamp" : 1514346295736, "name" : "200.200.107.232", "transport_address" : "200.200.107.232:9300", "host" : "200.200.107.232", "ip" : [ "200.200.107.232:9300", "NONE" ], "indices" : { "search" : { "open_contexts" : 0, "query_total" : 975758, "query_time_in_millis" : 329850, "query_current" : 0, "fetch_total" : 217069, "fetch_time_in_millis" : 84699, "fetch_current" : 0, "scroll_total" : 5348, "scroll_time_in_millis" : 92712468, "scroll_current" : 0 } } } } }
基于 search_after 實(shí)現(xiàn)深度分頁(yè)
search_after 是 ES5.0 及之后版本提供的新特性,search_after 有點(diǎn)類似 scroll,但是和 scroll 又不一樣,它提供一個(gè)活動(dòng)的游標(biāo),通過(guò)上一次查詢最后一條數(shù)據(jù)來(lái)進(jìn)行下一次查詢。
search_after 分頁(yè)的方式和 scroll 有一些顯著的區(qū)別,首先它是根據(jù)上一頁(yè)的最后一條數(shù)據(jù)來(lái)確定下一頁(yè)的位置,同時(shí)在分頁(yè)請(qǐng)求的過(guò)程中,如果有索引數(shù)據(jù)的增刪改查,這些變更也會(huì)實(shí)時(shí)的反映到游標(biāo)上。
-
第一頁(yè)的請(qǐng)求和正常的請(qǐng)求一樣。
GET /order/info/_search { "size": 10, "query": { "match_all" : { } }, "sort": [ {"date": "asc"} ] } # 返回結(jié)果 { "_index": "zmrecall", "_type": "recall", "_id": "60310505115909", "_score": null, "_source": { ... "date": 1545037514 }, "sort": [ 1545037514 ] }
-
第二頁(yè)的請(qǐng)求,使用第一頁(yè)返回結(jié)果的最后一個(gè)數(shù)據(jù)的值,加上 search_after 字段來(lái)取下一頁(yè)。注意:使用 search_after 的時(shí)候要將 from 置為 0 或 -1。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-633825.html
curl -XGET 127.0.0.1:9200/order/info/_search { "size": 10, "query": { "match_all" : { } }, "search_after": [1463538857], # 這個(gè)值與上次查詢最后一條數(shù)據(jù)的sort值一致,支持多個(gè) "sort": [ {"date": "asc"} ] }
注意:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-633825.html
- 如果 search_after 中的關(guān)鍵字為654,那么654323的文檔也會(huì)被搜索到,所以在選擇 search_after 的排序字段時(shí)需要謹(jǐn)慎,可以使用比如文檔的id或者時(shí)間戳等。
- search_after 適用于深度分頁(yè)+ 排序,因?yàn)槊恳豁?yè)的數(shù)據(jù)依賴于上一頁(yè)最后一條數(shù)據(jù),所以無(wú)法跳頁(yè)請(qǐng)求。
- 返回的始終是最新的數(shù)據(jù),在分頁(yè)過(guò)程中數(shù)據(jù)的位置可能會(huì)有變更。這種分頁(yè)方式更加符合 moa 的業(yè)務(wù)場(chǎng)景。
到了這里,關(guān)于Elasticsearch 使用scroll滾動(dòng)技術(shù)實(shí)現(xiàn)大數(shù)據(jù)量搜索、深度分頁(yè)問(wèn)題 和 search的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!