클라우드 컴퓨팅 & NoSQL/google cloud

파이어베이스 애널러틱스를 이용한 모바일 데이타 분석- #3 빅쿼리에 연동하여 모든 데이타를 분석하기

Terry Cho 2016. 9. 1. 17:17

파이어베이스 애널러틱스를 이용한 모바일 데이타 분석

#3 빅쿼리에 연동하여 모든 데이타를 분석하기


조대협 (http://bcho.tistory.com)


파이어베이스 애널러틱스의 대단한 기능중의 하나가, 모바일에서 올라온 모든 원본 로그를 빅쿼리에 저장하고, 이를 빅쿼리를 통해서 분석할 수 있는 기능이다. 대부분의 매니지드 서비스 형태의 모바일 애널리틱스 서비스는 서비스에서 제공하는 지표만, 서비스에서 제공하는 화면을 통해서만 볼 수 있기 때문에, 상세한 데이타 분석이 불가능하다. 파이어베이스의 경우에는 빅쿼리에 모든 원본 데이타를 저장함으로써 상세 분석을 가능하게 해준다.


아울러, 모바일 서비스 분석에 있어서, 상세 로그 분석을 위해서 로그 수집 및 분석 시스템을 별도로 만드는 경우가 많은데, 이 경우 모바일에 설치될 로그 수집 에이전트에서 부터 로그를 수집하는 API 서버, 이를 저장하기 위한 분산 큐(카프카 Kafka)와 같은 복잡한 백앤드 시스템을 설계 구현해야 하는데, 파이어베이스 애널러틱스의 로깅 기능을 이용하면 별도의 이런 인프라 구현이 없이도 손쉽게 로그를 수집 및 분석할 수 있다. (일종의 무임 승차라고나 할까?)


가격 정책

그렇다면 가장 고민이 되는 것이 가격 정책일 것이다. 파이어베이스 애널러틱스에서 빅쿼리에 데이타를 저장하려면 파이어베이스 플랜중 무료가 아닌 유료 플랜인 Blaze 플랜을 사용해야 한다.

그러나, 다행이도 Blaze 플랜은 “Pay as you go” 모델로 사용한 만큼 비용을 지불하는 모델인데, “Google Cloud Integration”은 별도의 비용이 부과 되지 않는다.



단지 빅쿼리에 대한 비용만 부담이 되는데, 빅쿼리의 경우 데이타 로딩은 무료이고, 저장 요금 역시 GB당 월 0.02$ (약 22원)이며, 90일동안 해당 데이타를 사용하지 않으면 이 요금은 50%로 자동 할인되서 GB당 월 0.01$(약 11원)만 과금된다. 이외에 쿼리당 비용이 과금되는데, 쿼리당 비용은 쿼리에서 스캔한 데이타 용량 만큼만 과금이 된다. TB를 쿼리 했을때 5$가 과금이되는데, 이역시 전체 테이블을 스캔을 하는것이 아니라, 쿼리에서 스캔하는 컬럼에 대해서만 과금이 되고, 전체 테이블이 아니라, 쿼리에서 스캔하는 날짜만 과금이 되기 때문에, 실제 과금 금액은 미미하다고 볼 수 있다. 실제로 실 서비스에서 모 앱의 하루 데이타를 수집한 경우 17만건의 이벤트가 수집되었는데 저장 용량은 전체 350 MB에 불과하다. 전체 컬럼을 스캔한다고 하더라도 (전체 컬럼을 스캔할 일은 없겠지만….) 쿼리 비용은 0.00175$에 불과하다.


파이어베이스 애널러틱스와 빅쿼리를 연동하여 데이타 수집하기

파이어베이스 애널러틱스에서 데이타를 빅쿼리로 수집하기 위해서는 앞에서 언급한바와 같이 먼저 파이어베이스 플랜을 Blaze로 업그레이드 해야 한다. 파이어베이스 콘솔 좌측 하단을 보면 아래와 같이 UPGRADE 버튼이 있다. 이 버튼을 눌러서 Blaze 플랜으로 업그레이드를 하자


다음으로 파이어베이스 애널러틱스 프로젝트를 빅쿼리와 연결을 해줘야 한다.

파이어베이스 콘솔 좌측 상단에서 설정 버튼을 누른 후에, Project settings 메뉴를 선택한다.


프로젝트 세팅 메뉴에 들어가서 상단 메뉴중에 ACCOUNT LINKING이라는 메뉴를 선택한다.


그러면 구글 플레이나 광고 플랫폼등과 연결할 수 있는 메뉴와 함께 아래 그림처럼 빅쿼리로 연결할 수 있는 메뉴와 “LINK TO BIGQUERY”라는 버튼이 화면에 출력된다.


이 버튼을 누르면 작업은 끝났다. 이제부터 파이어베이스의 모든 로그는 빅쿼리에 자동으로 수집되게 된다.

만약에 수집을 중단하고 싶다면 위의 같은 화면에서 LINK TO BIGQUERY라는 버튼이 MANAGE LINKING으로 바뀌어 있는데, 이 버튼을 누르면 아래와 같이 App Details가 나온다.



여기서 스위치 버튼으로 Send data to BigQuery를 끔 상태로 변경해주면 된다.

이제 부터 대략 한시간 내에, 데이타가 빅쿼리에 수집되기 시작할 것이다.  

수집 주기

그러면 파이어베이스 애널러틱스에서는 어떤 주기로 데이타를 수집하고 수집된 데이타는 언제 조회가 가능할까? 이를 이해하기 위해서는 앱 로그 수집에 관여되는 컴포넌트와 흐름을 먼저 이해할 필요가 있다.

로그 수집이 가능한 앱은 크게, 구글 플레이 스토어에서 배포되는 앱, 구글 플레이 스토어를 통하지 않고 배포되는 앱 그리고 iOS 앱 3가지로 나눌 수 있다.

이 앱들이 파이어베이스 서버로 로그를 보내는 방식은 앱마다 약간씩 차이가 있다.


  • 플레이스토어에서 다운 받은 앱 : 각 개별 앱이 이벤트 로그를 수집하여 저장하고 있다가 1시간 주기로, 모든 앱들의 로그를 모아서 파이어베이스 서버로 전송한다.

  • 플레이스토어에서 다운받지 않은 앱 : 플레이스토어에서 다운로드 받은 앱과 달리 다른 앱들과 로그를 모아서 함께 보내지 않고 한시간 단위로 로그를 모아서 개별로 파이어베이스에 전송한다.

  • iOS 앱 : 앱별로 한시간 단위로 로그를 모아서 파이어베이스 서버로 전송한다.


이렇게 앱에서 파이어베이스 서버로 전송된 데이타는 거의 실시간으로 구글 빅쿼리에 저장된다.

그러나 파이어베이스 애널러틱스의 대쉬 보다는 대략 최대 24시간 이후에 업데이트 된다. (24시간 단위로 분석 통계 작업을 하기 때문이다.)


이 전체 흐름을 도식화 해보면 다음과 같다.



수집된 데이타 구조

그러면 빅쿼리에 수집된 테이블은 어떤 구조를 가질까?

테이블 구조를 이해하기 전에 테이블 종류를 먼저 이해할 필요가 있다.

앱에서 수집한 로그는 안드로이드와 iOS 각각 다른 데이타셋에 저장되며, 테이블 명은

  • app_events_YYYYMMDD

가 된다. 2016년 8월30일에 수집한 로그는  app_events_20160830 이 된다.



Intraday 테이블

여기에 intraday 테이블이라는 개념이 존재하는데, 이 테이블은 app_events_intraday_YYYYMMDD 라는 이름으로 저장이 되는데, 이 테이블은 실시간 데이타 수집을 목적으로 하는 테이블로 오늘 데이타가 저장된다. 예를 들어 오늘이 2016년9월1일이라면, app_events테이블은 app_events_20160831 까지만 존재하고, 9월1일자 데이타는 app_events_intraday_20160901 이라는 테이블에 저장된다.

9월1일이 지나면 이 테이블은 다시 app_events_20160901 이라는 이름으로 변환된다.

intraday 테이블의 특성중의 하나는 몇몇 필드들은 값이 채워지지 않고 NULL로 반환된다. 모든 데이타를 수집하고 배치 연산을 통해서 계산이 끝나야 하는 필드들이 그러한데, LTV 값과 같은 필드가 여기에 해당한다.


여기서 주의할점 중의 하나가 intraday 테이블이 하나만 존재할것이라는 가정인데. 결론 부터 이야기 하면 최대 2개가 존재할 수 있다. 9월1일 시점에  app_events_intraday_20160901 테이블이 존재하다가 9월2일이 되면 app_events_intraday_20160902 테이블이 생성된다. app_events_intraday_20160901 를 app_events_20160901 테이블로 변환을 해야 하는데, 단순히 복사를 하는 것이 아니라, 배치 연산등을 수행하기 때문에 연산에 다소 시간이 걸린다. 그래서 연산을 수행하는 동안에는 app_events_intraday_20160901 테이블과 app_events_intraday_20160902이 동시에 존재하고, 9월1일 데이타에 대한 연산이 종료되면 app_events_intraday_20160901 은 app_events_20160901 로 변환 된다.  

테이블 스키마

빅쿼리에 저장된 데이타의 테이블 구조를 이해하기 위해서 빅쿼리의 데이타 저장 특성을 이해할 필요가 있는데, 빅쿼리는 테이블 데이타 구조를 가지면서도 JSON과 같이 컬럼안에 여러 컬럼이 들어가는 RECORD 타입이나, 하나의 컬럼안에 여러개의 데이타를 넣을 수 있는  REPEATED 필드라는 데이타 형을 지원한다.



<그림. 레코드 타입의 예>

레코드 타입은 위의 그림과 같이 Name이라는 하나의 컬럼 내에 Last_name과 First_name이라는 두개의 서브 컬럼을 가질 수 있는 구조이다.

아래는 REPEATED 필드(반복형 필드)의 데이타 예인데, Basket이라는 컬럼에 Books,Galaxy S7, Beer 라는 3개의 로우가 들어가 있다.


<그림. 반복형 필드 예>

이런 구조로 인하여, 빅쿼리는 JSON과 같이 트리 구조로 구조화된 데이타를 저장할 수 있고, 실제로 파이어베이스 애널러틱스에 의해 수집되어 저장되는 데이타도 JSON과 같은 데이타 구조형으로 저장이 된다.

많은 데이타 필드가 있지만, 큰 분류만 살펴보면 다음과 같은 구조를 갖는다.



하나의 레코드는 하나의 앱에서 올라온 로그를 나타낸다. 앱은 앞의 수집 주기에 따라서 한시간에 한번 로그를 올리기 때문에, 하나의 레코드(행/로우)는 매시간 그 앱에서 올라온 로그라고 보면 된다.


가장 상위 요소로 user_dim과, event_dim이라는 요소를 가지고 있다.

user_dim은 사용자나 디바이스에 대한 정보를 주로 저장하고 있고, event_dim은 앱에서 발생한 이벤트들을 리스트 형태로 저장하고 있다.

user_dim에서 주목할만한 것은 userid에 관련된 것인데, userid는 사용자 id 이지만, 파이어베이스가 자동으로 수집해주지는 않는다. 개발자가 앱의 파이어베이스 에이전트 코드에서 다음과 같이 setUserId 메서드를 이용해서 설정해줘야 빅쿼리에서 조회가 가능하다. (앱 서비스의 계정을 세팅해주면 된다.)

mFirebaseAnalytics.setUserId(Long.toString(user.id));

다음 주목할 필드는 user_dim에서 app_info.app_instance_id 라는 필드인데, 이 필드는 각 앱의 고유 ID를 나타낸다. 파이어베이스가 자동으로 부여하는 id로 설치된 앱의 id이다.

예를 들어 내가 갤럭시S7과 노트7를 가지고 같은 앱을 설치했다고 하더라도 각각 다른 디바이스에 설치되었기 때문에 각각의 앱 id는 다르다.


다음은 event_dim인데, event_dim은 이벤트들로 레코드들의 배열(리스트)로 구성이 되고 각각의 이벤트는 이벤트 이름과 그 이벤트에 값을 나타내는 name 과 params라는 필드로 구성이 되어 있다.  params는 레코드 타입으로 여러개의 인자를 가질 수 있고, params내의 인자는 또 각각 key와 value식으로 하여 인자의 이름과 값을 저장한다. values는 string_value,int_value,double_value 3가지 서브 필드를 가지고 있는데, 인자의 타입에 따라서 알맞은 필드에만 값이 채워진다. 예를 들어 인자의 타입이 문자열 “Cho” 이고, 인자의 이름이 “lastname”이면, params.key “lastname”이 되고, params.value.string_value=”Cho”가 되고 나머지 필드인 params.value.int_value와 params.value.float.value는 null이 된다.


   "event_dim": [

     {

       "name": "Screen",

       "params": [

         {

           "key": "firebase_event_origin",

           "value": {

             "string_value": "app",

             "int_value": null,

             "float_value": null,

             "double_value": null

           }

         },

         {

           "key": "Category",

           "value": {

             "string_value": "Main",

             "int_value": null,

             "float_value": null,

             "double_value": null

           }

         },

      ]

    },

     {

       "name": "Purchase",

       "params": [

         {

           "key": "amount",

           "value": {

             "string_value": null,

             "int_value": “5000”,

             "float_value": null,

             "double_value": null

           }

         }

         },

      ]

    },


위의 예제는 빅쿼리에 저장된 하나의 행을 쿼리하여 JSON형태로 리턴 받은 후, 그 중에서 event_dim 필드 내용 일부를 발췌한 것이다.

Screen과 Purchase라는 두개의 이벤트를 받았고,

Screen은 firebase_event_origin=”app”, Category=”main” 이라는 두개의 인자를 받았다.

Purchase는 amount=5000 이라는 정수형 인자 하나를 받았다.


전체 빅쿼리의 스키마는 다음과 같이 되어 있다.




파이어베이스 애널러틱스에서 빅쿼리로 저장된 테이블 스키마에 대한 상세는 https://support.google.com/firebase/answer/7029846?hl=en 를 참고하기 바란다.


구글 빅쿼리에 대한 자료 아래 링크를 참고하기 바란다.


  1. 2016.08.01 빅쿼리를 이용하여 두시간만에 트위터 실시간 데이타를 분석하는 대쉬보드 만들기

  2. 2016.07.31 빅데이타 수집을 위한 데이타 수집 솔루션 Embulk 소개

  3. 2016.06.18 빅쿼리-#3 데이타 구조와 접근(공유) (3)

  4. 2016.06.16 구글 빅데이타 플랫폼 빅쿼리 아키텍쳐 소개

  5. 2016.06.15 구글 빅데이타 플랫폼 빅쿼리(BIGQUERY)에 소개

  6. 빅쿼리로 데이타 로딩 하기 http://whitechoi.tistory.com/25


다음은 데이타랩을 통하여 데이타를 직접 분석해보도록 하겠다.


그리드형