【问题标题】:Remove Duplicates from MongoDB从 MongoDB 中删除重复项
【发布时间】:2015-10-11 23:16:18
【问题描述】:

嗨,我在 mongodb(复制)中有大约 500 万个文档,每个文档 43 个字段。如何删除重复的文档。我试过了

db.testkdd.ensureIndex({
        duration  : 1 , protocol_type  : 1 , service  : 1 ,
        flag  : 1 , src_bytes  : 1 , dst_bytes  : 1 ,
        land  : 1 , wrong_fragment  : 1 , urgent  : 1 ,
        hot  : 1 , num_failed_logins  : 1 , logged_in  : 1 ,
        num_compromised  : 1 , root_shell  : 1 , su_attempted  : 1 ,
        num_root  : 1 , num_file_creations  : 1 , num_shells  : 1 ,
        num_access_files  : 1 , num_outbound_cmds  : 1 , is_host_login  : 1 ,
        is_guest_login  : 1 , count  : 1 ,  srv_count  : 1 ,
        serror_rate  : 1 , srv_serror_rate  : 1 , rerror_rate  : 1 ,
        srv_rerror_rate  : 1 , same_srv_rate  : 1 , diff_srv_rate  : 1 ,
        srv_diff_host_rate  : 1 , dst_host_count  : 1 , dst_host_srv_count  : 1 ,
        dst_host_same_srv_rate  : 1 , dst_host_diff_srv_rate  : 1 ,
        dst_host_same_src_port_rate  : 1 ,  dst_host_srv_diff_host_rate  : 1 ,
        dst_host_serror_rate  : 1 , dst_host_srv_serror_rate  : 1 ,
        dst_host_rerror_rate  : 1 , dst_host_srv_rerror_rate  : 1 , lable  : 1 
    },
    {unique: true, dropDups: true}
)

运行此代码我得到一个错误 "errmsg" : "namespace name generated from index ..

{
    "ok" : 0,
    "errmsg" : "namespace name generated from index name \"project.testkdd.$duration_1_protocol_type_1_service_1_flag_1_src_bytes_1_dst_bytes_1_land_1_wrong_fragment_1_urgent_1_hot_1_num_failed_logins_1_logged_in_1_num_compromised_1_root_shell_1_su_attempted_1_num_root_1_num_file_creations_1_num_shells_1_num_access_files_1_num_outbound_cmds_1_is_host_login_1_is_guest_login_1_count_1_srv_count_1_serror_rate_1_srv_serror_rate_1_rerror_rate_1_srv_rerror_rate_1_same_srv_rate_1_diff_srv_rate_1_srv_diff_host_rate_1_dst_host_count_1_dst_host_srv_count_1_dst_host_same_srv_rate_1_dst_host_diff_srv_rate_1_dst_host_same_src_port_rate_1_dst_host_srv_diff_host_rate_1_dst_host_serror_rate_1_dst_host_srv_serror_rate_1_dst_host_rerror_rate_1_dst_host_srv_rerror_rate_1_lable_1\" is too long (127 byte max)",
    "code" : 67
}

如何解决这个问题?

【问题讨论】:

    标签: mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    从 MongoDB 2.6 和 removed in MongoDB 3.0 开始,用于创建索引的 "dropDups" 语法已被“弃用”。在大多数情况下使用它不是一个好主意,因为“删除”是任意的,并且可以删除任何“重复”。这意味着被“删除”的内容可能不是您真正想要删除的内容。

    无论如何,您遇到了“索引长度”错误,因为此处的索引键值会更长,这是允许的。一般来说,在任何正常的应用程序中,您都不是“打算”索引 43 个字段的。

    如果您想从集合中删除“重复项”,那么最好的办法是运行聚合查询以确定哪些文档包含“重复”数据,然后在该列表中循环删除“除一个之外的所有”已经“唯一的”_id 目标集合中的值。这可以通过"Bulk" 操作来完成,以获得最大效率。

    注意:我确实很难相信您的文档实际上包含 43 个“唯一”字段。 “您所需要的一切” 很可能只是识别那些使文档“唯一”的字段,然后按照以下概述的过程进行操作:

    var bulk = db.testkdd.initializeOrderedBulkOp(),
        count = 0;
    
    // List "all" fields that make a document "unique" in the `_id`
    // I am only listing some for example purposes to follow
    db.testkdd.aggregate([
        { "$group": {
            "_id": {
               "duration" : "$duration",
              "protocol_type": "$protocol_type", 
              "service": "$service",
              "flag": "$flag"
            },
            "ids": { "$push": "$_id" },
            "count": { "$sum": 1 }
        }},
        { "$match": { "count": { "$gt": 1 } } }
    ],{ "allowDiskUse": true}).forEach(function(doc) {
        doc.ids.shift();     // remove first match
        bulk.find({ "_id": { "$in": doc.ids } }).remove();  // removes all $in list
        count++;
    
        // Execute 1 in 1000 and re-init
        if ( count % 1000 == 0 ) {
           bulk.execute();
           bulk = db.testkdd.initializeOrderedBulkOp();
        }
    });
    
    if ( count % 1000 != 0 ) 
        bulk.execute();
    

    如果您的 MongoDB 版本“低于”2.6 并且没有批量操作,那么您也可以尝试在循环内使用标准 .remove()。还要注意.aggregate() 不会在此处返回游标,并且循环必须更改为:

    db.testkdd.aggregate([
       // pipeline as above
    ]).result.forEach(function(doc) {
        doc.ids.shift();  
        db.testkdd.remove({ "_id": { "$in": doc.ids } });
    });
    

    但请务必仔细查看您的文档,并且仅“仅”包含您希望成为_id 分组一部分的“唯一”字段。否则,您最终什么都不会删除,因为那里没有重复项。

    【讨论】:

    • @mohamedzajith 好吧,错误实际上是在告诉你该怎么做。将“allowDiskUse”添加到管道中。这是用聚合方法记录的。我还建议您“仍然”传递比实际构成“独特”组合的字段更多的字段。
    • 如何在mongo shell中添加allowDiskUse
    • @mohamedzajith documentation 中有明确的示例用于聚合选项。它们在管道参数数组之后指定。上面包含的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    相关资源
    最近更新 更多