Firebase로 캐시

Looker Studio에는 보고서를 위한 자체 캐시 시스템이 있습니다. 커넥터를 만들 때 맞춤 캐시를 구현하여 더 빠른 보고서를 용이하게 하고 APR 비율 제한을 피할 수 있습니다.

예를 들어 특정 우편번호에 대해 지난 7일 동안의 과거 날씨 데이터를 제공하는 커넥터를 만듭니다. 커넥터가 매우 인기를 얻고 있지만 데이터를 가져오는 외부 API에는 엄격한 비율 제한이 있습니다. API는 데이터를 매일 업데이트하므로 특정 우편번호의 경우 하루에 같은 데이터를 여러 번 가져올 필요가 없습니다. 이 솔루션 가이드를 사용하면 각 우편 번호의 일일 캐시를 구현할 수 있습니다.

요구사항

  • Firebase 실시간 데이터베이스 액세스 권한이 없는 경우 Google Cloud Platform (GCP) 프로젝트를 만들고 시작하기 가이드에 따라 Firebase 실시간 데이터베이스 인스턴스를 직접 만듭니다.
  • Firebase 실시간 데이터베이스에서 데이터를 읽고 쓰는 GCP 서비스 계정
  • 소스에서 데이터를 가져오는 커뮤니티 커넥터입니다.

제한사항

  • 이 솔루션은 Looker Studio 고급 서비스와 함께 사용할 수 없습니다. Looker Studio 고급 서비스를 사용하면 Apps Script의 커넥터 코드가 데이터에 액세스할 수 없습니다. 따라서 Apps Script를 사용하여 데이터를 캐시할 수 없습니다.
  • 보고서 수정 권한 사용자 및 보기 권한 사용자는 이 특정 캐시를 재설정할 수 없습니다.

해결 방법

서비스 계정 구현

  1. Google Cloud 프로젝트에서 서비스 계정을 만듭니다.
  2. 이 서비스 계정에 클라우드 프로젝트에서 BigQuery 액세스 권한이 있는지 확인하세요.
    • 필요한 Identity and Access Management (IAM) 역할: Firebase Admin
  3. JSON 파일을 다운로드하여 서비스 계정 키를 가져옵니다. 파일의 콘텐츠를 커넥터 프로젝트의 스크립트 속성에 저장하세요. 키를 추가한 후 Apps Script UI에 다음과 같이 표시됩니다.
    스크립트 속성에 서비스 계정 키 저장
  4. Apps Script 프로젝트에 Apps Script용 OAuth2 라이브러리를 포함합니다.
  5. 서비스 계정에 필요한 OAuth2 코드를 구현합니다.
firestore-cache/src/firebase.js
var SERVICE_ACCOUNT_CREDS = 'SERVICE_ACCOUNT_CREDS';
var SERVICE_ACCOUNT_KEY = 'private_key';
var SERVICE_ACCOUNT_EMAIL = 'client_email';
var BILLING_PROJECT_ID = 'project_id';

var scriptProperties = PropertiesService.getScriptProperties();

/**
 * Copy the entire credentials JSON file from creating a service account in GCP.
 * Service account should have `Firebase Admin` IAM role.
 */
function getServiceAccountCreds() {
  return JSON.parse(scriptProperties.getProperty(SERVICE_ACCOUNT_CREDS));
}

function getOauthService() {
  var serviceAccountCreds = getServiceAccountCreds();
  var serviceAccountKey = serviceAccountCreds[SERVICE_ACCOUNT_KEY];
  var serviceAccountEmail = serviceAccountCreds[SERVICE_ACCOUNT_EMAIL];

  return OAuth2.createService('FirebaseCache')
    .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(serviceAccountKey)
    .setIssuer(serviceAccountEmail)
    .setPropertyStore(scriptProperties)
    .setCache(CacheService.getScriptCache())
    .setScope([
      'https://www.googleapis.com/auth/userinfo.email',
      'https://www.googleapis.com/auth/firebase.database'
    ]);
}

Firebase에서 읽고 쓰는 코드 구현

Firebase Database REST API를 사용해 Firebase 실시간 데이터베이스를 읽고 씁니다. 다음 코드는 이 API에 액세스하는 데 필요한 메서드를 구현합니다.

getData() 구현

캐싱이 없는 기존 getData() 코드의 구조는 다음과 같습니다.

Firestore-cache/src/without-caching.js
/*
 * This file is only to demonstrate how the `getData()` fucntion would look
 * like without the Firebase Realtime Database caching. It is not a part of
 * the connector code and should not be included in Apps Script / Clasp.
 */

function getData(request) {
  var requestedFields = getFields().forIds(
    request.fields.map(function(field) {
      return field.name;
    })
  );

  var fetchedData = fetchAndParseData(request);
  var data = getFormattedData(fetchedData, requestedFields);

  return {
    schema: requestedFields.build(),
    rows: data
  };
}

getData() 코드에서 캐싱을 사용하려면 다음 단계를 따르세요.

  1. 캐시해야 하는 데이터의 '청크' 또는 '단위'를 결정합니다.
  2. 캐시에 데이터의 최소 단위를 저장할 고유 키를 만듭니다.
    구현 예에서는 configparamszipcode가 키로 사용됩니다.
    선택사항: 사용자별 캐시의 경우 기본 키와 사용자 ID를 사용하여 복합 키를 만듭니다. 구현 예:
    js var baseKey = getBaseKey(request); var userEmail = Session.getEffectiveUser().getEmail(); var hasheduserEmail = getHashedValue(userEmail); var compositeKey = baseKey + hasheduserEmail;

  3. 캐시된 데이터가 있는 경우 캐시가 최신인지 확인합니다.
    이 예에서는 특정 우편번호에 대해 캐시된 데이터가 현재 날짜와 함께 저장됩니다. 캐시에서 데이터를 가져오면 캐시 날짜가 현재 날짜와 비교하여 확인됩니다.

    var cacheForZipcode = {
      data: <data being cached>,
      ymd: <current date in YYYYMMDD format>
    }
    
  4. 캐시된 데이터가 존재하지 않거나 캐시된 데이터가 최신이 아닌 경우 소스에서 데이터를 가져와 캐시에 저장합니다.

다음 예에서 main.js는 캐싱이 구현된 getData() 코드를 포함합니다.

예시 코드

추가 리소스

Chrome UX 커넥터는 수천 명의 사용자에게 약 20GB의 BigQuery 테이블을 기반으로 대시보드를 제공합니다. 이 커넥터는 Firebase 실시간 데이터베이스와 Apps Script 캐시 서비스를 함께 사용하여 2가지 계층화된 캐싱 방식을 사용합니다. 구현 세부정보는 코드를 참고하세요.