Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 什么';在MongoDB上执行稠密_秩的最佳方法是什么?_Sql_Sql Server_Mongodb_Nosql - Fatal编程技术网

Sql 什么';在MongoDB上执行稠密_秩的最佳方法是什么?

Sql 什么';在MongoDB上执行稠密_秩的最佳方法是什么?,sql,sql-server,mongodb,nosql,Sql,Sql Server,Mongodb,Nosql,SQL Server和Oracle都有密集的功能。除其他外,这允许您获取记录的全局排名,同时仅返回这些记录的子集,例如: SELECT DENSE_RANK() OVER(ORDER BY SomeField DESC) SomeRank 在MongoDB中执行相同操作的最佳方法是什么?如果您的分数字段直接位于文档中,则密集排名就是文档按特定排序顺序的索引 假设您有一个游戏的分数集合,如: {user: "dcrosta", score: 10} {user: "someone", score

SQL Server和Oracle都有密集的功能。除其他外,这允许您获取记录的全局排名,同时仅返回这些记录的子集,例如:

SELECT DENSE_RANK() OVER(ORDER BY SomeField DESC) SomeRank

在MongoDB中执行相同操作的最佳方法是什么?

如果您的分数字段直接位于文档中,则密集排名就是文档按特定排序顺序的索引

假设您有一个游戏的分数集合,如:

{user: "dcrosta", score: 10}
{user: "someone", score: 18}
{user: "another", score: 5}
...
然后(假设您有一个关于分数的索引)要获得等级,您可以只查询按分数排序的等级(这里用pymongo语法显示):

如果您不熟悉Python,
enumerate
函数会创建一个迭代器,返回成对的(
index
元素


编辑:我假设您想要一个排名表——如果您正在寻找某个特定用户的排名,Richard的答案或类似的答案就是您想要的。

经过一些实验,我发现基于MapReduce构建排名函数是可能的,假设结果集可以容纳最大文档大小

例如,假设我有这样一个集合:

{ player: "joe", points: 1000, foo: 10, bar: 20, bang: "some text" }
{ player: "susan", points: 2000, foo: 10, bar: 20, bang: "some text" }
{ player: "joe", points: 1500, foo: 10, bar: 20, bang: "some text" }
{ player: "ben", points: 500, foo: 10, bar: 20, bang: "some text" }
...
我可以大致相当于一个稠密的_秩,如下所示:

var m = function() { 
  ++g_counter; 

  if ((this.player == "joe") && (g_scores.length != g_fake_limit)) { 
    g_scores.push({
      player: this.player, 
      points: this.points, 
      foo: this.foo,
      bar: this.bar,
      bang: this.bang,
      rank: g_counter
    });   
  }

  if (g_counter == g_final)
  {
    emit(this._id, g_counter);
  }
}}


var r = function (k, v) { }
var f = function(k, v) { return g_scores; }

var test_mapreduce = function (limit) {
  var total_scores = db.scores.count();

  return db.scores.mapReduce(m, r, {
    out: { inline: 1 }, 
    sort: { points: -1 }, 
    finalize: f, 
    limit: total_scores, 
    verbose: true,
    scope: {
      g_counter: 0, 
      g_final: total_scores, 
      g_fake_limit: limit, 
      g_scores:[]
    }
  }).results[0].value;
}
作为比较,以下是其他地方提到的“幼稚”方法:

var test_naive = function(limit) {
  var cursor = db.scores.find({player: "joe"}).limit(limit).sort({points: -1});
  var scores = [];

  cursor.forEach(function(score) {
    score.rank = db.scores.count({points: {"$gt": score.points}}) + 1;
    scores.push(score);
  });

  return scores;
}
我使用以下代码在MongoDB 1.8.2的单个实例上对这两种方法进行了基准测试:

var rand = function(max) {
  return Math.floor(Math.random() * max);
}

var create_score = function() {
  var names = ["joe", "ben", "susan", "kevin", "lucy"]
  return { player: names[rand(names.length)], points: rand(1000000), foo: 10, bar: 20, bang: "some kind of example text"};
}

var init_collection = function(total_records) {
  db.scores.drop();

  for (var i = 0; i != total_records; ++i) {
    db.scores.insert(create_score());
  }

  db.scores.createIndex({points: -1})
}


var benchmark = function(test, count, limit) {
  init_collection(count);

  var durations = [];
  for (var i = 0; i != 5; ++i) {
    var start = new Date;
    result = test(limit)
    var stop = new Date;

    durations.push(stop - start);
  }

  db.scores.drop();

  return durations;
}
虽然MapReduce的速度比我预期的要快,但对于更大的集合大小,这种天真的方法却一扫而光,尤其是在缓存预热之后:

> benchmark(test_naive, 1000, 50);
[ 22, 16, 17, 16, 17 ]
> benchmark(test_mapreduce, 1000, 50);
[ 16, 15, 14, 11, 14 ]
> 
> benchmark(test_naive, 10000, 50);
[ 56, 16, 17, 16, 17 ]
> benchmark(test_mapreduce, 10000, 50);
[ 154, 109, 116, 109, 109 ]
> 
> benchmark(test_naive, 100000, 50);
[ 492, 15, 18, 17, 16 ]
> benchmark(test_mapreduce, 100000, 50);
[ 1595, 1071, 1099, 1108, 1070 ]
> 
> benchmark(test_naive, 1000000, 50);
[ 6600, 16, 15, 16, 24 ]
> benchmark(test_mapreduce, 1000000, 50);
[ 17405, 10725, 10768, 10779, 11113 ]

因此,目前看来,天真的方法是可行的,尽管我有兴趣看看今年晚些时候随着MongoDB团队继续改进MapReduce性能,情况是否会有所改变。

感谢您的想法。不幸的是,这对我来说不起作用,因为我需要知道,例如,“dcrosta”的全局排名为“2”,即使我进行的查询遗漏了一个或多个其他文档。如果我真的可以得到作为结果的一部分返回的索引值,那将是非常棒的;然后我可以在分数上添加一个索引。“密集排名只是文档按一定排序顺序的索引”是不正确的。如果两行具有相同的
SomeField
,则它们将具有相同的密集秩,但它们将具有不同的索引。
densite_-rank
rank
窗口函数与
row_-number
窗口函数不同。
> benchmark(test_naive, 1000, 50);
[ 22, 16, 17, 16, 17 ]
> benchmark(test_mapreduce, 1000, 50);
[ 16, 15, 14, 11, 14 ]
> 
> benchmark(test_naive, 10000, 50);
[ 56, 16, 17, 16, 17 ]
> benchmark(test_mapreduce, 10000, 50);
[ 154, 109, 116, 109, 109 ]
> 
> benchmark(test_naive, 100000, 50);
[ 492, 15, 18, 17, 16 ]
> benchmark(test_mapreduce, 100000, 50);
[ 1595, 1071, 1099, 1108, 1070 ]
> 
> benchmark(test_naive, 1000000, 50);
[ 6600, 16, 15, 16, 24 ]
> benchmark(test_mapreduce, 1000000, 50);
[ 17405, 10725, 10768, 10779, 11113 ]