Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.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
Ruby MongodB—提高处理多个集合的速度_Ruby_Mongodb - Fatal编程技术网

Ruby MongodB—提高处理多个集合的速度

Ruby MongodB—提高处理多个集合的速度,ruby,mongodb,Ruby,Mongodb,我正在使用MongoDB和Ruby,使用mongogem 我有以下情况: 对于集合中的每个文档,例如coll1,请查看key1和key2 搜索另一个集合中的文档,例如coll2,其中包含key1和key2 如果存在匹配项,则在#1中引用的文档中添加在#2中获取的文档,并使用新键key3,其值应设置为key3 将更新的哈希插入新集合coll3 MongoDB的一般指导原则是在应用程序代码中处理交叉收集操作 因此,我做了以下工作: client = Mongo::Client.new([ '

我正在使用MongoDB和Ruby,使用
mongo
gem

我有以下情况:

  • 对于集合中的每个文档,例如
    coll1
    ,请查看
    key1
    key2
  • 搜索另一个集合中的文档,例如
    coll2
    ,其中包含
    key1
    key2
  • 如果存在匹配项,则在#1中引用的文档中添加在#2中获取的文档,并使用新键
    key3
    ,其值应设置为
    key3
  • 将更新的哈希插入新集合
    coll3
  • MongoDB的一般指导原则是在应用程序代码中处理交叉收集操作

    因此,我做了以下工作:

        client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => some_db, 
                                   :server_selection_timeout => 5)
        cursor = client[:coll1].find({}, { :projection => {:_id => 0} }) # exclude _id
        cursor.each do |doc|
            doc_coll2 = client[:coll2].find('$and' => [{:key1 => doc[:key1]}, {:key2 => doc[:key2] }]).limit(1).first # no find_one method
            if(doc_coll2 && doc[:key3])
                doc_coll2[:key3] = doc[:key3]
                doc_coll2.delete(:_id) # remove key :_id
                client[:coll3].insert_one(doc_coll2)
            end
        end
    
    这是可行的,但完成这项工作需要很多时间——在collection
    coll1
    中,每个文档大约需要250毫秒,或者大约15000条记录需要3600秒(1小时),这似乎是一个很大的工作量,可能与一次读取一个文档、执行签入应用程序代码,然后一次写入一个文档返回到新的集合有关

    有没有办法让这项工作做得更快?我现在的做法是正确的吗

    示例文档

    • coll1

      {
          "_id" : ObjectId("588610ead0ae360cb815e55f"),
          "key1" : "115384042",
          "key2" : "276209",
          "key3" : "10101122317876"
      }
      
    • coll2

      {
          "_id" : ObjectId("788610ead0ae360def15e88e"),
          "key1" : "115384042",
          "key2" : "276209",
          "key4" : 10,
          "key5" : 4,
          "key6" : 0,
          "key7" : "false",
          "key8" : 0,
          "key9" : "false"
      }
      
    • coll3

      {
          "_id" : ObjectId("788610ead0ae360def15e88e"),
          "key1" : "115384042",
          "key2" : "276209",
          "key3" : "10101122317876",
          "key4" : 10,
          "key5" : 4,
          "key6" : 0,
          "key7" : "false",
          "key8" : 0,
          "key9" : "false"
      }
      

      • 解决方案是使用聚合,并在一个查询中执行此操作:

        • 使用
          $lookup
        • 使用
          $unwind
        • 使用
          $redact
        • 使用
          $project
        • $out
        因此,问题是:

        db.coll1.aggregate([
            { "$lookup": { 
                "from": "coll2", 
                "localField": "key1", 
                "foreignField": "key1", 
                "as": "coll2_doc"
            }}, 
            { "$unwind": "$coll2_doc" },
            { "$redact": { 
                "$cond": [
                    { "$eq": [ "$key2", "$coll2_doc.key2" ] }, 
                    "$$KEEP", 
                    "$$PRUNE"
                ]
            }}, 
            { 
              $project: {
                 key1: 1, 
                 key2: 1, 
                 key3: 1, 
                 key4: "$coll2_doc.key4",
                 key5: "$coll2_doc.key5", 
                 key6: "$coll2_doc.key6", 
                 key7: "$coll2_doc.key7", 
                 key8: "$coll2_doc.key8", 
             key9: "$coll2_doc.key9",  
        
              } 
            }, 
            {$out: "coll3"} 
        ], {allowDiskUse: true} );
        
        db.coll3.find()
        将返回

        {
            "_id" : ObjectId("588610ead0ae360cb815e55f"),
            "key1" : "115384042",
            "key2" : "276209",
            "key3" : "10101122317876",
            "key4" : 10,
            "key5" : 4,
            "key6" : 0,
            "key7" : "false",
            "key8" : 0,
            "key9" : "false"
        }
        
        编辑:MongoDB 3.4解决方案 如果不想在
        $project
        阶段指定所有键,可以利用MongoDB 3.4中引入的两个新操作符
        $addFields
        $replaceRoot

        查询将变成:

        db.coll1.aggregate([
            { "$lookup": { 
                "from": "coll2", 
                "localField": "key1", 
                "foreignField": "key1", 
                "as": "coll2_doc"
            }}, 
            { "$unwind": "$coll2_doc" },
            { "$redact": { 
                "$cond": [
                    { "$eq": [ "$key2", "$coll2_doc.key2" ] }, 
                    "$$KEEP", 
                    "$$PRUNE"
                ]
            }}, 
            {$addFields: {"coll2_doc.key3": "$key3" }},
            {$replaceRoot: {newRoot: "$coll2_doc"}},
            {$out: "coll3"} 
        ], {allowDiskUse: true})
        

        在考虑了一段时间后,他意识到索引并没有被添加。添加索引可以将查询运行时间减少几个数量级

        要添加索引,请执行以下操作

        db.coll1.ensureIndex({"key1": 1, "key2": 1});
        db.coll2.ensureIndex({"key1": 1, "key2": 1});
        
        使用索引,整个查询运行时间是之前的1/10xxxxxx倍


        学习内容是,在处理大型数据集时,为
        find
        使用的字段编制索引,这本身就大大减少了查询运行时间。

        您能否提供coll1和coll2中的示例文档,以及预期结果的示例(要插入coll3中的文档)?为coll1添加了示例,coll2和coll3在
        $project:
        聚合的一部分中,我需要
        coll2
        中的所有键,加上
        coll1
        中的
        key3
        -有没有一种方法比必须指定coll2中的所有键更简单的方法来指定这一点-该集合有200个键:(我试过了,这很有效。但是关于速度的提高,我观察到的改进是,使用应用程序代码时,每小时15000个coll1文档,使用mongoDb aggregate时,每小时37000个coll1文档。这是否超出了预期范围,还是花费的时间太长?对我来说,与典型的RDBMS相比,这要长一个数量级。)就完成时间而言。@user3206440您提供的信息无法回答。这在很大程度上取决于您使用的硬件(磁盘类型、RAM…)还有你的收集内容。你应该看一下查询的结果,更好地了解发生了什么。了解你的观点,但是,在同一台机器上,性能数字是否与预期一致?