하둡 스트리밍을 이용한 MR을 짜면서 다른 사람 코드를 많이 본 것은 아니기에 습관처럼 나만의 코딩 패턴으로 짜고 있었다. MR 스테이지 하나당 코딩량이 많지 않으며, 하둡 스트리밍 특성 상 import를 이용한 재사용성은 배재하고보니 뭐 그저그런 코드가 된다.
그러다가 문득 예제로 나온 코드들은 내가 짜는 코드와 패턴이 다르다는 것을 발견해따..
예컨데 다음과 같은 데이터가 매핑되었다.
a, 1
a, 2
a, 3
b, 2
b, 4
b, 6
이를 카운트하는 통상적인 예제는 이렇다. 파이썬이라면 딕셔너리를 활용할 것이고 PHP라면 연관 배열을 활용할 것이며 요즘의 보통스런 훌륭한 언어들이 다들 지원하는 MAP을 쓰면 된다.
my_key['a'] += 1
// 코드 내에서는 이렇게 될 것이다. input_key에 a나 b가 들어온다.
my_key[input_key] += 1
예제들은 이렇지만 나는 이렇게 짠 적이 한 번도 없다. C로 시작한 사람들이 이렇다. 이 코드는 키공간이 늘어나면 메모리를 드릅게 많이 먹는다. 때로 뻗을지도 모르며, 언어적 특성과 최적화에 따라서는 키공간이 늘어나면서 카운트 하는 +1 연산을 할 때마다 발생하는 키탐색이 캐시를 못 타고 CPU와 메모리가 뺑뺑이 탈 것이다. 해시맵을 O(1)이라고 하는데 내부 구현은 안 그렇다.
다른 사람들도 이렇게 짜는 지는 알 수 없다. 나는 쪼렙, 캐뉴비, 개초보다. 아직 들판에서 양때려 잡느라 허송세월하는 사람이다. 다른 사람들이 용을 잡으러 다니는지 오토 돌려놓고 똥싸러 갔는지 조차도 잘 모른다.
사실은, 하둡 스트리밍에 의해 소팅된 데이터가 들어오므로 이미 계산 끝난 키에 대해 알거나 탐색할 필요가 없다. 메모리를 아끼는 슈도 코드는 이렇다.
if prev_key == current_key:
key_count += 1
else:
print current_key, key_count
소팅된 순서대로 들어오므로 현재 바라보고 있는 키에 대해서 계산하고, 새 키가 들어오면 그냥 찍고 지나간 값에 대해서는 잊어버린다. 물론 위 코드는 초기화, 최초인지, 마지막인지에 대한 처리가 필요하다. if 문에 대한 비용은 추가되지만 이 쯤은 그냥 못본체.. 파이썬 등에서 다양한 1방 연산 스킬들이 제공되지만 요점은 이렇다. 1. 키공간이 늘어나는 속도에 비례하여 연산량이 증가하면 안 된다. 2. 단일 키 하나에 속한 데이터량이 늘어나는 속도에 비례하여 연산량이 증가하면 안 된다. 3. 아껴야 잘 살죠.