Map / Reduce 란 무엇입니까?


84

특히 Google의 대규모 병렬 컴퓨팅 시스템과 관련하여 map / reduce에 대해 많이 듣습니다. 정확히 무엇입니까?


3
@Rinat : 그럼에도 불구하고 여전히 좋은 질문입니다.
Bill Karwin

3
물론 Google에서이 작업을 수행했습니다. 그러나 (a) SO는 모든 중요한 질문에 대한 답변을 얻을 수 있도록 성장하기위한 것입니다 (이미 답변이있는 질문을 게시 할 수도 있습니다).
Lawrence Dol

답변:


69

Google의 MapReduce 연구 간행물 페이지 요약에서 발췌 :

MapReduce는 대규모 데이터 세트를 처리하고 생성하기위한 프로그래밍 모델 및 관련 구현입니다. 사용자는 키 / 값 쌍을 처리하여 일련의 중간 키 / 값 쌍을 생성하는 맵 함수와 동일한 중간 키와 관련된 모든 중간 값을 병합하는 축소 함수를 지정합니다.

MapReduce의 장점은 처리가 여러 처리 노드 (여러 서버)에서 병렬로 수행 될 수 있으므로 매우 잘 확장 할 수있는 시스템이라는 것입니다.

함수형 프로그래밍 모델을 기반으로하기 때문에 mapreduce단계는 각각 부작용 map이 없으므로 (프로세스 의 각 하위 섹션의 상태와 결과는 서로 의존하지 않음) 매핑 및 축소되는 데이터 세트를 각각 분리 할 수 ​​있습니다. 여러 처리 노드를 통해.

Joel의 프로그래밍 언어가이 작업을 수행 할 수 있습니까? 조각은 Google에서 검색 엔진을 구동하는 MapReduce를 만들기 위해 함수형 프로그래밍을 이해하는 것이 얼마나 필수적인지 설명합니다. 함수형 프로그래밍과 확장 가능한 코드를 허용하는 방법에 익숙하지 않은 경우 매우 좋은 읽기입니다.

참고 : Wikipedia : MapReduce

관련 질문 : mapreduce를 간단하게 설명하십시오 .


3
훌륭하게 설명되었습니다. 그리고 Software Monkey에게 M / R은 일단 이해하면 거의 모든 것에 구현하기가 매우 쉬우 며 여기에 제공된 예제에 국한되지 않습니다. 주위를 둘러 보는 방법에는 여러 가지가 있습니다. 하나는 수집가와 깔때기로 생각하는 것입니다.
Esko


16

Map은 목록의 모든 항목에 다른 함수를 적용하여 모든 반환 값이있는 다른 목록을 생성하는 함수입니다. ( "apply f to x"의 또 다른 표현은 "call f, pass it x"입니다. 따라서 "call"대신 "apply"라고 말하는 것이 더 좋을 때도 있습니다.)

이것이 아마도지도가 C #으로 작성되는 방법입니다 (호출 Select되고 표준 라이브러리에 있음).

public static IEnumerable<R> Select<T, R>(this IEnumerable<T> list, Func<T, R> func)
{
    foreach (T item in list)
        yield return func(item);
}

당신이 Java 친구이고 Joel Spolsky는 GROSSLY UNFAIR LIES에게 Java가 얼마나 엉뚱한 지에 대해 이야기하는 것을 좋아합니다. Java 버전 (Java 컴파일러가 없으며 Java 버전 1.1을 막연하게 기억합니다!) :

// represents a function that takes one arg and returns a result
public interface IFunctor
{
    object invoke(object arg);
}

public static object[] map(object[] list, IFunctor func)
{
    object[] returnValues = new object[list.length];

    for (int n = 0; n < list.length; n++)
        returnValues[n] = func.invoke(list[n]);

    return returnValues;
}

저는 이것이 백만 가지 방법으로 개선 될 수 있다고 확신합니다. 그러나 그것은 기본 아이디어입니다.

Reduce는 목록의 모든 항목을 단일 값으로 바꾸는 기능입니다. 이렇게하려면 func두 항목을 단일 값으로 바꾸는 또 다른 함수 를 제공해야 합니다. 처음 두 항목을 func. 그런 다음 세 번째 항목과 함께 그 결과. 그런 다음 그 결과는 네 번째 항목으로, 모든 항목이 사라지고 하나의 값만 남을 때까지 계속됩니다.

C #에서는 reduce가 호출 Aggregate되고 다시 표준 라이브러리에 있습니다. Java 버전으로 바로 건너 뛰겠습니다.

// represents a function that takes two args and returns a result
public interface IBinaryFunctor
{
    object invoke(object arg1, object arg2);
}

public static object reduce(object[] list, IBinaryFunctor func)
{
    if (list.length == 0)
        return null; // or throw something?

    if (list.length == 1)
        return list[0]; // just return the only item

    object returnValue = func.invoke(list[0], list[1]);

    for (int n = 1; n < list.length; n++)
        returnValue = func.invoke(returnValue, list[n]);

    return returnValue;
}

이 Java 버전에는 제네릭 추가가 필요하지만 Java에서 수행하는 방법을 모르겠습니다. 그러나 펑터를 제공하기 위해 익명의 내부 클래스를 전달할 수 있어야합니다.

string[] names = getLotsOfNames();

string commaSeparatedNames = (string)reduce(names, 
   new IBinaryFunctor {
       public object invoke(object arg1, object arg2)
           { return ((string)arg1) + ", " + ((string)arg2); }
   }

제네릭이 캐스트를 제거하기를 바랍니다. C #의 typesafe에 해당하는 것은 다음과 같습니다.

string commaSeparatedNames = names.Aggregate((a, b) => a + ", " + b);

이 "멋진"이유는 무엇입니까? 더 큰 계산을 더 작은 조각으로 나누는 간단한 방법은 서로 다른 방식으로 다시 합칠 수 있도록 항상 멋집니다. Google이이 아이디어를 적용하는 방식은 병렬화에 있습니다. map과 reduce는 여러 컴퓨터에서 공유 할 수 있기 때문입니다.

그러나 핵심 요구 사항은 언어가 함수를 값으로 취급 할 수 있다는 것이 아닙니다. 어떤 OO 언어라도 그렇게 할 수 있습니다. 병렬화의 실제 요구 사항은 func매핑 및 축소를 위해 전달 하는 작은 함수가 상태를 사용하거나 업데이트하지 않아야한다는 것입니다. 전달 된 인수에만 의존하는 값을 반환해야합니다. 그렇지 않으면 전체를 병렬로 실행하려고 할 때 결과가 완전히 망가질 것입니다.


2
전반적으로 +1 가치가있는 좋은 답변입니다. 하지만 Java에서 잽을 좋아하지는 않았지만 C에서 Java로 이동 한 이후로 함수 값을 놓쳤으며 Java에서 가용성이 오래 지연되었다는 데 동의합니다.
Lawrence Dol

1
Java에서 심각한 문제는 아니 었습니다. 지금 당장 C #을 선호 할 정도로 3 가지 정도의 결함이 있지만, C #에는 언젠가 다른 언어를 선호하게 만드는 결함 목록도 있습니다.
Daniel Earwicker

그건 그렇고, 실제로 가능하다면 누군가가 예제를 편집하여 Java 제네릭을 사용할 수 있다면 좋겠습니다. 또는 편집 할 수없는 경우 여기에 스 니펫을 게시하면 편집하겠습니다.
Daniel Earwicker

편집을 시작했지만 map () 메서드는 반환 유형의 배열을 만듭니다. Java는 제네릭 유형의 배열 생성을 허용하지 않습니다. 목록을 사용하도록 변경할 수 있었지만 (배열로 변환 할 수도 있음) 그 당시에는 야망이 떨어졌습니다.
Michael Myers

1
(a, b) => a + ","+ b와 유사한 클로저 구문은 제가 자바 7에서 정말 기대했던 것이 었습니다. 특히 새로운 API가 들어갈 것 같은 부분이 있습니다. 그 구문은 다음과 같습니다. 이와 같은 것을 훨씬 더 깨끗하게 만들었습니다. 안타깝게도 일어날 것 같지 않습니다.
Adam Jaskiewicz

2

매우 긴 와플 또는 매우 짧은 막연한 블로그 게시물에 가장 좌절 한 후 결국이 매우 훌륭하고 간결한 논문을 발견했습니다 .

그런 다음 Scala로 번역하여 더 간결하게 만들었습니다. 여기서 사용자 가 응용 프로그램 의 mapreduce부분 만 지정하는 가장 간단한 사례를 제공했습니다 . Hadoop / Spark에서는 엄밀히 말하면 사용자가 여기에 설명 된 4 개의 추가 기능을 명시 적으로 지정해야하는 더 복잡한 프로그래밍 모델이 사용됩니다. http://en.wikipedia.org/wiki/MapReduce#Dataflow

import 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
}


0

Map은 배열에 적용 할 수있는 기본 JS 메서드입니다. 원래 배열의 모든 요소에 매핑 된 일부 함수의 결과로 새 배열을 만듭니다. 따라서 function (element) {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


0

MapReduce :

큰 것을 실행하기 위해 우리는 사무실에서 다른 컴퓨터의 계산 능력을 사용할 수 있습니다. 어려운 부분은 작업을 서로 다른 컴퓨터로 분할하는 것이며 MapReduce 라이브러리에서 수행합니다.

기본 아이디어는 작업을지도와 축소라는 두 부분으로 나누는 것입니다. Map은 기본적으로 문제를 가져 와서 하위 부분으로 분할하고 하위 부분을 다른 기계로 전송하므로 모든 부분이 동시에 실행됩니다. Reduce는 하위 부분의 결과를 가져 와서 다시 결합하여 단일 답을 얻습니다.

입력은 레코드 목록이고 맵 계산 결과는 키 / 값 쌍 목록입니다. Reduce는 동일한 키를 가진 각 값 집합을 가져 와서 단일 값으로 결합합니다. 작업이 100 개로 분할되었는지 2 개로 분할되었는지 알 수 없습니다. 최종 결과는 단일 맵의 결과와 거의 비슷합니다.

간단한지도를보고 프로그램을 줄이십시오.

맵 기능은 원래 목록에 일부 기능을 적용하는 데 사용되며 새 목록이 생성됩니다. Python의 map () 함수는 함수와 목록을 인수로받습니다. 목록의 각 항목에 기능을 적용하여 새로운 목록을 반환합니다.

li = [5, 7, 4, 9] 
final_list = list(map(lambda x: x*x , li)) 
print(final_list)  #[25, 49, 16, 81]

Python의 reduce () 함수는 함수와 목록을 인수로받습니다. 이 함수는 람다 함수 및 목록과 함께 호출되고 새로운 축소 결과가 반환됩니다. 이것은 목록 쌍에 대해 반복적 인 작업을 수행합니다.

#reduce func to find product/sum of list
x=(1,2,3,4)
from functools import reduce
reduce(lambda a,b:a*b ,x) #24
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.