2015-01-23 2 views
4

У меня есть огромная коллекция с 3 миллиардами документов. Каждый документ выглядит следующим образом:Mongodb отличная совокупность 3 миллиардов документов

"_id" : ObjectId("54c1a013715faf2cc0047c77"), 
"service_type" : "JE", 
"receiver_id" : NumberLong("865438083645"), 
"time" : ISODate("2012-12-05T23:07:36Z"), 
"duration" : 24, 
"service_description" : "NQ", 
"receiver_cell_id" : null, 
"location_id" : "658_55525", 
"caller_id" : NumberLong("475035504705") 

Я хотел бы получить список различных пользователей (они должны, по крайней мере, появляются один раз в качестве вызывающего абонента «caller_id»), их подсчета (сколько раз каждый пользователь появился в как абонент или получатель), так и подсчет местоположений, если они являются абонентами (т. е. счетчик для каждого location_id для каждого пользователя).

Я хочу, чтобы в итоге следующее:

"number_of_records" : 20, 
"locations" : [{location_id: 658_55525, count:5}, {location_id: 840_5425, count:15}], 
"user" : NumberLong("475035504705") 

Я попытался Описанное решение here и here, но они не являются достаточно эффективными (очень медленно). Каким будет эффективный способ достичь этого?

+0

Когда вы говорите 'очень медленно', как медленно ты говоришь? Как долго вы его запускали? –

+2

Можете ли вы отправить оба решения, которые вы пробовали, и какой из них лучше? Это было бы полезно, так как вы можете не захотеть получить то же самое, что вы пробовали в качестве ответа. – BatScream

+1

В настоящее время недостаточно информации, чтобы угадать, как ваши ограничения ресурсов могут влиять на производительность.Какое развертывание (автономное/реплика/оштрафованное) и ресурсы сервера (ram/disk/cpu) у вас есть, и каков общий размер данных? Можете ли вы также включить индексы для этой коллекции? И наконец, какую конкретную версию MongoDB и O/S вы используете? – Stennie

ответ

2

Использование агрегации для вашего результата:

db.<collection>.aggregate([ 
    { $group : { _id : { user: "$caller_id", localtion: '$location_id'} , count : { $sum : 1} } }, 
    { $project : { _id : 0, _id : '$_id.user', location : '$_id.localtion', count : '$count' } }, 
    { $group : { _id : '$_id', 'locations' : { $push : { location_id : '$location', count : '$count' } }, number_of_records : {$sum : '$count'} } }, 
    { $project : { _id : 0, user : '$_id', locations : '$locations', number_of_records : '$number_of_records'} }, 
    { $out : 'outputCollection'}, 
]) 

Выход будет:

{ 
    "0" : { 
     "locations" : [ 
      { 
       "location_id" : "840_5425", 
       "count" : 8 
      }, 
      { 
       "location_id" : "658_55525", 
       "count" : 5 
      } 
     ], 
     "number_of_records" : 13, 
     "user" : NumberLong(475035504705) 
    } 
} 

Update с помощью allowDiskUse:

var pipe = [ 
    { $group : { _id : { user: "$caller_id", localtion: '$location_id'} , count : { $sum : 1} } }, 
    { $project : { _id : 0, _id : '$_id.user', location : '$_id.localtion', count : '$count' } }, 
    { $group : { _id : '$_id', 'locations' : { $push : { location_id : '$location', count : '$count' } }, number_of_records : {$sum : '$count'} } }, 
    { $project : { _id : 0, user : '$_id', locations : '$locations', number_of_records : '$number_of_records'} }, 
    { $out : 'outputCollection'}, 
]; 

db.runCommand(
    { aggregate: "collection", 
    pipeline: pipe, 
    allowDiskUse: true 
    } 
) 
+0

Я хотел бы иметь коллекцию с указанным выходом для всех пользователей. Ваше решение будет иметь его только для одного пользователя (т. Е. 475035504705), правильно? – amaatouq

+0

удалите строку соответствия $. но ни один db не может быстро выполнить этот запрос с записью 3B. – Disposer

+0

Я попробую это .. Это нормально, если это займет несколько дней! так как это одноразовая вещь! – amaatouq

1

A map-reduce Решение было бы более подходящим здесь, а не концом aggregation, просто потому, Если бы вы могли выявить решение для агрегации с помощью одного разворота, это было бы так. Но нижеследующее решение для уменьшения карты - это один из способов сделать это, хотя вам нужно будет измерить время его работы над большими данными и посмотреть, будет ли оно работать для вас.

map функции:

var map = function(){ 
    emit(this.caller_id, 
     {locs:[{"location_id":this.location_id,"count":1}]}); 
} 

reduce функции:

var reduce = function(key,values){ 
    var result = {locs:[]}; 
    var locations = {}; 
    values.forEach(function(value){ 
     value.locs.forEach(function(loc){ 
       if(!locations[loc.location_id]){ 
        locations[loc.location_id] = loc.count; 
       } 
       else{ 
        locations[loc.location_id]++; 
       } 
     }) 
    }) 
    Object.keys(locations).forEach(function(k){ 
     result.locs.push({"location_id":k,"count":locations[k]}); 
    }) 
    return result; 
} 

finalize функции:

var finalize = function(key,value){ 
    var total = 0; 
    value.locs.forEach(function(loc){ 
     total += loc.count; 
    }) 
    return {"total":total,"locs":value.locs}; 
} 

Вызов Карта-свертка:

db.collection.mapReduce(map,reduce,{"out":"t1","finalize":finalize}); 

Агрегатирование результата, как только карта-редукция производит свой выход.

db.t1.aggregate([ 
{$project:{"_id":0, 
      "number_of_records":"$value.total", 
      "locations":"$value.locs","user":"$_id"}} 
]) 

образца о/р:

{ 
     "number_of_records" : 3, 
     "locations" : [ 
       { 
         "location_id" : "658_55525", 
         "count" : 1 
       }, 
       { 
         "location_id" : "658_55525213", 
         "count" : 2 
       } 
     ], 
     "user" : 2 
} 
{ 
     "number_of_records" : 1, 
     "locations" : [ 
       { 
         "location_id" : "658_55525", 
         "count" : 1 
       } 
     ], 
     "user" : NumberLong("475035504705") 
} 

Карта-свертка Java код сценария должен быть сам объяснительное.

+0

благодарит @BatScream за ваш ответ. Тем не менее, я пытаюсь использовать этот код, и он работает в течение 5 дней и все еще работает. Метод кажется очень медленным! – amaatouq

Смежные вопросы