Удаление дубликатов записей с помощью MapReduce - PullRequest
7 голосов
/ 03 апреля 2011

Я использую 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();

Ответы [ 4 ]

2 голосов
/ 03 апреля 2011

В mongodb вы можете использовать запрос для ограничения документов, которые передаются для отображения.Вы, вероятно, хотите сделать это для тех, кто вас не волнует.Тогда в функции уменьшения вы можете игнорировать дубликаты и возвращать только одну из документов для каждого дублирующего ключа.Если вы просто хотите найти дубликаты и удалить все, кроме одного, то вы можете просто создать уникальный индекс для этого поля и использовать опцию dropDups;В процессе создания индекса будут удалены дубликаты документов.Сохранение индекса гарантирует, что это больше не повторится.

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

2 голосов
/ 03 апреля 2011

Я не использовал mongoDB, но я использовал mapreduce.Я думаю, что вы находитесь на правильном пути с точки зрения функций mapreduce.Чтобы исключить 0 и пустые строки, вы можете добавить проверку в саму функцию карты ... что-то вроде

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

И уменьшение должно возвращать пары ключ-значение.Таким образом, это должно быть:

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

После этого у вас должен быть набор пар ключ-значение в выводе, так что ключом является MlsId, а значением является число thimes, в которых происходит этот конкретный идентификатор.Я не уверен насчет части db.drop ().Как вы указали, он, скорее всего, удалит все MlsIds вместо того, чтобы удалять только дубликаты.Чтобы обойти это, возможно, вы можете сначала вызвать drop (), а затем заново создать MlsId.Будет ли это работать для вас?

0 голосов
/ 17 февраля 2014

Вот как я следую за ответом @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
});
0 голосов
/ 12 апреля 2013

Вы можете использовать операцию агрегирования для удаления дубликатов. Расслабьтесь, представьте фиктивную стадию $ 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'
           }
         }
       }
}
]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...