Mongodb MapReduce для группировки до n по категориям с использованием Mongoid - PullRequest
0 голосов
/ 02 февраля 2012

У меня странная проблема с уменьшением карты MongoDB (2.0.2).

Итак, история выглядит так:

У меня есть модель объявления (см. Извлечение исходного кода модели ниже)и мне нужно сгруппировать до n объявлений по категориям, чтобы иметь хороший упорядоченный список, который я позже смогу использовать для более интересных вещей.

# encoding: utf-8
class Ad  
  include Mongoid::Document
  cache
  include Mongoid::Timestamps

  field :title
  field :slug, :unique => true

  def self.aggregate_latest_active_per_category

    map = "function () {
        emit( this.category, { id: this._id });
    }"

    reduce = "function ( key, value ) {
      return { ads:v };
    }"

  self.collection.map_reduce(map, reduce, { :out => "categories"} )

  end

Все развлечения и игры до сих пор.

То, что я ожидаю, это получить результат в форме, которая напоминает (оболочка монго для db.categories.findOne()):

    {
      "_id" : "category_name",
      "value" : {
          "ads" : [
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014ab")
                          },
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014b0")
                          },
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014b6")
                          },
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014b8")
                          },
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014bd")
                          },
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014c1")
                          },
                          {
                            "id" : ObjectId("4f2970e9e815f825a30014ca")
                          },
                          // ... and it goes on and on
          ]
        }
      }

На самом деле, было бы еще лучше, если бы я мог получить значение, содержащеетолько массив, но MongoDB жалуется на то, что пока не поддерживает его, но с последующим использованием функции finalize, это не большая проблема, о которой я хочу спросить.

Теперь вернемся к проблеме.Что происходит на самом деле, когда я уменьшаю карту, так это то, что она выплевывает что-то вроде:

{
    "_id" : "category_name",
    "value" : {
        "ads" : [
            {
                "ads" : [
                    {
                        "ads" : [
                            {
                                "ads" : [
                                    {
                                        "ads" : [
                                            {
                                                "id" : ObjectId("4f2970d8e815f825a3000011")
                                            },
                                            {
                                                "id" : ObjectId("4f2970d8e815f825a3000017")
                                            },
                                            {
                                                "id" : ObjectId("4f2970d8e815f825a3000019")
                                            },
                                            {
                                                "id" : ObjectId("4f2970d8e815f825a3000022")
                                            },

   // ... on and on and on

... и хотя я, возможно, смогу найти способ использовать это, это просто не похоже на то, что я долженget.

Итак, мои вопросы (наконец-то):

  1. Я что-то не так делаю и что это?
  2. Я что-то не так с картой MongoDB уменьшаю(Я имею в виду, помимо всех обычных вещей по сравнению с Hadoop)?

1 Ответ

1 голос
/ 02 февраля 2012

Да, вы делаете это неправильно. Входы и выходы map и reduce должны быть одинаковыми. Потому что они предназначены для параллельного выполнения, и reduce может выполняться с частично уменьшенными результатами. Попробуйте эти функции:

var map = function() {
  emit(this.category, {ads: [this._id]});
};

var reduce = function(key, values) {
  var result = {ads: []};

  values.forEach(function(v) {
    v.ads.forEach(function(a) {
      result.ads.push(a)
    });
  });
  return result;
}

Это должно привести к таким документам, как:

{_id: category, value: {ads: [ObjectId("4f2970d8e815f825a3000011"), 
                              ObjectId("4f2970d8e815f825a3000019"), 
                              ...]}}
...