pyspark를 써봅시다. 그리고 빠른지도 확인해봅시다.

what is pyspark

  • pyspark는 apache spark를 python에서 실행하기 위한 api입니다.
  • 위키피디다에는 다음과 같이 소개되어 있습니다.

Apache Spark has as its architectural foundation the resilient distributed dataset (RDD), a read-only multiset of data items distributed over a cluster of machines, that is maintained in a fault-tolerant way.

  • 한국어로 대략 “RDD(Resilient Distributed Dataset)을 지원하는 아키텍쳐이며, RDD는 read-only를 목적으로 다양한 머신에 데이터셋의 멀티셋(중복을 허용)을 분산해두고 특정한 머신에 문제가 생기더라도 문제없이 읽을수로 있도록 지원한다” 정도로 번역(및 의역)할 수 있을 것 같아요.

do it

  • 설치 프로세스는 이 블로그를 참고하여 진행했습니다.

  • 일단 설치를 합니다. 설치하는데 약간의 시간이 소요됩니다.

conda install pyspark 
  • 제가 참고한 블로그에서는 java도 설치해야 하고 하는데, 저의 경우 java는 예전에 설치해서 더 진행할 필요가 없습니다. 그래서 그냥 바로 실행을 하면
pyspark 
  • 아래처럼 잘 실행이 됩니다. 다만 중간에 보면 NativeCodeLoader:62 - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable이라는 말이 있습니다. hadoop이 안 깔려 있으니 java를 이용해서 진행하겠다는 말이죠. 필요하면 hadoop을 아예 설치하고 진행하는 것도 괜찮을 것 같아요.
Python 3.6.5 |Anaconda, Inc.| (default, Apr 26 2018, 08:42:37)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

2018-08-31 12:58:37 WARN  NativeCodeLoader:62 - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 2.3.1
      /_/

Using Python version 3.6.5 (default, Apr 26 2018 08:42:37)
SparkSession available as 'spark'.

performance test

  • 보통 pyspark는 속도가 빨라서 쓴다고들 합니다. 실제로 pyspark는 DB, list처러 데이터 묶음이 있을때 이를 병렬로 처리해서 속도를 빨리 처리해주거든요. 매트릭스 연산과 비슷하다고 생각해도 일단은 상관없습니다.
  • 그래서 속도를 비교해보려고 합니다. pyspark, pure python, numpy 이렇게 세 가지에 대해서 pi를 계산할때 n이 커짐에 따라서 속도 차이가 어떻게 달라지는지를 정리해봤습니다.
## 필요한 라이브러리를 불러옵니다. 
import time
import matplotlib.pyplot as plt
import numpy as np 
import pandas as pd
## pyspark를 불러옵니다.
from pyspark import SparkContext

## 이미 spark context가 살아 있으면 죽이고, 있으면 그대로 사용합니다. 
## spark context는 한 번에 여러 개 돌리려면 세팅에 몇 개를 추가해야 하는것 같아요. 
## 또한 스파크 컨텍스트를 제대로 구현하려면 여기에 넘겨야 하는 값들이 많이 있습니다만, 저는 테스트만 하려고 해서 이걸 대충 세팅했습니다. 
if sc is None: 
    sc = SparkContext(master="local", appName="first app")
else:
    sc.stop()
    sc = SparkContext(master="local", appName="first app")

## 이미 spark context가 살아 있으면 죽이고, 있으면 그대로 사용합니다. 
## spark context는 한 번에 여러 개 돌리려면 세팅에 몇 개를 추가해야 하는것 같아요. 
## 또한 스파크 컨텍스트를 제대로 구현하려면 여기에 넘겨야 하는 값들이 많이 있습니다만, 저는 테스트만 하려고 해서 이걸 대충 세팅했습니다. 
if sc is None: 
    sc = SparkContext(master="local", appName="first app")
else:
    sc.stop()
    sc = SparkContext(master="local", appName="first app")

### peformance check 
spark_time_lst = []
python_time_lst = []
python_np_time_lst = []
n_lst = [20000*i for i in range(0, 10)]
for n in n_lst:
    def each_k(k):
        return 1/(16**k)*( 4/(8*k+1) - 2/(8*k+4) - 1/(8*k+5) - 1/(8*k+6))
    ## with spark 
    start_time = time.time()
    pi_approximated = sc.parallelize(range(0, n)).map(each_k).sum()
    spark_time_lst.append(time.time()-start_time)
    ## pure python
    start_time = time.time()
    pi_approximated = sum((each_k(k) for k in range(0, n)))
    python_time_lst.append(time.time()-start_time)
    ## with numpy 
    start_time = time.time()
    pi_approximated = np.apply_along_axis(arr=np.array(range(0, 10)), func1d=each_k, axis=0).sum()
    python_np_time_lst.append(time.time() - start_time)

### plotting     
df = pd.DataFrame({
    "spark":spark_time_lst.copy(), 
    "pure python":python_time_lst.copy(), 
    "python with numpy":python_np_time_lst.copy()
}, index = [20000*i for i in range(0, 10)])
plt.figure(figsize=(12, 6))
plt.plot(df['spark'], 'ro-'), plt.plot(df['pure python'], 'bo-'), plt.plot(df['python with numpy'], 'go-')
plt.legend(fontsize=25)
plt.xticks([20000*i for i in range(0, 10)], [20000*i for i in range(0, 10)])
plt.savefig('../../assets/images/markdown_img/180831_pyspark_performance_check.svg')
plt.show()

wrap-up

  • 사실 피지컬 레벨에서 모르니까 이걸 판단하기는 어려워요. 제 맥은 cpu가 멀티코어도 아닐 거라서, 조금 애매하긴 합니다.
  • 이러니 저러니 해도, numpy가 제일 빠르네요. 물론 pyspak는 RDD를 이용해서, 즉 멀리서 데이터를 가져올때 중간에 데이터가 삭제되거나 없어질 때의 문제가 있으니까, 그 안정성을 고려하면 pyspark가 유용하겠죠.

reference

댓글남기기