MapReduce란
1. map이란 방식으로 원하는 데이터를 추출한 다음에
2. reduce라는 방법으로 추출한 데이터를 정제하는 것을 말한다.
fig 1. MapReduce의 이해(https://docs.mongodb.com/manual/core/map-reduce/)
위의 그림에서 보면 알 수 있듯이 orders라는 컬렉션이 존재하는데
1. query를 통해 필요한 데이터를 뽑아내고 (status: "A")
2. map을 이용해 원하는 데이터의 key, value를 추출하여 (key: cust_id, value: amount[])
3. reduce를 이용하여 추출한 데이터를 정제한 것을 알 수 있다. (amount[]의 총합.)
만약 컬렉션 전체가 mapping의 대상이라면 위의 1번은 생략이 가능하다.
그럼 아래의 예제 데이터를 이용해서 MapReduce를 연습해보자.
============================ JSON ============================
{
"_id" : ObjectId("5a8fa53cf6d63ea4599c476b"),
"cust_id" : "A2012001",
"order_date" : ISODate("2012-09-30T15:00:00.000+0000"),
"status" : "A",
"price" : 250.0,
"items" : [
{
"item_name" : "Bunny Boots",
"qty" : 5.0,
"price" : 25.0
},
{
"item_name" : "Skey Pole",
"qty" : 5.0,
"price" : 25.0
}
]
}
{
"_id" : ObjectId("5a8fa53df6d63ea4599c476c"),
"cust_id" : "A2012001",
"order_date" : ISODate("2012-09-14T15:00:00.000+0000"),
"status" : "A",
"price" : 500.0,
"items" : [
{
"item_name" : "Bunny Boots",
"qty" : 15.0,
"price" : 25.0
},
{
"item_name" : "Skey Pole",
"qty" : 5.0,
"price" : 25.0
}
]
}
{
"_id" : ObjectId("5a8fa53df6d63ea4599c476d"),
"cust_id" : "A2012002",
"order_date" : ISODate("2012-09-14T15:00:00.000+0000"),
"status" : "A",
"price" : 500.0,
"items" : [
{
"item_name" : "Bunny Boots",
"qty" : 15.0,
"price" : 25.0
},
{
"item_name" : "Skey Pole",
"qty" : 5.0,
"price" : 25.0
}
]
}
============================ JSON ============================
위의 예제 데이터는 _id, cust_id, order_date, status, price, items 컬럼으로 구성된 order라는 컬렉션에 넣으면 된다.
이제 두 가지 MapReduce를 해보겠다.
=========================== Query ===========================
// 분산처리를 활용한 map함수로 데이터 가져오기
var map_function = function(){
// emit : 추출하다. (key, value)
emit(this.cust_id, this.price); // emit(key, value) 로 작성.
}
// 필터를 위한 reduce 함수
// function(변수, 변수) -> 변수 이름은 마음대로 정할 수 있다.
var reduce_function = function(keyCustId, valuesPrices){
// price가 들어있는 valuesPrices를 Array로 만들고 다 더한다.
return Array.sum(valuesPrices);
}
// 위에 있는 내용을 적용한 map, reduce메서드 처리
db.order.mapReduce( // .mapReduce(map함수, reduce함수, 어떻게 처리를 할 것인가.)
map_function,
reduce_function,
{out:"order_cust_total"} // order_cust_total이라는 컬렉션을 만들어서 그 컬렉션에 저장한다.
)
=========================== Query ===========================
먼저 cust_id를 key, price를 value로 하고 key에 해당하는 모든 price 값을 더해보는 프로그램이다.
map: (key: cust_id, value: price[])
reduce: (key: cust_id, value: sum[price])
데이터를 저장할 collection: order_cust_total
이제 본격적으로 MapReduce를 사용해보겠다.
=========================== Query ===========================
// 제품명별 수량의 평균
// order collection 안에 items라는 항목으로 입력되어 있다.
var map_function = function(){
for(var idx = 0 ; idx < this.items.length ; idx++){ // items는 리스트이므로 리스트 길이만큼 반복하여 모든 key, value를 뽑는다.
var key = this.items[idx].item_name; // key는 상품명 -> group
// 넘기려는 값이 2개 이상이면 json 데이터를 만든다.
var value = {
count: 1, // count에 무조건 1을 넣어서 나중에 총계를 확인할 때 쓴다.
qty: this.items[idx].qty // items에 있는 qty를 qty에 넣는다.
};
// 메서드이기 때문에 local에 위치하더라도 데이터는 emit()이 저장하는 장소에 저장되고 reduce_function에 넘어갈 수 있다.
// 그리고 emit()은 dictionary(자바에서 hashMap) 형태이기 때문에 key라는 네임스페이스에 value값들이 전부 저장되게 된다.
emit(key, value);
};
}
// map함수에서 넘겨준 데이터를 필터링하는 처리 -> reduce -> 합계를 구한다.
var reduce_function = function(keySKU, valueCountObject){
// 결과값을 내는 데이터가 2개 -> json으로 만든다.
var reducedValue = {
count:0,
qty:0
} // return 으로 넘길 데이터의 기본형태. reduceValue: count, qty.
for(var idx = 0; idx < valueCountObject.length; idx++){
// valuesCountObject 안에 있는 count를 reduceValues count 안에 넣어준다.
reducedValue.count += valueCountObject[idx].count;
reducedValue.qty += valueCountObject[idx].qty;
}
return reducedValue;
}
// finalize 함수를 정의해서 사용할 수 있다. -> 평균을 구한다.
var finalize_function = function(key, reducedValue){
// 평균을 구하기 위해 reducedValue에 average를 만들어서 qty/count로 평균을 만든다.
reducedValue.average = reducedValue.qty / reducedValue.count
}
// mapReduce 실행.
db.order.mapReduce(
map_function,
reduce_function,
{
// 만약 기존에 map_reduce_example 컬렉션이 있으면 이번에 만드는 것으로 대체한다.
out:{replace:"map_reduce_example"},
// 아까 위에 만든 finalize를 여기서 적용시킨다.
finalize:finalize_function
}
)
=========================== Query ===========================
위의 MapReduce보다 조금 어려워졌다.
일단 저 프로그램의 목적은
각 item_name이
1. 몇 번 팔렸는가
2. 몇 개가 팔렸는가
3. 평균적으로 1회 구매에 몇 개나 팔렸는가
를 구하는 MapReduce이다.
일단 대부분의 내용은 전부 주석으로 달아놨으므로 읽어보면 충분히 이해 할 수 있을 것이다.
'데이터베이스' 카테고리의 다른 글
[MongoDB] GeoSpatial index를 이용해보기 (0) | 2018.06.30 |
---|---|
[MongoDB] 시퀀스와 게시판 페이징처리 및 CRUD (0) | 2018.06.15 |
[Mybatis] root-context.xml 자료(Oracle) (0) | 2018.05.20 |
[Mybatis] pom.xml 자료(Oracle) (0) | 2018.05.20 |
MongoDB에 계정(유저) 추가하기 (0) | 2018.04.17 |