<jupyter_start><jupyter_text>4. 하둡을 활용한 데이터 입수이장에서 다룰 내용- 새로운 데이터 처리 패러다임으로 부상한 데이터 레이크의 개념- CSV 데이터를 HDFS와 하이브로 불러오는 기본적인 방법- 스파크로 데이터를 하이브 테이블이나 스파크 작업으로 불러오는 방법- 관계형 데이터와 HDFS 간의 데이터 송수신을 수행하는 아파치 스쿱- 스트리밍 데이터(예를 들면 웹 로그)를 HDFS로 수집, 정송하는 아파치 플럼- 하둡 입수 작업의 워크플로우를 관리하는 아파치 우지- 하둡 클러스터의 데이터 관제 프레임워크인 아파치 팔콘 프로젝트하둡은 처리할 데이터 종류가 무엇이든 HDFS에서 가져오거나, HDFS로 내보낼 수 있는 데이터 전송 도구를 활용할 수 있다. 일단 데이터가 HDFS에 저장되면 하둡 생태계의 다양한 처리 엔진으로 이 데이터를 분석할 수 있다.이 장에서는 하둡 데이터 레이크의 개념을 소개하고, 하둡으로 데이터를 입수하는 주요 도구(스파크, 스쿱, 플럼)의  개괄적인 설명과 몇 가지 구체적인 활용 예를 제시한다. 또한 데이터 입수 과정을 효과적으로 관리하는 워크플로우 도구(우지,팔콘 등)를 소개한다.  4.1 하둡 데이터 레이크데이터는 어디에나 있지만, 그렇다고 데이터를 저장하고 접근하는 과정이 항상 쉬운 건 아니다. 사실, 하둡 이전에 사용한 데이터 아키텍처들은 대부분 경직된 성실이 이었고 다루거나 병경하기도 어려웠다. 하지만 데이터 레이크라는 개념은 이 모든 것을 바꾸어 놓았따.그럼 데이터 레이크란 무엇일까?기존 데이터베이스나 데이터 웨어하우스는 사전에 정의된 스키마로 데이터를 변환하는 작업이 데이터를 적재하기 전에 필요했다. 이러한 데이터 입수 단계를 '추출, 변환, 적재'라고 부르며, 이 ETL 개발 단계를 거쳐 최종 애플리케이션에서 데이터를 활용하기까지 많은 시간과 노력, 비용이 소모되는 경우가 잦았다. 무엇보다 ETL의 개발 단계에서 데이터 사용 방법을 미리 결정해야 했으며 ETL 개발이 끝난 후 이 결정을 번복하려면 많은 노력과 비용이 소모되었다. 또한 데이터가 스키마에 맞지 않거나 필요 없어 보이거나 최종 애플리케이션에 중요하지 않다는 이유 등으로 입수한 데이터를 ETL 단계에서 폐기하는 경우도 많았다. 하둡의 주요 특징 중 하나는 모든 데이터를 HDFS에 저장할 수 있는 중앙 스토리지이며, 기존 시스템보다 훨씬 낮은 비용으로 대규모 데이터셋을 중복 저장할 수 있다는 것이다.즉, 하둡 데이터 레이크란 조직의 모든 데이터를 원시 형식으로 저장하는 중앙 스트리지를 말한다. 데이터 레이크는 하둡 애플리케이션이 데이터를 처리하는 시점에 이르러서야 비로소 종전의  ETL 단계와 유사한 데이터 변환 과정이 수행된다. 이러한 방식을 '스키마 온 리드'라고 하며, 프로그래머와 사용자가 원시 데이터에 자신이 원하는 구조를 적용할 수 있다는 장점이 있다. 반면, 기존 데이터 웨어하우스는'스키마 온 라이트'방식을 사용하며, 데이터가 어떻게 활용될지 사전에 추측하는 설계 단계를 반드시 거쳐야 한다.데이터 과학에서는 프로젝트에 중요한 데이터가 무엇인지 사전에 명확하게 파악하기 어려우므로 모든 데이터를 원시 형태로 유지하면 많은 이점을 누릴 수 있다.기존의 데이터 웨어하우스에 비해 데이터 레이크는 빅데이터 관점에서 다음 세 가지 이점이 있다.- 모든 데이터를 사용할 수 있다. 향후 데이터를 어떻게 사용할지를 사전에 추측할 필요가 없다.- 모든 데이터를 공유할 수 있다. 모든 데이터가 모든 실무자와 연구자에게 열려 있다. 이전에는 이기종 시스템의 데이터 구획화 때문에 일부 데이터에 쉽게 접근할 수 없었다.- 모든 데이터 접근 방식이 가능하다. 다양한 처리 엔진(맵리듀스, 테즈, 스파크)과 애플리케이션(하이브,스파크 SQL, 피그)을 이용해 데이터를 탐색하고 필요에 따라 처리할 수 있다.하지만 데이터 웨어하우스는 분명 유용한 비즈니스 도구이며, 하둡은 이를 대체한다기보다는 보완하도록 설계되었다. 그럼에도 기존 데이터 웨어하우스는 새로운 유형의 데이터가 등장한 빅데이터 시대 이전에 개발된 기술이다. 이미 소셜 미디어 데이터, 클릭 로그, 센서 데이터 등 여러 유형의 데이터가 데이터 레이크를 빠르게 채우기 시작했다. 기존 ETL 단계로는 이 같은 유형의 데이터가 유입되는 속도를 따라잡지 못할 것이다. 따라서 데이터 웨어하우스와 데이터 레이크 기술은 각각의 설계 목적에 맞는 요구 사항을 만족시키며 앞으로도 계속 공존할 것이다.그림에서는 세 데이터 소스(A, B, C)에서 생성되는 데이터가 ETL 과정과 데이터 레이크에 각각 유입된다. ETL 과정은 데이터를 관계형 데이터베이스에 저장하면서 스키마에 맞게 변환한다.(스키마 온 라이드). 반면, 데이터 레이크는 원시 형태 그대로 저장하며, 하둡 애플리케이션이 데이터 레이크에서 데이터를 읽어 들이는 시점에 이르러서야 비로소 스키마를 적용한다. ETL 단계에서는 몇몇 데이터를 버리는 경우가 있다. 물론 데이터 웨어하우스의 사용자도 원하는 데이터에 접근할 수 있다. 하지만 하둡에서는 데이터 레이크에 데이터가 입수되는 즉시 데이터에 접근 할 수 있다.  4.2 HDFS모든 하둡 애플리케이션은 하둡 분산 파일 시스템에 저장된 데이터를 바탕으로 실행된다. HDFS의 파일 작업은 대부분의 사용자에게 익숙한 로컬 파일 시스템과 분리돼 있다. 즉, 사용자는 필요한 파일을 로컬 파일 시스템에서 HDFS로 직접 복사하거나, HDFS에서 로컬 파일 시스템으로 복사해야 한다. HDFS는 일반적인 파일 시스템이 아니며 기존의 POSIX 또는 이와 유사한 파일 시스템을 대체할 수 없다.HDFS는 대용량 파일의 읽기 및 쓰기 작업에 최적화된 독특한 스트리밍 파일 시스템이다. HDFS에 파일을 저장하면, HDFS는 파일의 데이터를 슬라이스로 분할해 하둡 클러스터의 여러 서버에 이중으로 저장한다. 데이터의 분할 과정에서는 대용량 파일을 작은 단위의 블록으로 나눠 클러스터 노드에 '투명하게'저장한다. HDFS는 여러 슬라이스를 동시에 병렬로 처리하므로 파일 연산을 더 빠르게 처리할 수 있다. 사용자는 실제 파일 슬라이스를 직접 볼 수없지만, 모든 HDFS파일을 마치 일반 파일 시스템의 파일처럼 다룰 수 있다(파일 복사, 이동, 삭제 등). HDFS에서 호스트 파일 시스템으로 파일을 전송할 때는 분할된 슬라이스를 다시 합쳐 파일 하나로 만든 후 호스트에 저장한다. 파일 슬라이스가 여러 서버에 이중으로 저장되므로 일부 서버 장애가 데이터 유실로 이어지지 않는다. HDFS는 랜덤 읽기나 쓰기를 지원하지 않는 대신 이어 쓰기를 지원하게 설계되었다. 또한 테스트 목적으로 랩톱이나 데스크톱 컴퓨터의 하드 드라이브에도 HDFS를 설치할 수 있다. 하지만 이 경우 파일 분할이나 이중화가 적용되지 않든다.  4.3 파일을 HDFS로 직접 정상하기HDFS와 데이터를 주고받는 가장 쉬운 방법은 기본 HDFS 명령을 사용하는 것이다. HDFS 명령은 HDFS 파일 시스템을 연동한 일종의 래퍼이며, 로컬 명령(cp. ls. mv등)은 오직 로컬 파일 시스템에서만 사용할 수 있다. 다음과 같이 HDFS의 put 명령으로 로컬 파일 시스템에 저장된 test 파일을 HDFS로 복사할 수 있다. - $ hdfs dfs -put test 다음과 같이 HDFS에 저장된 파일 목록을 조회할 수 있다. HDFS 파일 목록은 로컬 파일 시스템에서 ls -l 명령이 출력하는 결과와 유사하다. - $ hdfs dfs -ls -rw-r--r--  2 username hdfs    497  2016-05-11 14:32 test HDFS에서 로컬 파일 시스템 파일(another-test)을 복사할 때는 다음과 같이 get 명령을 사용한다.- $ hdfs dfs -get another-test다른 HDFS 명령도 예제에서 살펴볼 것이다. 부록 A.1 HDFS 퀙스타트에서 기본 HDFS 명령 예제(파일 조회, 복사 삭제 등)를 볼 수 있다.  4.4 파일을 하이브 테이블로 가져오기아파치 하이브 SQL과 유사한 스크립트를 사용해 HDFS의 데이터를 분석하는 도구다. 데이터과학 프로젝트에서 프프렛드시트나 데이터베이스에서 추출한 텍스트 파일을 하이브로 가져 와야 하는 경우가 종종 있다. 텍스트 파일은 TSV, CSV, JSON형식, 또는 단순한 비표준 텍스트 파일일 수도 있다. 일단 데이터를 하이브 테이블로 가져오면, 나중에 진행할 모델링 단계에서 이를 편리하게 사용할 수 있다. 5장 하둡을 활용한 데이터 개조에서 더 자세히 다룰 특징 변수 생성을 대표적인 모델링 단계로 볼 수 있다.일단 하이브 테이블로 데이터를 가져오면 하이브의 SQL 쿼리나 피그, 스파크 같은 다양한 도구를 사용해 데이터를 처리할 수 있다.  하이브는 두 종류의 테이블을 지원한다. 첫 번째는 내부 테이블이며, 하이브가 완전히 관리하는 테이블이다. 내부 테이블을 삭제하면 하이브의 테이블 메타 정의와 테이블에 들어 있는 모든 데이터도 같이 삭제되다. 내부 테이블은 ORC 같은 최적화된 형식으로 저장될 수 있어 비교적 빠른 성능을 보인다. 두 번째는 외부 테이블이며, 하이브가 직접 관리하지 않는다. 외부 테이블은 오직 하이브의 메타 정의만 사용해 원시 형태로 저장된 텍스트 데이터에 접근한다. 내부 테이블과는 달리, 외부 테이블의 데이터를 삭제하면 하이브의 테이블 메타 정의만 섹제되고 실제 데이터는 그대로 유지된다. 외부 테이블은 해당 데이터가 하이브 외부에 적재(예를 들어 다른 애플리케이션도 파일을 사용, 생성, 관리하는 경우)돼 있거나, 테이블이 삭제되더라도 원본 데이터가 본래 위치에 남아야 할 때 주로 사용한다.하이브를 활용하는 사례가 많은 관계로 여기서는 하이브가 지원하는 모든 입수 방법을 다루기 보다는 CSV 파일을 하이브로 가져오는 기본적인 예제를 소개한다. 더 많은 내용은 하이브 프로젝트 페이지(https://hive.apache.org)를 참조하기 바란다.  4.4.1 CSV 파일을 하이브 테이블로 가져오기다음 예제는 쉼표로 구분된 텍스트(CSV) 파일을 하이브 테이블로 가져오는 방법을 설명한다. 여기서 사용된 입력 파일(names.csv)은 필드 5개(직원 ID, 이름, 직급, 주, 랩톱 유형)로 구성돼 있다.파일의 처음 다섯 줄은 다음과 같다.- names.csv 10,Andrew,Manager,DE,PC 11,Arun,Manager,NJ,PC 12,Harish,Sales,NJ,MAC 13,Robert,Manager,PA,MAC 14,Laura,Engineer,PA,MAC 데이터 입수의 첫 번째 단계는 HDFS에 파일을 보관할 디렉터리를 생성하는 것이다. 대부분의 하둡 도구와 마찬가지로, 하이브도 디렉터리를 기반으로 데이터를 읽어 들인다. 즉, 주어진 디렉터리에 있는 모든 파일이 하이브 쿼리의 입력 데이터로 사용된다. 다음 명령으로 사용자(여기서는 username)의 HDFS 디렉터리 안에 names 디렉터리를 만들자. - $ hdfs dfs -mkdir names이 예제에서는 파일을 한 개만 사용하지만, 여러 파일을 입력 디렉터리에 넣을 수도 있다. names 디렉터리를 만들었다면, 다음과 같이 names.csv 파일을 복사해 넣자.- $ fdfs dfs -put names.csv names파일을 HDFS에 복사한 이후에 외부 하이브 테이블로 데이터를 불러올 수 있다. 명령 프롬프트에서 hive를 입력해 하이브 셸을 실행한 후 다음 명령을 입력하자. 예에서는 명령을 실행할 때 출력되는 내용 중 불필요한 실행 시간이나 진행 상황은 제외했다. - hive > CREATE EXTERNAL TABLE IF NOT EXISTS Names_text(  *>* EmployeeID INT, FirstName STRING, Title STRING,  *>* State STRING, Laptop STRING)  *>* COMENT'Employee Names'  *>* ROW FORMAT DELIMITED  *>* FIELDS TERMINATED BY','  *>* STORED AS TEXTFILE  *>* LOCATION '/user/username/names';  OK 명령이 성공적으로 수행되면 하이브 OK 메시지를 출력한다. 이 명령은 여러 필드를 선언하면서 필드 사이의 구분다(delimiter)는 쉼표(',')를 사용했다. 마지막의 LOCATION문은 테이블이 사용할 입력 파일의 경로를 지정한다. 다음 쿼리를 사용해 데이터가 잘 입수되었는지 확인해보자.- hive> Select * from Names_text limit 5;  OK 10 <NAME> DE PC 11 Arun Manager NJ PC 12 Harish Sales NJ MAC 13 Robert Manager PA MAC 14 Laura Engineer PA MAC Note :  데이터 입수에 INSERT가 없다?관계형 데이터베이스에 익숙한 독자는 INSERT 명령을 실행하지 않았는데도 데이터 입수가 끝나버린 이 상황이 다소 생소할 수 있다. 하이브는 모든 데이터를 파일로 저장하며, 하이브 테이블은 파일의 데이터를 읽는 일종의 틀에 불과하다. 그러므로 HDFS에 파일을 저장한 후에 이 파일을 읽는 외부 테이블만 정의해도 SELECT 문으로 데이터를 조회할 수 있다. *****다음 단계로 외부 테이블의 데이터를 내부 테이블로 옮겨 보자. 앞에서 본 외부 테이블과 유사한 방식으로 내부 테이블을 생성할 수 있다. 한 가지 차이는 STORED AS에 내부 테이블의 파일 형식을 지정할 수 있다는 점이다. 하이브 테이블은 기본 텍스트 파일 외에도 4가지 파일 형식을 지원한다. 데이터와 분석 유형에 따라 서로 다른 형식을 선택할 수 있지만, 압축률이 가장 좋고 속도가 빠른 ORC나 Parquet 형식을 주로 사용한다.- 텍스트 파일: 모든 데이터가 유니코드 표준을 사용한 원시 텍스트로 저장된다.- 시퀀스 파일: 데이터가 이진 키-값 쌍으로 저장된다.- RC 파일: 모든 데이터가 로우기반 최적화 대신 칼럼 기반 최적화 형식으로 저장된다- ORC 형식: Optimized Row Columnar의 약자로, 하이브 성능을 크게 높일 수 있다.- Parquet 형식: 하이브, 드릴, 임팔라, 크런치, 피그 등의 다양한 하둡 도구와 호환되는 칼럼 기반 형식이다.다음 명령으로 ORC 형식을 사용하는 내부 하이브 테이블을 생성하자.- hive > CREATE TABLE IF NOT EXISTS Names(  *>* EmployeeID INT, FistName STRING, Title STRING,  *>* State STING, Laptop STRING)  *>* COMMENT 'Employee Names'  *>* ROW FORMAT DELIMITED  *>* FIELDS TERMINATED BY ','  *>* STORED AS ORC;  OK ORC 외의 형식으로 테이블을 생성하고 싶다면 STORED AS에 새 형식을 넣어 명령을 수정하자. 테이블이 생성되면 다음 쿼리로 외부 데이터를 내부 테이블로 복사할 수 있다.- hive > INSERT OVERWRITE TABLE Names SELECT * FROM Names_text외부 테이블과 마찬가지로, 아래 쿼리를 사용해 복사된 결과를 확인할 수 있다.- have> Select * from Names limit 5; OK 10,Andrew,Manager,DE,PC 11,Arun,Manager,NJ,PC 12,Harish,Sales,NJ,MAC 13,Robert,Manager,PA,MAC 14,Laura,Engineer,PA,MAC 하이브는 파티션 기능도 지원한다. 파티션을 사용하면 테이블을 논리적으로 나눌 수 있기 때문에 쿼리를 일부 데이터에만 효율적으로 실행할 수 있다. 예를 들어 앞에서 생성한 하이브 내부 데테이블 대신 주 필드에 파티션이 적용된 내부 테이블을 만들 수 있다. 다음 명령으로 파티션 테이블을 생성해 보자.- have> CREATE TABLE IF NOT EXISTS Names_part(  *>* EmployeeID INT,  *>* FirstName STRING,  *>* Title STRING, *>* Laptop STRING)  *>* COMMENT 'Employee names partitioned by state'  *>* PARTITIONED BY (State STRING)  *>* STORED AS ORC;  OK 다음 쿼리를 실행해 펜실베니아주 출신 직원들의 데이터를 외부 테이블에서 내부 테이블로 복사 할 수 있다.- hive> INSERT INTO TABLE Names_part PARTITION(state='PA')  *>* SELECT EmployeeID, FirstName, Title, Laptop FROM Names_text WHERE state='PA';  .....  OK 이와 같은 INSERT 방법을 사용하려면 각 파티션 키를 개별적으로 선택해 테이블에 저장해야 한다. 하지만 저장할 파티션 개수가 많으면 이 방법은 매우 불편할 수 있다. 하이브는 이런 불편함을 해소하는 동적 파티션 삽입 기능을 제공한다. 이 기능은 입력 테이블을 스캔하면서 어떤 파티션을 생성하고 어떤 파티션에 데이터를 넣어야 할지 동적으로 판단한다. Note : 하이브의 테이블 파티션앞서 설명했듯이 HDFS는 랜덤 읽기를 지원하지 않는다. 즉, 모든 파일을 처음부터 읽어야 한다. 하이브의 파티션을 사용하면 테이블의 파일을 하위 폴더로 나눠 저장할 수 있으므로 쿼리 성능을 크게 개선할 수 있다. 또한 파일을 읽어들일 매퍼를 훨씬 적게 사용하므로 일부 사용자가 하둡 클러스터를 과도하게 점유하는 현상을 줄일 수 있다. 따라서 데이터를 대량으로 다룰 때는(특히 장기간의 데이터를 날짜별로 처리할 때는) 파티션을 사용하는 방안을 권장한다. 동적 파티션은 매우 편리하지만 데이터가 너무 많으면 간혹 INSERT 쿼리가 실패하기도 한다. 또한 strict 모드에서는 동적 파티션 기능이 제한된다. 이때는 다음과 같이 동적 파티션 모드를 nonstrict로 변경해야 한다.- set hive.exec.dynamic.partition.mode=nonstrict;  4.5 스파크를 사용해 데이터를 하이브 테이블로 가져오기아파치 스파크는 인-메모리 처리에 초점을 맞춘 최신 처리 엔진이다. 스파크의 주요 데이터 추상화 객체는 불변 분산 아이템 컬렉션 RDD이다. RDD는 하둡 입력 형식(HDFS 파일 등)으로 생성하거나 다른 RDD를 변형해 얻을 수 있다. RDD의 각 데이터셋은 논리적인 파티션으로 나뉘며, RDD의 연산은 클러스터의 여러 노드에서 투명하게 처리된다. Note : 스파크 RDD의 불변성스파크 RDD의 불변성은 한 번 생성된 RDD가 더는 변경되지 않음을 의미한다. 다시 말해, RDD 객체에 어떤 연산을 적용해도 RDD의 데이터가 변경되지 않으며, 대신 새 RDD가 연산의 결과로 만들어진다. RDD가 불변성으로 설계된 이유는 RDD를 언제든지 복원하게 만들기 위함이며 부수적으로 RDD의 이중화와 공유, 캐싱 등이 쉽다는 장점이 있다.********스파크의 또 다른 주요 데이터 추상화 객체는 DataFrame이다. DataFrame은 RDD를 기반으로 개발됐지만 RDD와 달리 관계형 데이터베이서, R의 데이터 프레임이나 파이썬의 Pandas패키지처럼 이름이 지정된 칼럼으로 데이터가 구성된다.다음과 같은 다양한 데이터 소스로부터 스파크 DataFrame을 생성할 수 있다.- 이미 생성한 RDD- 정형 데이터 파일- JSON 데이터셋- 하이브 테이블- 외부 데이터베이스스파크는 유연성이 높고 개발자 친화적인 API를 제공해 하둡으로 데이터 입수 작업에 자주 사용된다. 스파크를 활요해 CSV 파일이나 외부 SQL/NoSQL 데이터베이스의 다양한 소스에서 데이터를 읽어 들이고, 데이터 변환을 거쳐 HDFS나 하이브로 저장할 수 있다. 하이브 예제와 마찬가지로 책에서 스파크의 데이터 입수 기능을 모두 설명하지는 않는다. 더 자세한 내용은 아파치 스파크 프로젝트 홈페이지(http://spark.apache.org)를 참조하자.이 절에서는 PySpark(스파크의 파이썬 API)를 사용해 기본적인 데이터 입수 예제를 다룬다. 물록 스파크의 스칼라나 자바 API의 자세한 내용을 세세히 설명하지는 않는다.예제를 실행하려면 PySpark 셸(버전 1.6)이 필요하다. 명령 프롬프트에서 다음 명령을 입력해 PySpark를 실행하자.<jupyter_code>import pyspark
pyspark<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.05650054710036805, 'fraction_numerical': 0.00676415000497364, 'mean_word_length': 3.2225955480890383, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 34, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '622470', 'license': 'MIT', 'n_tokens_mistral': 9120, 'n_tokens_neox': 12501, 'n_words': 2068, 'path': 'chapter_4.ipynb', 'repo_name': 'choiuikang/hadoop_and_spark', 'size': '10060'}