編程界的小學生
一、分頁API
1、api
from:從第幾條開始
size:每頁幾條
2、demo
2.1、查詢前兩條數據
GET /_search?size=2
或
GET /_search?from=0&size=2
2.2、查詢第50~60條數據
GET /_search?from=50&size=10
二、deep paging
1、描述
就是深度分頁,假設有6w條數據平分到了3個shard中,假設需求是分頁,數據太多了,要查第1000頁的數據,假設每頁10條,第1000頁的數據也就是第1w條。由於6w條數據,3個shard,所以大約每個shard上2w條數據。那麼我們客觀的認爲應該是協調節點從三個shard中分別拿出10條數據(第10001到10010這十條),然後再協調節點中將這30條數據根據規則獲取想要的前10條。但是我們的想法很天真,實際ES的做法是將三個shard上的1~10010條數據分別返回給協調節點,也就是協調節點最終的結果是30030條數據,在這30030條數據的基礎上進行按照規則(比如先排序然後再分頁取前10)返回給客戶端,所以造成了性能的浪費和瓶頸所在。
2、圖解
三、scroll解決方案
1、場景
就跟js的懶加載一樣,滾動加載。也可以用於解決深度分頁問題。
2、原理
scroll搜索會在第一次搜索的時候,保存一個當時的試圖快照。也就是保存完快照後之後的更改都不會對這個快照的數據產生影響,你改你的,我查的還是老的。
默認採用基於_doc的創建時間來排序,不使用_score進行排序的方式,性能較高。
3、用法
3.1、數據準備
PUT /product/_doc/1
{
"name": "xiaomi shouji",
"desc": "niubi quanwangtong",
"tags": ["niubi", "quanwangtong", "xiaomi", "shouji"]
}
PUT /product/_doc/2
{
"name": "huawei shouji",
"desc": "4G 5G",
"tags": ["shouji"]
}
PUT /product/_doc/3
{
"name": "xiaomi shouhuan",
"desc": "quanzidong",
"tags": ["shengdian", "xiaomi", "shouji"]
}
3.2、scroll api
GET /product/_search?scroll=1m
{
"query": {
"match_all": {}
},
"size": 1
}
返回結果
{
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAQoAWOWV3WnBTMVNSNFc1ZXAzeGxlWGJ1UQ==",
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "product",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "xiaomi shouji",
"desc" : "niubi quanwangtong",
"tags" : [
"niubi",
"quanwangtong",
"xiaomi",
"shouji"
]
}
}
]
}
}
獲取的結果會有一個scroll_id,下一次在發送scroll請求時,必須帶上這個scroll_id,因爲只有這樣,纔會去查詢上一次scroll生成的快照。
GET /_search/scroll
{
"scroll": "1m",
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAQoAWOWV3WnBTMVNSNFc1ZXAzeGxlWGJ1UQ=="
}
返回結果
{
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAQoAWOWV3WnBTMVNSNFc1ZXAzeGxlWGJ1UQ==",
"took" : 1,
"timed_out" : false,
"terminated_early" : true,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "product",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "huawei shouji",
"desc" : "4G 5G",
"tags" : [
"shouji"
]
}
}
]
}
}
可以發現這個數據是id=2的。以此類推,拿着id=2的scroll_id去查會查到id=3的。但是這期間有新的數據插入進來了,是不會被查到的,因爲查的是快照。
3.3、補充說明
- 指定的1m代表的是持續滾動時間,如果過了1分鐘,還沒有查詢下一頁,那麼這個scroll_id就會被es清理掉。就無法用這個scroll_id去查數據。還可以指定1s,代表1秒鐘。
- 刪除scroll_id
DELETE /_search/scroll/DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAQoAWOWV3WnBTMVNSNFc1ZXAzeGxlWGJ1UQ==
- 刪除所有scroll_id
DELETE /_search/scroll/_all
四、優化
- 當你的數據分頁超過5000的時候,不用用deep paging
也就是比如1w條數據,假設每頁10條,1000頁。這時候第5000條數據在第500頁,正常人你去百度搜索,你也就點前幾頁就完了,誰會點到幾百頁。但是不能排除這種情況,所以建議前N頁採取
from/size
,在之後就採取scroll,但是scroll不支持上一頁的操作,看產品需求。
- 返回結果500以下爲最佳
避免每頁返回幾千條數據。