给出了gameim-sample示例的以下视图:
function (doc, meta) {
if (doc.jsonType == "player" && doc.experience) {
emit([doc.experience,meta.id], doc.id);
}
}
我想查询仅属于特定组的用户的排行榜(分组数据在外部系统中维护)。
例如如果视图有用户"橙","紫","绿","蓝"和"红色"我希望排行榜能够给我排名只有" orange"和"紫色"无需查询各自的当前经验值。
...view/leaderboard?keys=[[null,"orange"],[null,"purple"]
以下工作正常,但需要额外的查询才能找到" orange"的体验点。和"紫色"预先。但是,由于显而易见的原因,这不会扩展。
...view/leaderboard?keys=[[1,"orange"],[5,"purple"]
提前致谢!
答案 0 :(得分:0)
首先,您必须记住,特别是Couchbase,其优势在于超快速存储和检索记录。后来添加了指标,作为一种使存储更有用且更不容易出错的方法(将它们更多地视为自动化库存),它们的设计确实限制了您摆脱SQL式思维。您上面的查询是一个很好的例子:
select *
from leaderboard
where id in ('orange','purple')
order by experience
这是一次性检索,计算和过滤。这正是NoSql数据库优化不要做的事情(相反,SQL数据库 ,这往往使它们无可救药地复杂,但这是另一个主题)。
因此,这导致SQL与NoSQL数据库之间的主要区别:NoSql针对存储进行了优化,而SQL针对查询进行了优化。结合起来,它可以调整一个人如何思考数据库的角色,在我看来,这应该比前者更多。
Couchbase的创建者最初完全专注于数据库的存储方面。但是,当您知道存储的内容时,存储会更有意义,并且索引稍后会作为一项功能添加(最初您必须跟踪自己的内容 - 这不是很有趣!)他们还添加了{ {1}}利用CB同时存储和检索大量记录的能力。这些功能都不是真正意图解决复杂的查询问题(即使这个查询很简单,因此这是一个完美的例子)。这是应用程序逻辑的功能。
所以,现在问你的问题。查询本身出现是一个简单的,事实确实如此。然而,
map-reduce
实际上并不简单。它是一个2层深度查询,因为您对排行榜的定义意味着从最大到最小的玩家体验的排序列表。因此,展开的此查询将变为:
select * from leaderboard
Couchbase在索引机制中原生支持上述内容(请记住,它会清点您的对象),并且您已在问题中准确描述了如何利用视图来实现此输出。 Couchbase不支持的是第三级查询,它代表您的select * from players order by experience desc
子句。通常,Couchbase中的where
在视图“map”定义或索引选择参数中执行。你不能在“map”中这样做,因为你并不总是想要相同的选择,并且你不能在索引选择参数中这样做,因为索引首先按经验级别排序。
我们假设您正在向网页上的用户显示此内容。您可以通过按原样提取数据并丢弃不需要的值来轻松实现此过滤器客户端(或在Web服务中)。当用户向下滚动(或点击更多页面或其他内容)时,请使用where
和limit
参数询问更多内容。
反转索引的顺序,先按“组”(又名颜色)排序,然后按经验级别排序。运行单独的查询以选择每种颜色的顶级“N”个用户,然后在客户端进行合并和排序。这需要更长时间才能预先加载,但如果您因此需要,可以为您提供更大的内存数据集。如果您的类别分布非常不均匀,则此方法可能无法正常工作,在这种情况下,需要定制“N”以匹配类别中的统计分布。
一个离别的想法是,NoSql数据库被设计用于处理高度动态的数据集。这需要一些统计思考,因为不再有一个“正确”的答案。会出现一定程度的不一致和错误(正如现实世界中一样)。您不能指望NoSql数据库返回完美的查询结果 - 因为没有完美。你必须满足于“足够好” - 这通常比所需要的要好得多。