使用elasticsearch去做翻页功能的时候,会考虑到两种实现方法:如题中的pagination和scroll。
pagination
假设我们要拿头十条数据
//from:开始拿数据的索引值,默认值为0
//size:获取的数据量,默认值为10条
client.search({
index:index,
type:type,
from:0,
size:10
},(res)=>{
console.log(res.hits.hits)
})
官网文档里有这么一句话:
Results are sorted before being returned.
我猜测这句话表明了每次获取的数据都是实时的,经验证,我的猜测是成立的。
但是这种实时用于移动端上拉加载时,就会出现以下弊端
1.插入情景
假设第一页获取了10条数据
而在你准备获取第二页前,有人插入了1条数据
此时你再从11开始拿数据就会重复拿到第一页的第10条
2.删除情景
一样假设第一页获取了10条数据
而在你准备获取第二页前,有人删除了第一页1条数据
此时你再从11开始拿数据就会漏掉原本在第二页的第一条数据
elasticsearch是采用分布式存储的。现在我们假设这个index中存在5个碎片,若是要从这个index中拿取10条数据,就需要在每个碎片中拿取头10条数据,然后在这50条数据中再排序选取头十条。
可想而知,在分布式系统中,数据量越大,排序成本越大。所以官网建议:每次搜索的数据量最好不要超过1000条
小结:pagination比较适合用于pc端的分页
scroll
假设我们要拿到所有title为test的数据
//scroll:scroll_id存活时长
var allTitles = [];
client.search({
index:index,
type:type,
scroll:'30s',
q: 'title:test'
},function getMoreUntilDone(error, response)=>{
response.hits.hits.forEach(function (hit) {
allTitles.push(hit.fields.title);
});
//直到拿到所有title为test的数据,才停止scroll
if (response.hits.total !== allTitles.length) {
client.scroll({
scrollId: response._scroll_id,
scroll: '30s'
}, getMoreUntilDone);
} else {
console.log('every "test" title', allTitles);
}
})
scroll的出现是为了解决逐步加载大量数据这个功能点,所以并不具备实时性。数据映射会在初始化search的时候完成。所以在scroll_id失效之前(或重新初始化search)之前,别人的修改对你获取的数据不会生效。
小结:scroll比较适合用于移动端的下拉加载,虽然scroll_id具有存活时长,但是在失效时,可以重新获取。
写在最后
pagination文档、scroll文档、scroll例子