Я много слышу о map / reduce, особенно в контексте системы массовых параллельных вычислений Google. Что именно?
language-agnostic
mapreduce
Лоуренс Дол
источник
источник
Ответы:
Из аннотации страницы публикации исследования Google MapReduce :
Преимущество MapReduce заключается в том, что обработка может выполняться параллельно на нескольких узлах обработки (нескольких серверах), поэтому это система, которая может очень хорошо масштабироваться.
Поскольку она основана из функционального программирования модели,
map
иreduce
шаги каждого не имеют каких - либо побочных эффектов (состояние и результаты каждого подраздела вmap
процессе не зависит от другого), поэтому набор данных привязывается и уменьшается каждый может быть отделен через несколько узлов обработки.Joel's Может ли ваш язык программирования это сделать? В статье рассказывается, как понимание функционального программирования было важным в Google для разработки MapReduce, на котором работает его поисковая система. Это очень хорошее чтение, если вы не знакомы с функциональным программированием и тем, как оно позволяет масштабировать код.
См. Также: Википедия: MapReduce
Связанный вопрос: просто объясните mapreduce
источник
Объяснение MapReduce .
Это объясняет лучше, чем то, что я могу. Помогает?
источник
Карта - это функция, которая применяет другую функцию ко всем элементам в списке, чтобы создать другой список со всеми возвращаемыми значениями в нем. (Другой способ сказать «применить f к x» - «вызвать f, передать ему x». Иногда лучше сказать «применить» вместо «вызвать».)
Вот так, вероятно, написана карта на C # (она называется
Select
и находится в стандартной библиотеке):Поскольку вы чувак на Java, а Джоэл Спольски любит рассказывать ГРОМНУЮ НЕПРАВИЛЬНУЮ ложь о том, насколько дрянная Java (на самом деле, он не лжет, это дерьмо, но я пытаюсь вас убедить), вот моя очень грубая попытка версия Java (у меня нет компилятора Java, и я смутно помню версию Java 1.1!):
Я уверен, что это можно улучшить миллионами способов. Но это основная идея.
Reduce - это функция, которая превращает все элементы списка в одно значение. Для этого ему нужно дать другую функцию,
func
которая превращает два элемента в одно значение. Это сработает, если передать первые два элемента вfunc
. Затем результат этого вместе с третьим пунктом. Затем результат этого с четвертым элементом, и так до тех пор, пока все элементы не исчезнут, и у нас останется одно значение.В C #
Aggregate
метод reduce вызывается и снова находится в стандартной библиотеке. Я сразу перейду к версии для Java:Эти версии Java нуждаются в добавлении дженериков, но я не знаю, как это сделать на Java. Но вы должны иметь возможность передавать им анонимные внутренние классы для предоставления функторов:
Будем надеяться, что дженерики избавятся от слепков. Типичный эквивалент в C #:
Почему это «круто»? Простые способы разбить большие вычисления на более мелкие части, чтобы их можно было собрать различными способами, всегда круто. Google применяет эту идею к распараллеливанию, потому что и map, и reduce могут совместно использоваться на нескольких компьютерах.
Но ключевое требование НЕ состоит в том, чтобы ваш язык мог рассматривать функции как значения. Любой объектно-ориентированный язык может это сделать. Фактическое требование к распараллеливанию заключается в том, что небольшие
func
функции, которые вы передаете в map и reduce, не должны использовать или обновлять какое-либо состояние. Они должны возвращать значение, которое зависит только от переданных им аргументов. В противном случае результаты будут полностью испорчены, если вы попытаетесь запустить все это параллельно.источник
После того, как я был очень разочарован либо очень длинными вафлями, либо очень короткими расплывчатыми сообщениями в блоге, я, в конце концов, обнаружил эту очень хорошую строгую краткую статью .
Тогда я пошел вперед и сделал его более кратким путем перевода в Scala, где я предоставивший простейший случай , когда пользователь просто задает лишь
map
иreduce
части приложения. В Hadoop / Spark, строго говоря, используется более сложная модель программирования, которая требует, чтобы пользователь явно указал еще 4 функции, описанные здесь: http://en.wikipedia.org/wiki/MapReduce#Dataflowimport scalaz.syntax.id._ trait MapReduceModel { type MultiSet[T] = Iterable[T] // `map` must be a pure function def mapPhase[K1, K2, V1, V2](map: ((K1, V1)) => MultiSet[(K2, V2)]) (data: MultiSet[(K1, V1)]): MultiSet[(K2, V2)] = data.flatMap(map) def shufflePhase[K2, V2](mappedData: MultiSet[(K2, V2)]): Map[K2, MultiSet[V2]] = mappedData.groupBy(_._1).mapValues(_.map(_._2)) // `reduce` must be a monoid def reducePhase[K2, V2, V3](reduce: ((K2, MultiSet[V2])) => MultiSet[(K2, V3)]) (shuffledData: Map[K2, MultiSet[V2]]): MultiSet[V3] = shuffledData.flatMap(reduce).map(_._2) def mapReduce[K1, K2, V1, V2, V3](data: MultiSet[(K1, V1)]) (map: ((K1, V1)) => MultiSet[(K2, V2)]) (reduce: ((K2, MultiSet[V2])) => MultiSet[(K2, V3)]): MultiSet[V3] = mapPhase(map)(data) |> shufflePhase |> reducePhase(reduce) } // Kinda how MapReduce works in Hadoop and Spark except `.par` would ensure 1 element gets a process/thread on a cluster // Furthermore, the splitting here won't enforce any kind of balance and is quite unnecessary anyway as one would expect // it to already be splitted on HDFS - i.e. the filename would constitute K1 // The shuffle phase will also be parallelized, and use the same partition as the map phase. abstract class ParMapReduce(mapParNum: Int, reduceParNum: Int) extends MapReduceModel { def split[T](splitNum: Int)(data: MultiSet[T]): Set[MultiSet[T]] override def mapPhase[K1, K2, V1, V2](map: ((K1, V1)) => MultiSet[(K2, V2)]) (data: MultiSet[(K1, V1)]): MultiSet[(K2, V2)] = { val groupedByKey = data.groupBy(_._1).map(_._2) groupedByKey.flatMap(split(mapParNum / groupedByKey.size + 1)) .par.flatMap(_.map(map)).flatten.toList } override def reducePhase[K2, V2, V3](reduce: ((K2, MultiSet[V2])) => MultiSet[(K2, V3)]) (shuffledData: Map[K2, MultiSet[V2]]): MultiSet[V3] = shuffledData.map(g => split(reduceParNum / shuffledData.size + 1)(g._2).map((g._1, _))) .par.flatMap(_.map(reduce)) .flatten.map(_._2).toList }
источник
MapReduce и / или SQL:
http://www.data-miners.com/blog/2008/01/mapreduce-and-sql-aggregations.html
http://www.data-miners.com/blog/
критика MapReduce
http://www.databasecolumn.com/2008/01/mapreduce-a-major-step-back.html
http://www.databasecolumn.com/2008/01/mapreduce-continued.html
источник
Карта - это собственный JS-метод, который можно применить к массиву. Он создает новый массив в результате выполнения некоторой функции, отображаемой на каждый элемент исходного массива. Поэтому, если вы сопоставили функцию (элемент) {return element * 2;}, она вернет новый массив с удвоением каждого элемента. Исходный массив останется неизменным.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Reduce - это собственный метод JS, который также можно применить к массиву. Он применяет функцию к массиву и имеет начальное выходное значение, называемое аккумулятором. Он перебирает каждый элемент в массиве, применяет функцию и сокращает их до одного значения (которое начинается как аккумулятор). Это полезно, потому что у вас может быть любой результат, который вы хотите, вам просто нужно начать с этого типа аккумулятора. Так что, если бы я хотел что-то уменьшить до объекта, я бы начал с аккумулятора {}.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce?v=a
источник
Уменьшение карты:
Чтобы запустить что-то большое, мы можем использовать вычислительную мощность разных компьютеров в нашем офисе. Сложная часть - разделить задачу между разными компьютерами, это делает библиотека MapReduce.
Основная идея состоит в том, что вы делите задание на две части: карту и сокращение. По сути, Map берет проблему, разбивает ее на части и отправляет части на разные машины, поэтому все части работают одновременно. Reduce берет результаты из частей и объединяет их вместе, чтобы получить единый ответ.
Вход - это список записей. Результат вычисления карты - список пар ключ / значение. Reduce берет каждый набор значений с одним и тем же ключом и объединяет их в одно значение. Вы не можете сказать, было ли задание разделено на 100 частей или 2 части; конечный результат очень похож на результат одной карты.
Пожалуйста, посмотрите на простую карту и программу сокращения:
Функция карты используется для применения некоторой функции в нашем исходном списке, и, следовательно, создается новый список. Функция map () в Python принимает функцию и список в качестве аргумента. Новый список возвращается путем применения функции к каждому элементу списка.
Функция reduce () в Python принимает в качестве аргумента функцию и список. Функция вызывается с лямбда-функцией и списком, и возвращается новый сокращенный результат. Это выполняет повторяющуюся операцию над парами списка.
источник