MongoDB MapReduce намного медленнее, чем чистая обработка Java? - PullRequest
3 голосов
/ 13 декабря 2010

Я хотел посчитать все ключи моих документов (включая встроенные) коллекции. Сначала я написал Java-клиент для решения этой проблемы. Потребовалось менее 4 секунд, чтобы показать результат. Затем я написал карту / уменьшить функцию. Результат был хорошим, но запуск функции занял более 30 секунд! Я думал, что карта / уменьшить функцию будет быстрее, так как она выполняется на стороне сервера. Клиенту Java нужно извлекать каждый документ с сервера, но, тем не менее, он намного быстрее. Почему это так?

// Вот моя функция карты:

map = function(){
    for(var key in this) {
      emit(key, {count:1});
      if(isNestedObject(this[key])){
        m_sub(key, this[key]);
      }
    }
}

// Вот моя функция уменьшения:

reduce = function (key, emits) {
    total = 0;
    for (var i in emits) {
        total += emits[i].count;
    }
    return {count:total};
}

// Вот вызов mapreduce:

mr = db.runCommand({"mapreduce":"keyword", "map" : map, "reduce" : reduce, 
    "scope":{
        isNestedObject : function (v) {
            return v && typeof v === "object";
        },
        m_sub : function(base, value) {
            for(var key in value) {
              emit(base + "." + key, {count:1});
              if(isNestedObject(value[key])){
                m_sub(base + "." + key, value[key]);
              }
            }
        }
    }
})

// Вот вывод:

{
 "result" : "tmp.mr.mapreduce_1292252775_8",
 "timeMillis" : 39087,
 "counts" : {
  "input" : 20168,
  "emit" : 986908,
  "output" : 1934
 },
 "ok" : 1
}

// Вот мой клиент Java:

public static Set<String> recursiv(DBObject o){

        Set<String> keysIn = o.keySet();
        Set<String> keysOut = new HashSet<String>();
        for(String s : keysIn){
            Set<String> keys2 = new HashSet<String>();
            if(o.get(s).getClass().getSimpleName().contains("Object")){
                DBObject o2 = (DBObject) o.get(s);
                keys2 = recursiv(o2);
                for(String s2 : keys2){
                    keysOut.add(s + "." + s2);
                }   
            }else{
                keysOut.add(s);
            } 
        }
        return keysOut;     
    }

    public static void main(String[] args) throws Exception {

        final Mongo mongo =  new Mongo("xxx.xxx.xxx.xxx");
        final DB db = mongo.getDB("keywords");
        final DBCollection keywordTable = db.getCollection("keyword");
        Multiset<String> count = HashMultiset.create();

        long start = System.currentTimeMillis();

        DBCursor curs = keywordTable.find();    
        while(curs.hasNext()){
            DBObject o = curs.next();
            Set<String> keys = recursiv(o);
            for(String s : keys){
                count.add(s);
            }
        }

        long end = System.currentTimeMillis();
        long duration = end - start;

        System.out.println(new SimpleDateFormat("mm:ss:SS").format(Long.valueOf(duration)));              
        System.out.println("duration:" + duration + " ms");
        //System.out.println(count);
        System.out.println(count.elementSet().size());

    }

// Вот вывод:

00:03:726
duration:3726 ms
1898

Не беспокойтесь о разном количестве результатов (1934 против 1898). Это связано с тем, что уменьшение карты также учитывает ключи в массиве, которые не учитываются клиентом Java. Спасибо, чтобы пролить свет на различные времена выполнения.

Ответы [ 3 ]

9 голосов
/ 13 декабря 2010

Это не так уж много ответов, но в книге «О'рейли Монго» Кристина говорит, что запросы сокращения карт - это одна из самых медленных вещей, которые вы можете сделать, но они также являются наиболее гибкими и наиболее масштабируемыми.,Mongo сможет разбить запрос и обработать вычислительную мощность на всех узлах, что означает, что вы должны получать линейную масштабируемость с каждым добавляемым вами узлом.Но на одном узле даже группировка по запросу будет быстрее, чем сокращение карты.

5 голосов
/ 04 августа 2011

Другая причина в том, что у mongodb есть проблемы с его движком javascript, который позволяет им использовать только один поток. Mongodb планирует переключиться на движок gavascript v8 от Google, который, как мы надеемся, позволяет mongodb обрабатывать карту / сокращать многопоточность. См http://www.mongodb.org/display/DOCS/MapReduce#MapReduce-Parallelism и https://jira.mongodb.org/browse/SERVER-2407

1 голос
/ 09 декабря 2013

Если вы можете, посмотрите в команду агрегации фреймворка. Не так гибко, как MapReduce, но производительность впечатляет. Я использовал его для агрегирования большого количества данных коллекций в ежечасные, ежедневные и ежемесячные сводные данные, в нашей ситуации соотношение производительности с MapReduce составляло от 1 до 50.

Мы выбрали дизайн с сегментированным набором с идентичной структурой, который позволял нам выполнять небольшие, но многочисленные задания агрегации, конвейерная концепция команды агрегации прекрасно работает.

Мне также показалось, что команда $ group очень эффективна, но ограничения по размеру и осколкам ограничивают ее использование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...