CouchDB中的无状态分页?
我看到的关于CouchDB分页的研究大多建议,你需要先从视图中取出前十个(或者任意数量的)项目,然后记录最后一个文档的ID,并把它传递到下一页。不过,我觉得这种方法有几个明显的问题。
- 这种方法让你无法在页面之间随意跳转(比如如果有人直接想去第100页,你就得先查询第2到第99页的数据,才能知道怎么加载第100页)。
- 它需要在不同的页面之间传递可能很多的状态信息。
- 编写代码时也比较困难。
不幸的是,我的研究显示,使用skip
在处理5000条记录或更多的数据集时会显著变慢,一旦数据量真的很大(比如要去第20000页,每页10条记录,大约需要20秒),那就会变得非常糟糕(确实有这么大的数据集在实际应用中)。所以这并不是一个可行的选项。
所以,我想问的是,有没有一种高效的方法可以在CouchDB中分页查看结果,能够从任意页面获取所有项目?(我在使用couchdb-python,但希望这与客户端无关。)
2 个回答
我们通过使用CouchDB Lucene来解决这个搜索列表的问题。现在的0.6版本快照已经足够稳定,建议你试试看:
我刚接触CouchDB,但我觉得我可以提供一些帮助。我在《CouchDB: The Definitive Guide》中读到以下内容:
链表风格的分页有一个缺点,就是... 跳转到特定页面并不太有效... 如果你真的需要在所有文档中跳转到某一页... 你仍然可以保持一个整数值的索引作为视图索引,并采用混合的方法来解决分页问题。
— http://books.couchdb.org/relax/receipts/pagination
如果我理解得没错,你的情况可以这样处理:
- 在你的文档集中嵌入一个数字序列。
- 将这个数字序列提取到一个数字视图索引中。
- 用数学运算来计算你想要的页面的起始和结束数字键。
在第一步中,你需要在文档中添加一个类似“page_seq”的字段。我没有具体的建议来获取这个数字,也想知道大家的看法。为了让这个方案有效,它必须对每个新记录增加1,所以关系数据库的序列可能不适用(我知道的那些可能会跳过数字)。
在第二步中,你需要写一个视图,使用类似这样的映射函数(用Javascript):
function(doc):
emit(doc.page_seq, doc)
在第三步中,你的查询可以写成这样(假设page_seq和页面编号序列从1开始):
results = db.view("name_of_view")
page_size = ... # say, 20
page_no = ... # 1 = page 1, 2 = page 2, etc.
begin = ((page_no - 1) * page_size) + 1
end = begin + page_size
my_page = results[begin:end]
然后你就可以遍历my_page了。
这个方法的一个明显缺点是,page_seq假设你没有对视图的数据集进行过滤,如果你试图用任意查询来实现这个功能,你会很快遇到问题。
欢迎大家提出意见或改进建议。