【问题标题】:Removing duplicate records using MapReduce使用 MapReduce 删除重复记录
【发布时间】:2011-07-28 16:26:06
【问题描述】:

我正在使用 MongoDB,需要删除重复记录。我有一个看起来像这样的列表集合:(简化)

[
  { "MlsId": "12345"" },
  { "MlsId": "12345" },
  { "MlsId": "23456" },
  { "MlsId": "23456" },
  { "MlsId": "0" },
  { "MlsId": "0" },
  { "MlsId": "" },
  { "MlsId": "" }
]

如果 MlsId 不是“”或“0”并且另一个列表具有相同的 MlsId,则该列表是重复的。所以在上面的例子中,需要删除第 2 和第 4 条记录。

如何找到所有重复的列表并将其删除?我开始查看 MapReduce,但找不到适合我的示例。

这是我目前所拥有的,但它不检查 MlsId 是“0”还是“”:

m = function () { 
    emit(this.MlsId, 1); 
} 

r = function (k, vals) { 
   return Array.sum(vals); 
} 

res = db.Listing.mapReduce(m,r); 
db[res.result].find({value: {$gt: 1}}); 
db[res.result].drop();

【问题讨论】:

    标签: mongodb mapreduce


    【解决方案1】:

    这就是我按照@harri 回答删除重复项的方式:

    //contains duplicated documents id and numeber of duplicates 
    db.createCollection("myDupesCollection")
    res = db.sampledDB.mapReduce(m, r, { out : "myDupesCollection" });
    
    // iterate through duplicated docs and remove duplicates (keep one) 
    db.myDupesCollection.find({value: {$gt: 1}}).forEach(function(myDoc){
        u_id = myDoc._id.MlsId;
        counts =myDoc.value;
        db.sampledDB.remove({MlsId: u_id},counts-1); //if there are 3 docs, remove 3-1=2 of them
    });
    

    【讨论】:

      【解决方案2】:

      您可以使用聚合操作来删除重复项。放松,引入一个虚拟的 $group 和 $sum 阶段并忽略下一个阶段的计数。像这样的,

      db.myCollection.aggregate([
       {
           $unwind: '$list'
       },
       {
          $group:{
         '_id':
             {
               'listing_id':'$_id', 'MlsId':'$list.MlsId'
             },
                'count':
             {
                '$sum':1
             }
            }
      },
      {
            $group:
             {
              '_id':'$_id.listing_id',
              'list':
               {
                '$addToSet':
                 {
                  'MlsId':'$_id.MlsId'
                 }
               }
             }
      }
      ]);
      

      【讨论】:

        【解决方案3】:

        在 mongodb 中,您可以使用查询来限制传入用于映射的文档。你可能想为那些你不关心的人这样做。然后在 reduce 函数中,您可以忽略 dups,只为每个重复键返回一个文档。

        不过,我对你的目标有点困惑。如果您只想查找重复项并删除除其中一个之外的所有重复项,那么您可以在该字段上创建一个唯一索引并使用 dropDups 选项;创建索引的过程将删除重复的文档。保留索引将确保它不会再次发生。

        http://www.mongodb.org/display/DOCS/Indexes#Indexes-DuplicateValues

        【讨论】:

        • 如上所述,我不能将唯一索引与 dropDups 一起使用,因为当我想保留所有列表时,它只会保留一个值为“”的列表和一个值为“0”的列表其中。
        【解决方案4】:

        我没有使用过 mongoDB,但我使用过 mapreduce。我认为您在 mapreduce 功能方面走在正确的轨道上。要排除 he 0 和空字符串,您可以在 map 函数本身中添加一个检查.. 类似于

        m = function () { 
          if(this.MlsId!=0 && this.MlsId!="") {    
            emit(this.MlsId, 1); 
          }
        } 
        

        reduce 应该返回键值对。所以应该是:

        r = function(k, vals) {
          emit(k,Arrays.sum(vals);
        }
        

        在此之后,您应该在输出中有一组键值对,其中键是 MlsId,值是此特定 ID 出现的次数。我不确定 db.drop() 部分。正如您所指出的,它很可能会删除所有 MlsId,而不是仅删除重复的 MlsId。为了解决这个问题,也许你可以先调用 drop() 然后重新创建 MlsId 一次。这对你有用吗?

        【讨论】:

        • 这个你可能答不上来,但是如果我声明m和r函数然后执行mapReduce函数然后运行db[res.result].drop();命令,它会删除所有列表还是仅删除重复的列表?我不懂 mapReduce 和 emit 所以不知道这一切是如何工作的......
        • 我对reduce()做了一个小的修正。我不确定 hoe db.drop() 是否有效,但是是的,我想它会删除为该特定 ID 输入的所有内容。但我希望你对 map-reduce 部分的理解很清楚。虽然我不确定 mongodb 语法.. 看看我是否能弄清楚..
        • 您可以尝试使用此处提到的删除重复选项添加索引:mongodb.org/display/DOCS/Indexes 它会自动删除重复值。另一种方法是先 drop() 所有值,然后添加一个值。
        • 我不能使用唯一索引,因为在我的情况下,会有多个 MlsId 为“”或“0”的有效列表。如果我要使用 MapReduce 路由,那么我想我需要知道如何只删除重复记录,而不是全部。
        • 我想了想,决定只在地址属性而不是 mlsid 上使用唯一索引,因为有些列表没有 mlsid,但每个列表都有一个地址。感谢您的帮助!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-17
        • 2016-01-07
        • 1970-01-01
        • 2012-05-11
        • 1970-01-01
        相关资源
        最近更新 更多