AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 4859
Accepted
kgriffs
kgriffs
Asked: 2011-08-20 22:07:37 +0800 CST2011-08-20 22:07:37 +0800 CST 2011-08-20 22:07:37 +0800 CST

Existe alguma maneira de executar com eficiência o equivalente a DENSE_RANK no MongoDB?

  • 772

SQL Server e Oracle têm funções DENSE_RANK. Existe uma maneira de fazer algo semelhante no MongoDB sem precisar recorrer ao MapReduce? Em outras palavras, suponha que você tenha uma cláusula de seleção T-SQL como esta:

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

Qual é a melhor maneira de fazer a mesma coisa no MongoDB?

(Observação: esta é uma repostagem da pergunta do MongoDB aqui . Espero obter mais feedback dos DBAs...)

sql-server nosql
  • 2 2 respostas
  • 1294 Views

2 respostas

  • Voted
  1. Best Answer
    Richard
    2011-08-21T05:09:37+08:002011-08-21T05:09:37+08:00

    O MongoDB não tem nenhum conceito de classificação. O mais próximo que encontrei vem daqui :

    Aqui estão alguns dados de exemplo:

     > db.scoreboard.find()`
     { "_id" : ObjectId("4d99f71450f0ae2165669ea9"), "user" : "dave", "score" : 4 }
     { "_id" : ObjectId("4d99f71b50f0ae2165669eaa"), "user" : "steve", "score" : 5 }`
     { "_id" : ObjectId("4d99f72350f0ae2165669eab"), "user" : "tom", "score" : 3 }
    

    Primeiro, encontre a pontuação do usuário "dave":

     db.scoreboard.find({ user : "dave" }, { score : 1 }) { "_id" : ObjectId("4d99f71450f0ae2165669ea9"), "score" : 4 }
    

    Em seguida, conte quantos usuários têm uma pontuação mais alta:

     db.scoreboard.find({ score : { $gt : 4 }}).count() 
     1
    

    Como há 1 pontuação mais alta, a classificação de Dave é 2 (basta adicionar 1 à contagem de pontuações mais altas para obter a classificação).

    Obviamente, isso está longe de ser o ideal. No entanto, o MongoDB simplesmente não possui nenhum tipo de funcionalidade para isso, pois simplesmente não foi projetado para esse tipo de consulta.

    • 5
  2. kgriffs
    2011-08-25T05:29:41+08:002011-08-25T05:29:41+08:00

    Depois de algumas experiências, descobri que é possível construir uma função de classificação com base no MapReduce, assumindo que o conjunto de resultados pode caber no tamanho máximo do documento.

    Por exemplo, suponha que eu tenha uma coleção como esta:

    { 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" }
    ...
    

    Posso executar o equivalente aproximado de um DENSE_RANK assim:

    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;
    }
    

    Para comparação, aqui está a abordagem "ingênua" mencionada em outro lugar:

    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;
    }
    

    Eu comparei ambas as abordagens em uma única instância do MongoDB 1.8.2 usando o seguinte código:

    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;
    }
    

    Embora o MapReduce tenha sido mais rápido do que eu esperava, a abordagem ingênua o surpreendeu para tamanhos de coleção maiores, especialmente depois que o cache foi aquecido:

    > 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 ]
    

    Então, por enquanto, parece que a abordagem ingênua é o caminho a percorrer, embora eu esteja interessado em ver se a história muda ainda este ano, à medida que a equipe do MongoDB continua melhorando o desempenho do MapReduce.

    • 5

relate perguntas

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

  • Quais são as diferenças entre o NoSQL e um RDBMS tradicional?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve