MapReduce에 대한 간단한 설명?


166

CouchDB 질문과 관련이 있습니다.

누구나 Numbnuts가 이해할 수있는 용어로 MapReduce를 설명 할 수 있습니까?



3
그리고 여기에 내 취향이 있습니다 : MapReduce for and the kids .
Michael Hausenblas

@MichaelHausenblas-나는 당신의 예를 좋아합니다 : 온 가족이 이해하기 쉽고 재미 있습니다.
Lee

Joel Spolsky 초보자를위한 좋은 설명 -joelonsoftware.com/items/2006/08/01.html
user2314737

답변:


187

지도 및 축소에 대한 기본 사항으로 넘어갑니다.


은 어떤 종류의 목록에있는 항목을 다른 종류의 항목으로 "변환"하여 같은 종류의 목록에 다시 넣는 기능입니다.

숫자 목록이 [1,2,3]이고 모든 숫자를 두 배로 늘리려 고한다고 가정합니다.이 경우 "모든 숫자를 두 배로"하는 함수는 함수 x = x * 2입니다. 그리고 매핑없이 간단한 루프

A = [1, 2, 3]
foreach (item in A) A[item] = A[item] * 2

A = [2, 4, 6]이지만 루프를 작성하는 대신 맵 함수가 있으면 작성할 수 있습니다.

A = [1, 2, 3].Map(x => x * 2)

x => x * 2는 [1,2,3]의 요소에 대해 실행될 함수입니다. 프로그램은 각 항목을 가져 와서 x를 각 항목과 동일하게하여 (x => x * 2) 실행하고 결과 목록을 생성합니다.

1 : 1 => 1 * 2 : 2  
2 : 2 => 2 * 2 : 4  
3 : 3 => 3 * 2 : 6  

따라서 (x => x * 2)로 맵 기능을 실행하면 [2, 4, 6]이됩니다.


감소 "를 수집"리스트에서 항목이 일부 계산을 수행하는 기능이다 모든 따라서 단일 값들을 감소는 그들.

합계를 찾거나 평균을 찾는 것은 모두 축소 함수의 예입니다. 예를 들어 [7, 8, 9]와 같은 숫자 목록이 있고 합계를 원하면 다음과 같은 루프를 작성합니다.

A = [7, 8, 9]
sum = 0
foreach (item in A) sum = sum + A[item]

그러나 reduce 함수에 액세스 할 수 있다면 다음과 같이 작성할 수 있습니다

A = [7, 8, 9]
sum = A.reduce( 0, (x, y) => x + y )

이제 왜 두 개의 인수 (0과 x 및 y의 함수)가 전달되는지 약간 혼란 스럽습니다. reduce 함수가 유용하려면 2 개의 항목을 가져 와서 무언가를 계산하고 2 개의 항목을 하나의 단일 값으로 "감소"할 수 있어야하므로 프로그램은 단일 값을 가질 때까지 각 쌍을 줄일 수 있습니다.

실행은 다음과 같습니다.

result = 0
7 : result = result + 7 = 0 + 7 = 7
8 : result = result + 8 = 7 + 8 = 15
9 : result = result + 9 = 15 + 9 = 24

그러나 항상 0으로 시작하고 싶지 않으므로 첫 번째 인수는 첫 번째 result =줄 의 시드 값을 구체적으로 지정하도록합니다 .

두 목록을 합산한다고 가정하면 다음과 같습니다.

A = [7, 8, 9]
B = [1, 2, 3]
sum = 0
sum = A.reduce( sum, (x, y) => x + y )
sum = B.reduce( sum, (x, y) => x + y )

또는 실제 환경에서 더 쉽게 찾을 수있는 버전 :

A = [7, 8, 9]
B = [1, 2, 3]

sum_func = (x, y) => x + y
sum = A.reduce( B.reduce( 0, sum_func ), sum_func )

Map \ Reduce 지원을 통해 DB에 데이터를 저장하는 방법을 알 필요없이 데이터베이스 작업을 수행 할 수 있기 때문에 DB 소프트웨어의 장점은 바로 DB 엔진입니다.

Map 또는 Reduce 함수를 제공하여 원하는 엔진을 "알릴"수 있어야합니다. 그러면 DB 엔진이 데이터를 탐색하고 함수를 적용하며 결과를 얻을 수 있습니다. 모든 레코드를 반복하는 방법을 모른 채 모든 것을 원합니다.

단일 데이터베이스가 보유 할 수있는 인덱스, 키, 조인 및 뷰 및 많은 것들이 있으므로 데이터가 실제로 저장되는 방식으로부터 사용자를 보호함으로써 코드를보다 쉽게 ​​작성하고 유지 관리 할 수 ​​있습니다.

루핑 코드를 실제로 구현하는 대신 데이터로 수행하려는 작업 만 지정하면 병렬 프로그래밍도 마찬가지입니다. 그러면 기반 인프라가 "병렬화"되어 병렬 병렬 루프에서 함수를 실행할 수 있습니다.


좋아, 나는지도를 이해하고 개별적으로 찍은 축소. 그러나 어떤 애플리케이션을 축소 할 수 있습니까? Google 시나리오에서 그들은 예를 들어 주어진 키워드에 대한 페이지 순위를 제공하는 일련의 매개 변수를 합산하는 데 사용합니까?
Lorenzo

@lbolognini var total = orderes.Sum (o => o.UnitPrice * o.Quantity)
chakrit

@lbolognini 루핑이라는 개념을 추상화 할 때 많은 용도가 있습니다. 구글의 시나리오에는 아마도 페이지 랭크, 링크 및 기타를 계산하기위한 1000 대의 머신이있을 것입니다. 서버를 몇 대 더 추가해야 할 때 무엇을합니까? 모든 단일 루핑 코드를 수정하는 것은 아마도 옵션이 아닙니다. 그들이 한 것은 대신 "감소"기능에 대해 계산 코드를 작성하는 것입니다. 서버 목록이 변경되면 "감소"기능 만 변경하면됩니다. 알았다?
chakrit

평균 계산을 어떻게 줄일 수 있습니까? 내가 당신이 할 수없는 것 같아요 무엇을보고? 아마도 분자와 분모를 매핑하고 합산의 끝에서 나눌 수 있습니까?
andyczerwonka

@arcticpenguin 나는 거기에 너무 일반적입니다. 실제로 Average()는 위에 장식되어있을 것입니다 Sum(). 그러나 함수가 "리 듀스"라고 불리는 이유를 설명하기 위해 그것에 대해 이야기했습니다. 평균 함수는 숫자 목록을 가져와 단일 숫자 (평균)로 줄이는 것입니다.
chakrit

60

MapReduce는 개발자가 매퍼 이외의 다른 코드를 작성하고 함수를 줄일 필요없이 방대한 양의 데이터를 병렬로 처리하는 방법입니다.

지도 기능 배리어에 유지되는 결과, 데이터 아웃 및 괴로워 걸린다. 이 기능은 다수의 동일한 작업 과 동시에 실행할 수 있습니다 . 그런 다음 데이터 세트를 스칼라 값 으로 줄일 수 있습니다 .

따라서 SQL 문처럼 생각하면

SELECT SUM(salary)
FROM employees
WHERE salary > 1000
GROUP by deptname

map 을 사용 하여 급여가 1000보다 큰 직원의 하위 집합을 가져와 그룹 크기 버킷의 장벽으로 만들 수 있습니다.

Reduce 는 각 그룹을 합산합니다. 결과 세트를 제공합니다.

Google 논문의 대학 연구 노트 에서 이것을 뽑았습니다.


33
  1. 많은 데이터를 가져옵니다
  2. 모든 데이텀을 다른 데이텀으로 변환하는 변환을 수행하십시오.
  3. 새로운 데이터를 더 간단한 데이터로 결합

2 단계는지도입니다. 3 단계는 축소입니다.

예를 들어

  1. 도로의 한 쌍의 압력계에서 두 개의 임펄스 사이의 시간을 확보하십시오.
  2. 미터의 거리를 기준으로 해당 시간을 속도로 매핑
  3. 그 속도를 평균 속도로 줄이십시오

MapReduce가 Map과 Reduce간에 분리되는 이유는 서로 다른 부분을 쉽게 병렬로 수행 할 수 있기 때문입니다. (특히 Reduce에 특정 수학 속성이있는 경우)

MapReduce에 대한 복잡하지만 자세한 설명은 Google의 MapReduce 프로그래밍 모델-재 방문 (PDF)을 참조하십시오 .


1
3 단계의 경우 "변형"대신 "결합"
TraumaPony

처음에는 세 가지 답변이 BEST 답변입니다. 먼저 Nasser의 기사 링크 (이론적 하이 레벨)를 읽은 다음 chakrit의 답변 (지도 축소에 대한 개별 설명) 이제 Frank의 답변 (유명한 MapReduce 관용구는 무엇입니까) 감사합니다. :)
Ajeet Ganga

20

MAP 및 REDUCE는 사람이 마지막 공룡을 죽인 때부터 오래된 Lisp 기능입니다.

이름, 거주 인원 및 도시 크기에 대한 정보가있는 도시 목록이 있다고 가정합니다.

(defparameter *cities*
  '((a :people 100000 :size 200)
    (b :people 200000 :size 300)
    (c :people 150000 :size 210)))

이제 인구 밀도가 가장 높은 도시를 찾고 싶을 것입니다.

먼저 MAP을 사용하여 도시 이름 및 인구 밀도 목록을 만듭니다.

(map 'list
     (lambda (city)
         (list (first city)
               (/ (getf (rest city) :people)
                  (getf (rest city) :size))))
     *cities*)

=>   ((A 500) (B 2000/3) (C 5000/7))

REDUCE를 사용하여 인구 밀도가 가장 높은 도시를 찾을 수 있습니다.

(reduce (lambda (a b)
          (if (> (second a) (second b))
             a
             b))
        '((A 500) (B 2000/3) (C 5000/7)))

 =>   (C 5000/7)

두 부분을 결합하여 다음 코드를 얻습니다.

(reduce (lambda (a b)
          (if (> (second a) (second b))
             a
             b))
        (map 'list
             (lambda (city)
                (list (first city)
                   (/ (getf (rest city) :people)
                      (getf (rest city) :size))))
             *cities*))

함수를 소개하자 :

(defun density (city)
   (list (first city)
         (/ (getf (rest city) :people)
            (getf (rest city) :size))))

(defun max-density (a b)
   (if (> (second a) (second b))
          a
          b))

그런 다음 MAP REDUCE 코드를 다음과 같이 작성할 수 있습니다.

(reduce 'max-density
        (map 'list 'density *cities*))

 =>   (C 5000/7)

호출 MAP하고 REDUCE(평가는 내부에 있음), map reduce 라고 합니다 .


@MoMolog : MAX 함수는 이미 존재하며 약간 다른 기능을 수행합니다. 또한 : MAX를 재정의해서는 안됩니다.
Rainer Joswig

max-density전달 된 인수 의 두 번째 요소를 비교합니다 . 바보 같은 편집에 대해 죄송합니다.
Alexander Presber

@MoMolog : 예, 두 번째 요소이며이 작은 예제의 맥락에서만 유용합니다. 이 코드는 의도적으로 데이터 구조로 목록이있는 약간 오래된 스타일 Lisp로 작성되었습니다.
Rainer Joswig

17

Google 논문 에서 예제를 보자 . MapReduce의 목표는 어떤 종류의 알고리즘에 대해 병렬로 작업하는 많은 처리 단위를 효율적으로 사용할 수 있도록하는 것입니다. 예를 들면 다음과 같습니다. 모든 단어와 단어 수를 문서 세트에서 추출하려고합니다.

일반적인 구현 :

for each document
    for each word in the document
        get the counter associated to the word for the document
        increment that counter 
    end for
end for

MapReduce 구현 :

Map phase (input: document key, document)
for each word in the document
    emit an event with the word as the key and the value "1"
end for

Reduce phase (input: key (a word), an iterator going through the emitted values)
for each value in the iterator
    sum up the value in a counter
end for

그 주위에, 당신은 Map 단계를 위해 병렬로 처리 될 "분할"로 문서 세트를 분할하는 마스터 프로그램을 갖게 될 것입니다. 방출 된 값은 작업자에 의해 특정 버퍼에 작성됩니다. 마스터 프로그램은 버퍼 처리 준비가 완료되었음을 알리는 즉시 다른 작업자에게 Reduce 단계를 수행하도록 위임합니다.

모든 작업자 출력 (Map 또는 Reduce worker)은 실제로 분산 파일 시스템 (Google의 경우 GFS) 또는 CouchDB의 분산 데이터베이스에 저장된 파일입니다.


10

정말 쉽게 , 빨리"인형에 대한"는 : 맵리 듀스 소개에서 확인할 수있다 http://www.marcolotz.com/?p=67

내용 중 일부를 게시 :

우선, MapReduce가 원래 만들어진 이유는 무엇입니까?

기본적으로 Google은 대규모 계산 작업을 쉽게 병렬화하여 네트워크를 통해 연결된 여러 컴퓨터에 데이터를 배포 할 수있는 솔루션이 필요했습니다. 그 외에도 기계 고장을 투명하게 처리하고로드 밸런싱 문제를 관리해야했습니다.

MapReduce의 진정한 장점은 무엇입니까?

MapReduce 매직은 Map and Reduce 함수 응용 프로그램을 기반으로합니다. 나는 배우자를 고백해야한다. MapReduce를 대중화 한 주요 기능은 간단한 인터페이스와 결합 된 자동 병렬화 및 분배 기능입니다. 이러한 요소는 대부분의 오류에 대해 투명한 실패 처리와 결합하여이 프레임 워크를 대중적으로 만들었습니다.

종이에 조금 더 깊이 :

MapReduce는 원래 Google 논문 (Dean & Ghemawat, 2004 – 여기 링크)에서 병렬 접근 방식과 상용 컴퓨터 클러스터를 사용하여 빅 데이터에서 계산을 수행하는 솔루션으로 언급되었습니다. Java로 작성된 Hadoop과 달리 Google의 프레임 워크는 C ++로 작성됩니다. 이 문서는 대규모 데이터 세트에서 기능 프로그래밍의 맵 및 축소 기능을 사용하여 병렬 프레임 워크가 어떻게 작동하는지 설명합니다.

이 솔루션에는 Map과 Reduce라는 두 가지 주요 단계가 있으며, 첫 번째 단계와 두 번째 단계 사이의 선택적 단계 인 Combine이라고합니다. 맵 단계가 먼저 실행되고 입력 키-값 쌍에서 계산을 수행하고 새로운 출력 키-값을 생성합니다. 입력 키-값 쌍의 형식이 출력 형식 쌍과 반드시 ​​일치 할 필요는 없습니다. 감소 단계는 동일한 키의 모든 값을 어셈블하여 다른 계산을 수행합니다. 결과적으로이 마지막 단계는 키-값 쌍을 출력합니다. MapReduce의 가장 간단한 응용 프로그램 중 하나는 단어 수를 구현하는 것입니다.

이 응용 프로그램의 의사 코드는 다음과 같습니다.

map(String key, String value):

// key: document name
// value: document contents
for each word w in value:
EmitIntermediate(w, “1”);

reduce(String key, Iterator values):

// key: a word
// values: a list of counts
int result = 0;
for each v in values:
    result += ParseInt(v);
Emit(AsString(result));

알 수 있듯이 맵은 레코드의 모든 단어를 읽고 (이 경우 레코드는 행이 될 수 있음) 단어를 키로, 숫자 1을 값으로 내 보냅니다. 나중에 Reduce는 동일한 키의 모든 값을 그룹화합니다. 예를 들어 보자. '집'이라는 단어가 기록에 세 번 나온다고 상상해보십시오. 감속기의 입력은 [house, [1,1,1]]입니다. 감속기에서는 키 하우스에 대한 모든 값을 합산하여 다음 키 값을 출력으로 제공합니다. [house, [3]].

다음은 MapReduce 프레임 워크에서 어떻게 보일지에 대한 이미지입니다.

원본 MapReduce Google 논문의 이미지

MapReduce 애플리케이션의 몇 가지 다른 고전적인 예로써 다음과 같이 말할 수 있습니다.

• URL 액세스 횟수

• 역 웹 링크 그래프

• 분배 된 그렙

• 호스트 당 항 벡터

너무 많은 네트워크 트래픽을 피하기 위해이 백서에서는 프레임 워크가 데이터 로컬 성을 유지하는 방법을 설명합니다. 즉, 맵 작업을 실행하는 시스템이 네트워크에서 데이터를 가져 오지 않고 항상 메모리 / 로컬 스토리지에 데이터를 가지고 있는지 확인해야합니다. 매퍼를 넣어 네트워크를 줄이기 위해 앞에서 설명한 선택적 결합기 단계가 사용됩니다. 컴 바이 너는 지정된 머신에서 매퍼의 출력을 계산하여 리듀서로 보내기 전에 다른 머신에있을 수 있습니다.

이 문서는 또한 오류 발생시 프레임 워크 요소가 어떻게 작동해야하는지 설명합니다. 이 문서에서 이러한 요소를 작업자 및 마스터라고합니다. 그것들은 오픈 소스 구현에서보다 구체적인 요소로 나뉩니다. Google은이 문서의 접근 방식 만 설명하고 독점 소프트웨어를 출시하지 않았으므로 모델을 구현하기 위해 많은 오픈 소스 프레임 워크가 만들어졌습니다. 예를 들어 MongoDB의 Hadoop 또는 제한된 MapReduce 기능을 말할 수 있습니다.

런타임은 입력 데이터 파티셔닝, 대규모 머신 세트에서 프로그램 실행 스케줄링, 머신 장애 처리 (투명한 방식으로) 및 머신 간 통신 관리와 같은 비전문가 프로그래머 세부 사항을 처리해야합니다. . 숙련 된 사용자는 입력 데이터가 작업자간에 분할되는 방식으로 이러한 매개 변수를 조정할 수 있습니다.

주요 컨셉:

내결함성 :기계 고장을 정상적으로 견뎌야합니다. 이를 수행하기 위해 마스터는 작업자를 주기적으로 핑합니다. 마스터가 정해진 시간 경과에 지정된 작업자로부터 응답을받지 못하면 마스터는 해당 작업자에서 작업을 실패한 것으로 정의합니다. 이 경우 결함이있는 작업자가 완료 한 모든 맵 작업이 버려지고 사용 가능한 다른 작업자에게 제공됩니다. 작업자가 여전히 맵 또는 축소 작업을 처리하는 경우에도 마찬가지입니다. 작업자가 이미 축소 부분을 완료 한 경우 모든 계산은 실패한 시점까지 이미 완료되었으므로 재설정 할 필요가 없습니다. 기본 실패 지점으로 마스터가 실패하면 모든 작업이 실패합니다. 이러한 이유로, 데이터 구조를 저장하기 위해 마스터에 대한주기적인 체크 포인트를 정의 할 수 있습니다.

로컬 성 : 네트워크 트래픽을 피하기 위해 프레임 워크는 모든 입력 데이터가 컴퓨터에서 계산을 수행 할 머신에 로컬로 제공되는지 확인합니다. 원래 설명에서는 복제 팩터가 3으로 설정되고 블록 크기가 64MB 인 Google File System (GFS)을 사용합니다. 이는 64MB의 동일한 블록 (파일 시스템에서 파일을 구성하는)이 세 개의 다른 시스템에서 동일한 사본을 갖게됨을 의미합니다. 마스터는 블록이 어디에 있는지 알고 해당 기계에서 맵 작업을 스케줄하려고합니다. 실패하면 마스터는 작업 입력 데이터의 복제본 (예 : 데이터 시스템의 동일한 랙에있는 작업자 시스템) 근처에 시스템을 할당하려고합니다.

작업 세분성 : 각 맵 단계가 M 조각으로 나누어지고 각 축소 단계가 R 조각으로 나뉜다 고 가정하면 M과 R이 작업자 기계 수보다 훨씬 큰 것이 이상적입니다. 이는 다양한 작업을 수행하는 작업자가 동적로드 밸런싱을 개선하기 때문입니다. 그 외에도 작업자가 실패한 경우 복구 속도가 향상됩니다 (완료된 많은 맵 작업이 다른 모든 시스템에 분산 될 수 있기 때문에).

백업 작업 : 때때로 맵 또는 리듀서 작업자가 클러스터의 다른 작업자보다 훨씬 느리게 동작 할 수 있습니다. 이것은 전체 처리 시간을 보유 할 수 있으며 단일 느린 기계의 처리 시간과 동일하게 만들 수 있습니다. 원본 백서는 MapReduce 작업이 완료 될 때 마스터가 예약하는 백업 작업이라는 대체 방법을 설명합니다. 이들은 진행중인 작업의 마스터에 의해 예약 된 작업입니다. 따라서 기본 또는 백업이 완료되면 MapReduce 작업이 완료됩니다.

카운터 : 때때로 이벤트 발생 횟수를 계산할 수 있습니다. 이러한 이유로 생성 된 위치를 셉니다. 각 작업자의 카운터 값은 주기적으로 마스터에 전파됩니다. 그런 다음 마스터는 성공적인 맵의 카운터 값을 집계하고 (Yep. Pregel 어 그리 게이터가이 위치에서 온 것 같습니다) MapReduce 작업이 완료되면 작업을 줄이고 사용자 코드로 반환합니다. 마스터 상태에서 사용 가능한 현재 카운터 값도 있으므로 프로세스를보고있는 사람은 동작 상태를 추적 할 수 있습니다.

글쎄, 나는 위의 모든 개념으로 Hadoop이 당신을위한 케이크 조각이 될 것이라고 생각합니다. 원래 MapReduce 기사 또는 관련 사항에 대해 궁금한 점이 있으면 알려주십시오.


4

나는 trite 소리를하고 싶지 않지만 이것은 매우 도움이되었으며 매우 간단합니다.

cat input | map | reduce > output

4

Python에 익숙한 경우 MapReduce에 대한 가장 간단한 설명은 다음과 같습니다.

In [2]: data = [1, 2, 3, 4, 5, 6]
In [3]: mapped_result = map(lambda x: x*2, data)

In [4]: mapped_result
Out[4]: [2, 4, 6, 8, 10, 12]

In [10]: final_result = reduce(lambda x, y: x+y, mapped_result)

In [11]: final_result
Out[11]: 42

이 경우 원시 데이터의 각 세그먼트가 개별적으로 처리 된 방법 (이 경우 MapReduce 의 부분) 에 2를 곱한 방법을 확인하십시오 . 에 기초 mapped_result하여 결과는 42( MapReduce 의 축소 부분) 이라고 결론을 내 렸습니다 .

이 예제에서 중요한 결론은 각 처리 청크가 다른 청크에 의존하지 않는다는 사실입니다. 예를 들어 thread_1maps [1, 2, 3]thread_2maps [4, 5, 6]인 경우 두 스레드의 최종 결과는 여전히 [2, 4, 6, 8, 10, 12]있지만 처리 시간 은 절반으로 줄었 습니다. 감소 작업에 대해서도 마찬가지이며 MapReduce가 병렬 컴퓨팅에서 작동하는 방식의 본질입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.