mongodb - Обработка логических правил с помощью mapreduce? - PullRequest
1 голос
/ 10 февраля 2012

Допустим, у меня есть три правила:

[{ 
    selector: {_id: "1"},
    value: {name: "apple"} 
},
{ 
    selector: {name: "apple"},
    value: {type: "fruit"} 
},
{ 
    selector: {type: "fruit"},
    value: {class: "food"} 
}]

Я бы хотел получить такой результат:

{
    _id: 1,
    value: {
        name: "apple",
        type: "fruit",
        class: "food"
    }
}

Могу ли я сделать это с помощью mapreduce?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2012

вы можете в значительной степени делать что угодно с помощью mapreduce, поскольку вы можете выполнять произвольный javascript для всех ваших объектов.Но тогда вы должны знать, что mapreduce пока не очень быстрый, и рекомендуется не выполнять операции «db» в функциях map / lower (становится несовместимым с sharding и может создавать проблемы блокировки).

В идеале1-й шаг - попытаться смоделировать данные так, чтобы они были предварительно заполнены, даже если это означает дублирование некоторых данных.Если это невозможно, вы должны сравнить скорости mapreduce с выполнением работы на стороне клиента.

0 голосов
/ 11 февраля 2012

Вот мой взгляд на проблему (node.js с драйвером mongodb).Я почти уверен, что его можно немного оптимизировать.

var logicize = function(db, callback) {
    var reduce = function(key, values){
        // If values is an array of objects, it is merged into a single object
        if(values.length) {
            while(values.length>1) {
                var current = values.pop();
                for (var property in current) {
                    values[0][property] = current[property];
                }
            }
            return values[0];
        }
        return values;
    };

    db.collection("rules", function(err, rules) {
        db.collection("results", function(err, results) {
            rules.mapReduce("function() {emit(this.selector._id, this.value);}", reduce, {out: {replace:"results"}, query:{"selector._id":{$exists:true}}}, function() {
                rules.find({"selector._id":{$exists:false}}, function(err, cursor) {            
                    cursor.nextObject(function(err, item) { 
                        // Recursive because I don't want to start a new mapreduce 
                        // before the previous one has finished. The following one 
                        // might depend on the results of the previous
                        (function recurse(item) {
                            if(item==null) // Done
                                callback();
                            else {
                                var map = new Function('emit(this._id, '+JSON.stringify(item.value)+');');

                                var conditions = {};
                                for(var condition in item.selector) {
                                    conditions['value.'+condition] = item.selector[condition];
                                }
                                results.mapReduce(map, reduce, {out:{reduce:"results"},query: conditions}, function() { 
                                    // Previous mapreduce has finished so we can start the next one
                                    cursor.nextObject(function(err, item) {
                                        recurse(item);
                                    });
                                });
                            }
                        })(item);
                    });
                });
            });
        });
    });
}

Правила находятся в коллекции "правил", а результаты переходят в "результаты".Сначала я выполняю начальное преобразование карты только с правилами, которые имеют _id.После этого я запускаю отдельную карту для каждого из остальных правил.

...