Comments 15
Оригинальная реализация MapReduce была написана в Google на Си++, но так получилось, что широкое распространение парадигмы началось в индустрии только с реализации MapReduce от Apache, которая на Java.
Вероятно, дело не в языке, а в том, что Google никогда не открывал исходников MapReduce. Поэтому пришлось ждать, пока кто-нибудь воплотит идею в open-source.
Но, к сожалению, ни Google, ни Яндекс, не опубликовали Си++ реализации, и народу оставалось играться на Java. (Вы только представьте себе, какой другой, «более лучшей» была бы индустрия HPC/BigData если бы изначально у народа были бы доступны C++ библиотеки для масштабирования bigdata решений. Но, история не терпит сослагательного наклонения, и мы рабоиаем на чем работаем)
Здесь же («хороша ложка к обеду») речь шла про то, как плотно пошли статьи, моя — вчера, и из Яндекса сегодня. Что, опять же, свидетельствует о том, что технология еще актуальна и о ней говорят и её применяют.
вы (Гугл)
Мои комментарии выражают только моё личное мнение и не имеют никакого отношения к мнению компании.
почему не опубликовали эту библиотеку ни тогда ни сейчас?
Потому что это не библиотека, это сервис. Чтобы он хорошо работал и был удобным, нужен огромный кусок инфраструктуры: планировщик задач, система управления ресурсами, система развёртывания приложений, распределённая файловая система, системы мониторинга и половина стандартной библиотеки впридачу. В итоге получается, что нужно открыть огромную часть инфраструктуры и кода. Это непростое решение.
Потому что это не библиотека, это сервис. Чтобы он хорошо работал и был удобным, нужен огромный кусок инфраструктуры: планировщик задач, система управления ресурсами, система развёртывания приложений, распределённая файловая система, системы мониторинга и половина стандартной библиотеки впридачу.
Вот, кстати, нет. Это именно библиотека, которая может основываться на инфраструктуре (определенная распределенная файловая система, или развертывание приложений), а может быть и абстрагиована от всего этого. Как я покажу в остальных статьях серии, MapReduce остаётся MapReduce дже если у него вынуть GFS или HDFS и пользовться другими средствами доставки данных в кластере.
(В-общем и целом, если бы Google выложил MapReduce только как библиотеку, то сообщество нашло бы чем заменить инфраструктуру. Но чего уж тут. Нет так нет)
Это именно библиотека
Ну понятно, что любой сервис можно оформить в виде библиотеки и исполняемого файла, абстрагировать библиотеку от внешних зависимостей, выделив интерфейсы для коммуникации и определив семантику и ожидаемую производительность каждого вызова каждого метода каждого интерфейса. Проблема в том, что если это не было сделано изначально, то обычно проще переписать всё с нуля, чем сделать такой рефакторинг. К тому же, чтобы правильно выделить абстракции, обычно нужно иметь в виду как минимум несколько возможных реализаций каждой абстракции (хотя бы три).
Далее, чтобы пользователь мог использовать эту библиотеку, нужно попросить его реализовать все зависимости в соответствии с их семантикой. Это много работы.
В теории это может работать, но на практике не выглядит особо хорошей инвестицией времени для компании, у которой много другой работы.
Предположим, что мы в полном соответствии с примером в статье хотим посчитать повторения слов в следующем известном шуточном стихотворении:
Ехал Гитлер через Гитлер Видит Гитлер Гитлер Гитлер Сунул Гитлер в Гитлер Гитлер Гитлер Гитлер Гитлер Гитлер
Размер чанка примем равным 8 байтам, и для простоты будем считать, что текст у нас в какой-то однобайтовой кодировке, поэтому 1 байт = 1 знак, и вместо переносов строки — обычные пробелы.
Если я все правильно понимаю, то это значит, что мапперы на входе получат следующее разбиение:
0: "Ехал Гит"
1: "лер чере"
2: "з Гитлер"
3: " Видит Г"
4: "итлер Ги"
5: "тлер Гит"
6: "лер Суну"
7: "л Гитлер"
8: " в Гитле"
9: "р Гитлер"
10: "Гитлер Г"
11: "итлер Ги"
12: "тлер Гит"
13: "лер"
Теперь мапперы прогоняют свой алгоритм для каждого чанка и выдают следующие ключи:
0:
"Ехал": 1
"Гит": 1
1:
"лер": 1
"чере": 1
2:
"з": 1
"Гитлер": 1
3:
"Видит": 1
"Г": 1
4:
"итлер": 1
"Ги": 1
5:
"тлер": 1
"Гит": 1
6:
"лер": 1
"Суну": 1
7:
"л": 1
"Гитлер": 1
8:
"в": 1
"Гитле": 1
9:
"р": 1
"Гитлер": 1
10:
"Гитлер": 1
"Г": 1
11:
"итлер": 1
"Ги": 1
12:
"тлер": 1
"Гит": 1
13:
"лер": 1
Наверное, вы уже поняли, что меня смущает, но я доведу мысль до конца. Теперь, перед тем, как передать данные в reducer-ы, платформа выполняет группировку по ключу.
"Видит": 1
"Г": 1, 1
"Ги": 1, 1
"Гит": 1, 1, 1
"Гитле": 1
"Гитлер": 1, 1, 1, 1
"Ехал": 1
"Суну": 1
"в": 1
"з": 1
"итлер": 1, 1
"л": 1
"лер": 1, 1, 1
"р": 1
"тлер": 1, 1
"чере": 1
Ну и наши reducer-ы просто суммируют единички для каждого слова.
Мне кажется проблемой то, что мы, по моему пониманию, решили не ту задачу, которую хотели. Мы получили вот это:
"Видит": 1
"Г": 2
"Ги": 2
"Гит": 3
"Гитле": 1
"Гитлер": 4
"Ехал": 1
"Суну": 1
"в": 1
"з": 1
"итлер": 2
"л": 1
"лер": 3
"р": 1
"тлер": 2
"чере": 1
А хотели (я хотел) вот это:
"Видит": 1
"Гитлер": 12
"Ехал": 1
"Сунул": 1
"в": 1
"через": 1
Если варьировать размер блока, результаты тоже будут дико гулять, и все еще не иметь ничего общего с правильным ответом, полученным традиционным способом. Что я понял неправильно? Почему так получается? Как с таким бороться?
"Видит": 1000000000000
"Гитлер": 12000000000000
"Ехал": 1000000000000
"Сунул": 1000000000000
"в": 1000000000000
"через": 1000000000000
А по факту будет отчет с разными комбинациями слов, разрезанных пополам в произвольных позициях. И даже если увеличить размер чанка до, например, 4 ГиБ, которые поместятся в памяти произвольной ноды, у нас все равно есть слова на границах, которые были разрезаны. Или я все же упускаю что-то в понимании?
Здравый смысл подсказывает, что если входные данные расположены в файлах, то проще всего отдавать отдельному обработчику на стадии отображения файл полностью.
(Главное, не пытаться запихнуть весь файл в память, ни к чему это.)
Просто верно ли я понимаю, что mapreduce не приспособлен к работе с неструктурированными данными? И в данном конкретном случае, нельзя получить корректный результат без предварительной обработки и разбиения мегафайла на записи приемлемого размера, которые могут поместиться в память? И при этом мы можем выбрать только такой размер чанка, который кратен размеру записи?
Если нужна поточная реализация (и вы пишете на Java) то вам в Spark Streaming или Apache Storm. Если вы про Си++, то увы, и MapReduce реализации у вас нет, не говоря про streaming реализацию (ждем публичного релиза Yandex YT как-нибудь в будущем, тогда появится всё). Если же вы про InterSystems Caché ObjectScript, то продолжайте читать данную серию. (Вторая часть, третья часть) Там будет и поточный режим.
Какая-такая Data? Или ещё раз про MapReduce