Big Data Analysis with Scala and Spark



  Coursera mooc 중 Functional Programming in Scala 의 4번째 코스이다. Scala 언어로 작성된 Big Data Analysis 를 하기 위한 툴인 Spark 의 원리 및 사용 방법 등을 알려준다. Spark의 장점이나 Hadoop 과의 차이점 등은 이 과정에서 따로 설명하지 않고, 오직 Scala와 연관된 부분만 설명하고 있다.

  week1에서는 일반적인 Parallel Programming과 Distributed Programming의 차이점 및 특징 등을 설명해준다. Distributed System에서는 Cluster들이 Network를 통해 연결되기 때문에 Network Latency가 발생한다. 이를 고려하여 실시간 데이터 분석을 지원하는 것이 바로 Spark라고 언급한다. 이 외에 Spark에서 사용하는 기본 데이터 Collection인 RDD(Resilient Distributed DataSet)및 기본적인 RDD 사용법을 소개한다.  


  week2에서는 RDD를 가지고 Reduction Operation 작업을 어떻게 하는지 설명한다. 또, Pair RDD 및 이를 활용한 데이터 조작 방법 등을 설명한다. RDD에서 Transformation 작업을 수행할 때마다 해당 작업을 실행하는 것이 아닌, Lazy Evaluation을 활용하여 작업을 뒤로 미룬다. 그러다가 특정 순간에 Action 작업을 수행하면 뒤로 미뤄진 작업들과 함께 한꺼번에 작업을 수행하여 결과물을 내놓는다. 마지막으로 여러 RDD들을 하나로 합치는 Join 동작도 설명한다. Spark에서 사용하는 명령어들은 SQL에서 사용하는 명령어와 비슷한 명령어를 가지고 있다.


  week3에서는 다행스럽게도(?) 과제가 없다. 대신에 아주 중요한 개념인 Shuffling을 설명한다. Shuffling은 Cluster간에 데이터들이 네트워크를 통하여 이동한다는 개념이다. 예를 들어 key를 가진 Pair RDD에서 join()과 같은 작업을 수행하면 Cluster 안에서 기준없이 섞인 key, data 셋들이 특정한 key로 구분된 Partition들로 각 Cluster에서의 데이터들이 이동한다는 개념이다. 그래서, Shuffling 작업이 수행되기 전에, 불필요한 작업들을 모두 수행하고(reduce작업 등을 통한 데이터 축소) 필요할 때에 Shuffling 작업을 수행하라는 것이 week3 의 전반적인 내용이다. 또 Partition을 효율적으로 나누는 여러가지 방법 등을 소개한다.


  week4는 마지막 주차인데, 내가 생각하기에는 두 주 분량의 강의를 하나로 합친 것과 같은 중요함과 강의 량을 보여주고 있다. 우선 Structured vs Unstructured Data를 설명하면서 Structured data나 semi-structured data에서는 Spark SQL 및 DataFrames를 사용하라고 주장한다. DataFrame는 csv, json 등 기존에 알려진 데이터 형식을 이용하여 Query를 작성했을 때, RDD 및 Scala Higher-order Function을 직접 사용하는 것처럼 번거로운 작업을 하지 않고도 아주 최적화된 함수들을 제공한다. 프로그래밍을 할 때, 데이터를 다루는 일을 하다보면 DataBase에서 등장하는 Query나 각종 이론들이 계속 등장한다. DB에 관한 개념이 부족하다면, 나처럼 DataFrame을 다룰 때 오히려 RDD를 다룰 때보다 더 애를 먹을 수 있다. 마지막으로, DataSets에 대하여 설명한다. DataSet은 Spark 2.0 이후에 등장한 개념으로, RDD와 DataFrame를 합쳐 놓은 것이라고 간단하게 생각할 수 있다. RDD의 Higher-Order Function 및 DataFrame의 Query 등을 함께 사용할 수 있다.

Parallel programming


  Coursera mooc 중 Functional Programming in Scala 의 3번째 강의이다. 1,2번째 강의에서 배운 Scala 기본, 심화 과정을 이용해 Parallel Programming을 주로 다루는 강의이다. 1,2의 강의를 듣지 않더라도, Scala에서 제공하는 Collection을 어느 정도 다룰 줄 안다면, 이 강의만 수강해도 무방할 듯 하다.

  week1에서는 Parallel Programming 이론 및 Java, JVM에서 다루는 Parallel Programming 방법 등을 다룬다. Java 언어를 가지고 Multi-Thread 프로그램을 작성했다면, 빠르게 이해하며 넘어갈 수 있다. 그리고 앞으로 진행할 수업 과정에서 Parallel Program에 대하여 어떻게 성능을 측정하는 지를 다룬다.

  week2 부터 본격적으로 Parallel Programming에 대하여 다룬다. 기본적인 내용으로 merge sort를 parallel 하게 구현하는 방법을 알려준다. 그리고 Fold(Reduce) 에 관한 내용에 대해 설명한다. 이 때, Fold를 수행하기 위한 Iterable[T] 객체가 있을 때, type T가 Associative 해야 Parallel Fold 작업이 항상 같은 값을 리턴한다는게 주 내용이다. 여기서 말하는 Associative는 다음과 같다.

연산 + 가 있을 때,
A + (B + C) = (A + B) + C 를 만족하면
+ 연산은 Associative 하다는 것이다. (흔히 말하는 결합법칙)


  week3 부터는 Scala에서 쓰이는 다양한 Data-Parallel Programming 을 알려준다. 기존 Collection에서 .par 함수를 호출하면 바로 Parallel한 Collection을 얻을 수 있다. 그리고 FoldLeft 는 Parallel 하게 동작할 수 없다는 것을 설명한다.


  foldLeft의 정의는 다음과 같다.


foldLeft[B](z: B)(f: (B, A) => B): B


  foldLeft를 진행 중, f 함수의 리턴 타입 A가 B와 같지 않다면, foldLeft의 다음번 차례에서 함수 매개변수 인자인 B의 위치에 들어갈 수 없다. 이러한 특성 때문에 foldLeft는 Palallel하게 사용할 수 없다.


  foldLeft 대신, fold와 foldLeft를 조합한 aggregate 함수를 제공한다. aggregate 함수는 재귀함수를 통해 Parallel 하게 fold 함수를 진행하다가 특정 threshold보다 낮을 경우에 foldLeft를 수행한 뒤, 다시 합치는 모습을 보여준다.


  그리고, week 3에서 K-means 알고리즘을 토대로한 연습문제를 제공하는데, 이런 심도있는 연습문제를 통해 Parallel Programming이나 Scala 등의 Functional Programming이 어떤 방식으로 쓰일 수 있는지 알려준다.


  마지막 week4에서는 Combinator이라는 trait와(Java에서의 Interface와 비슷한 개념) Conc-tree라는 듣도 보도 못한 새로운 자료구조를 알려준다. Scala의 Collection 들은 Combinator trait의 combine() 함수를 통하여 Parallel 하게 동작하기 위해 쪼개졌던 작은 sub-collection 들을 다시 합치는 동작을 제공한다. Array, Set, Tree 등을 combine할 때 최적화 하기 위한 동작이 서로 다르기 때문에, combine() 함수를 통하여 추상화를 제공한다고 볼 수 있다.


  week4 의 마지막으로 가면서 Conc-Tree 자료구조와 이를 Parallel하게 동작시키기 위한 Combiners 를 소개한다. Conc-Tree 에 특정 element를 추가할 때 걸리는 시간 O(1) 과 Conc-Tree 에 다른 Conc-Tree를 Concatenation을 할 때 O(log N) 을 보장하기 위해 Binary Count System을 사용한다. Concatenation을 할 때 트리의 노드 균형을 맞추기 위해 AVL tree나 Red-Black Tree에서 볼 수 있는 회전 동작도 구현하고 있다. 연습문제를 풀 때, Conc-Tree를 직접 구현하지 않기 때문에 자세하게 살펴보지는 않았지만, 이런 자료구조가 있다는 것을 알고 나중에 사용하면 될 것 같다는 생각이 들었다.


  Parallel Programming 수업을 들었을 때 중요하게 생각한 점은, Associativity 와 Commutativity 같은 수학 개념이 사용되었다는 것이다. 고 수준의 프로그래밍을 할 때, 항상 나의 발목을 잡는 것이 수학 이론이다. 알고리즘에서만 수학이 사용되는줄 알았지만, 다양한 분야에서 수학을 기본으로 프로그래밍을 하고 있다. 처음부터 수학을 다시 공부할 수는 없으니, 문제를 해결하려고 할 때 수학이 등장한다면, 대충 넘어가지 말고 머리 속에 꾸겨 넣어서 다음 task로 넘어가야 겠다.

Functional Program Design in Scala


  Scala 언어를 만든 마틴 오더스키 교수의 Coursera MOOC 2탄이다. 1탄에 대한 소감은 이 링크에 있다. 1탄에서는 Scala와 Functional Programming의 기본 과정을 다뤘다면, 이번 강의는 심화 과정을 다룬다.


  처음에는 1장에서 배웠던 for 구문에 대한 심화 과정을 알려준다. for와 yield를 조합한 코드는  Scala 컴파일러가 map, flatMap 과 같은 Higher-order Function으로 변경시킨 후, 해당 작업을 처리한다. 이러한 변환은 Higher-order Function을 직접 사용하는 것보다 code에 대한 추상화를 더 강력하게 지원한다. 그리고 난수를 생성하는 방법을 함수형 스럽게 지원한다. 가장 작은 기본 단위인 Int형 난수 생성기를 이용해, 단계적으로 아주 큰 범위의 난수까지 생성하는 과정을 보여준다. 이 장의 마지막에는 함수형 프로그래밍의 끝판왕 중 하나인 Monad에 대해 설명하고 있다. Scala에서 Monad는 flatMap() 함수로 나타난다. Monad는 카테고리 이론에서 나온 것으로써, 단어 자체의 어원과는 전혀 상관없는 이론을 나타낸다. Monad에 대해서 이 강의에서는 기본적인 개념만 설명하고 있다. 이 강의를 가지고 Monad를 완벽하게 이해하는 것은 어려운 것 같다. Scalaz 라이브러리나 스칼라로 배우는 함수형 프로그래밍 책, 또는 Haskell 프로그래밍 언어나 Category Theory 책 같은 것을 이용하여 향우에 깊기 파야지 완벽하게 이해할 수 있을 것 같다.


  2장에선는 Lazy Evaluation 에 관한 설명을 한다. Lazy Evaluation을 위한 lazy 키워드나 Stream 클래스를 설명하고, 이를 이용하여 Infinite Sequences를 생성하는 방법을 알려준다. Lazy Evaluation을 이용하면 런타임에서 특정 값을 사용할 때, 필요한 경우에만 값을 계산하여 준비를 한 후 사용하기 때문에, 프로그램의 최적화가 가능하다.


 3장에서는 실무에서 쓰일법 한 프로그래밍인 상태(state)를 주제로 다루고 있다. 논리회로 시간에 배웠던 가산기를 만드는 방법을 Scala 코드로 알려준다. And gate나 Or gate 등을 이용해 Half Adder, Full Adder 등을 조합해서 만드는 방법을 State를 가지고 만든다. 역시 작은 단위부터 큰 단위까지 만들기 위한 점진적인 방법을 사용하는데, 이것이 함수형 프로그래밍의 장점 중 하나인 것 같다.


  마지막 장에서는, 얼마 전에 한참 유행하던 FRP(Functional Reactive Programming)을 우선 다룬다. 기존 Imperative Programming에서 다루던 MVC와 같은 구조는 Muti-Threading 환경에서 동기화 처리를 하기 힘든데, FRP를 사용하면 이런 작업이 아주 편하다는 장점을 알려준다. FRP 의 기본 개념 및 간단한 FRP를 구현하는 방법을 알려준다. 그 뒤에 Future를 중점적으로 다룬다. Future를 설명할 때 에릭 매이어가 오더스키 교수를 대신해 강의를 한다. 마이어는 Microsoft 재직 당시 C#의 RINQ를 만들고, Async이나 Await 같은 동시성 프로그래밍 개념을 만들어 다른 프로그래밍 언어로까지 전파시킨 네임드 개발자이다. 강의가 오더스키 교수 때와는 다르게, 대화를 하는 것 같은 재미있는 상황이 펼쳐졌지만, 오더스키 교수가 구사하던 깔끔한 영어와는 다르기 때문에 약간 알아듣기가 힘들었다. 마이어가 C9에서 Haskell 을 가지고 진행한 함수형 프로그래밍 강의가 있는데, 이 것도 시간이 되면 수강할 예정이다. 강의 마지막에는 Future의 Monad(flatMap) 을 구현하는 방법을 알려주는데, 아직 내공이 부족해서 고개만 끄덕거리고 넘어갔다.


  두 개의 Scala를 이용한 Functional Programming 강의를 들었는데, 책으로 보던 것보다는 내공이 많이 쌓인 것 같다. 좀 더 학문적으로 접근하기 위해 Category Theory는 Functional Programming에서는 필수인 것 같다. 좀 더 내공이 쌓이면 Monad나 Category Theory에 대한 포스팅을 할 예정이다. 또, Functional Programming에 관해 얘기하는 사람들을의 대다수는 SICP에 대해서도 언급을 많이 하고 있다. 봐야할 책과 자료들이 산처럼 쌓이고 있다. 이런 것들을 보다 보면, 좀 더 나은 개발자가 될 수 있다고 믿기 때문에 재미 없을 때까지 계속 산더미를 치워야 겠다.

Functional Programming Principles in Scala


  Scala 언어를 만든 마틴 오더스키 교수가 직접 강의하는 MOOC로써, 2012년에 제작된 것으로 추정된다. 강의 하나에 70달러 이상의 가격을 주고 수강을 완료하면 수료증을 받을 수 있다. 이 수료증은 Linked in 에 연동이 가능하다. 수료증이 필요하지 않으면 무료로 강의를 들을 수 있다. 나의 경우에는 돈을 주고 수강을 해야 돈이 아깝다고 생각하여 열심히 공부를 하는 스타일이므로, 이 강의 외에도 패키지로 수강할 수 있는 강의 5개를 한꺼번에 결제하여 10%의 할인을 받았다.


  내가 처음 Scala 언어가 있다는 것을 알고 공부를 시작한게 2016년이니, 참으로 늦게 시작한 것 같다. 함수형 프로그래밍이나 Scala, Haskell 에 대한 것이 있다는 것을 진작부터 알았으면 하는 아쉬움이 있다. 프로그래머로써 어떻게 공부를 해 나가야할 지 몰랐던 나의 미숙한 점도 있지만, 회사에서 프로그래머로써의 실력을 증진시키지 않는 회사 주변의 상사나 동료들 탓도 있는 것 같다. 결정적으로 Tizen Platform App 개발과 현업에서 전혀 사용하지 않는 아주 미세한 부분을 다루는 알고리즘 시험을 채택한 회사 때문에 저런 것들을 늦게 접한 면도 있다.


  이 강의에서는 일반적인 책에서 배울 수 있는 Scala에 대한 내용을 주로 다루고 있다. Currying이나  Higher-Order-Function, 각종 Collection (List, Set, Map 등), Pattern Matching 등이다. 이론을 설명할 때 위에 언급한 것들을 단순히 어떻게 사용하는지만 알려주는 것이 아니라, 구체적인 사례를 들거나 이론에 대한 원리를 알려주는 점이 아주 좋았다.


  이론 강의 수강 외에도 각 주차별 강의에 따른 실습 과제를 해야 이 과정을 이수할 수 있지만, 예전에 다른 강의에서 했던 별도의 시험은 없었다. 실습은 Scala 빌드 도구인 SBT(Simple Build Tool) 프로젝트로 제공한다. 위에서 배운 이론을 토대로, 실제 현업에서 다룰 법한 문제나 커먼하게 알려진 알고리즘(허프만 코딩, 아나그램)을 구현하는게 주 목적이었다.


  과제를 하면서 두 가지 깨닮음(?)을 얻었다. 먼저, Scala의 Pattern Matching이 아주 강력한 기능이라는 점이다. 내가 전에 알고있던 패턴 매팅은 단순히 Int, String 타입과 같은 Primitive 타입을 편하게 다루기 위한 것인데, 이 것은 패턴 매칭의 아주 일부분이었다. 각종 Object나 Tuple, Collection을 패턴매칭과 각종 Recursive 패턴 등을 이용하여 조합해서 사용하면, Java 에서는 찾아볼 수 없는 추상화가 가능하다.

  두 번째로 느낀 점은, 바로 기존의 Object를 다루기 위한 Set(자료구조 Set이 아닌, 특정한 데이터 집합을 다룬다는 의미)과 동일하게 사용할 수 있도록 Functional Set을 다루는 방법과 그 원리를 과제를 통해서 알게 되었다. 이 것이 함수형 프로그래밍의 강력한 추상화에 도움을 주는 것 같다. 말로는 설명하기가 힘드니, 이 강의를 참고하길 바란다.


  이 강의에서는, 함수형 프로그래밍의 깊은 원리에 대해서는 파해치지 않고, 다음 강의인 [Functional Program Design in Scala] 로 떠넘겼다(?). 내가 MOOC를 통해서 정말로 습득하기 원하는 이론인 Monad를 다루고 있다. 지금 이 포스팅에서 설명하고 있는 강의는 Scala나 Functional Programming을 처음 접하는 분들이나 Scala를 책으로 공부하는데 명확하게 이해가 되지 않는 분들에게 추천하고 싶다.

+ Recent posts