ユーザー提供データ マッチング

ユーザー提供データ マッチング(UPDM)では、収集したユーザーに関する自社データ(ウェブサイト、アプリ、実店舗からの情報など)と、Google が所有および運営するデータを含むすべての Google 広告データにおけるそのユーザーのログイン中のアクティビティ データが結合されます。これには、Google マーケティング プラットフォーム(GMP)サービスを通じて購入したデータ(ディスプレイ&ビデオ 360 を使用して購入した YouTube など)が含まれます。Google が所有、運営していないその他の GMP プロダクトはサポートされていません。

UPDM で使用する広告イベントは、Google の広告データ上でログイン済みのユーザーと関連付けられている必要があります。

このドキュメントでは、ユーザー提供データの照合機能について説明し、設定と使用に関するガイダンスを提供します。

[]

[接続] タブの概要

有益な広告インサイトを得るには、多くの場合、複数のソースからデータを統合する必要があります。このデータ パイプラインの問題を解決するために独自のソリューションを構築するには、時間とエンジニアリングに多大な投資が必要になります。Ads Data Hub の [接続] ページでは、BigQuery で広告データをインポート、変換、照合するための手順ガイド付きのインターフェースが提供されるため、このプロセスを効率化できます。インポートしたデータは、Ads Data Hub のクエリや、BigQuery から読み取った他のサービスで使用できます。自社データを使ってクエリを拡充すると、カスタマー エクスペリエンスが豊かになり、広告業界におけるトラッキング手法の変化にも対応しやすくなります。

[接続] ページには、プライバシー重視の方法で個人情報(PII)を暗号化してパートナーと共有できるツールが用意されています。PII を含む列を選択すると、Ads Data Hub はデータを暗号化し、自社データのエクスポートや読み取りを許可されたユーザーのみが行えるようにします。測定やアクティベーションのユースケースに必要な自社データの特定は難しい場合がありますが、Ads Data Hub には事前定義されたユースケースの包括的なリストが用意されており、データの抽出、変換、読み込みの全体的な手順をガイドします。複数のタイプの接続を作成できますが、このドキュメントでは、ユーザー提供データのマッチングに [接続] ページを使用していることを前提としています。

サポートされているファーストパーティ データソース

次のデータソースからデータをインポートできます。

  • BigQuery
  • Cloud Storage
  • セキュア FTP(sFTP)
  • Snowflake
  • MySQL
  • PostgreSQL
  • Amazon Redshift
  • Amazon S3

ユーザー提供データ マッチングは、Google が所有および運営する広告枠でのみログイン中のユーザーが利用可能なため、今後のサードパーティ Cookie のサポート終了による影響を受けません。第三者データよりも業界の変化に強いため、より豊富な分析情報を提供でき、顧客エンゲージメントの向上につながります。

用語を学ぶ

  • ユーザー提供データ接続: ユーザー提供データ接続を設定すると、データのインポートと照合、データのインポートのスケジュール設定、データの変換、ユーザー ID を使用した広告データの照合を行うことができます。広告イベントは、Google の広告データでログイン済みのユーザーに関連付けられている必要があります。複数の Google Cloud プロジェクトが必要です。
  • ファーストパーティ データ接続: ファーストパーティ データ接続をデータ準備ツールとして設定すると、UPDM の高度な機能なしでデータのインポートをスケジュールし、データを変換できます。このタイプの接続では、1 つの Google Cloud プロジェクトのみが必要です。
  • データソース: 接続されたプロダクト、インポートされたファイル、またはサードパーティ統合(BigQuery など)。
  • リンク先: ユースケース: 通常、インポートしたデータを Google プロダクトまたはプロダクトの機能で活用(Ads Data Hub ユーザー提供データ マッチングなど)
  • 管理プロジェクト: 独自の広告データを元の形式で格納する Google Cloud プロジェクト。
  • 出力データセット: Ads Data Hub が書き込む BigQuery データセット。デフォルトでは、これは管理プロジェクト内のデータセットです。別の Google Cloud プロジェクトに変更するには、サービス アカウントを構成するをご覧ください。

プロセスの概要

  1. データの取り込みと照合の設定
  2. ファーストパーティ データの取り込みとマッチング
    • お客様が自社データをフォーマットし、BigQuery データセットにアップロードします。最も簡単な設定では、管理プロジェクトを使用します。ただし、所有している BigQuery データセットは使用できます。
    • データ マッチング リクエストを開始するには、接続を作成し、インポート スケジュールを設定します。
    • Google は、プロジェクトと Google 所有のデータ(Google のユーザー ID とハッシュ化されたユーザー提供データを含む)のデータを結合して、マッチテーブルを構築および更新します。
    • ファーストパーティ データを取り込むをご覧ください。
  3. 一致したデータに基づく Ads Data Hub の継続的なクエリ
    • マッチテーブルに対してクエリを実行する方法は、Ads Data Hub で通常のクエリを実行する方法と同じです。一致したデータをクエリするをご覧ください。

プライバシー要件について

顧客データの収集

ユーザー提供データ マッチングを使用する場合は、ファーストパーティ データをアップロードする必要があります。ウェブサイト、アプリ、実店舗で収集した情報や、顧客から直接提供された情報などです。

以下を行ってください:

  • 広告主様に代わってサービスを提供する第三者と顧客データを共有していることをプライバシー ポリシーで開示すること、また、法律上必要な場合はそのような共有について同意を得ること
  • 顧客データをアップロードする際には、Google が承認する API かインターフェースのみを使用すること
  • 適用されるすべての法律および規制(自主規制によるガイドラインや業界が定めるガイドラインを含む)を遵守すること

ファーストパーティによる同意取得の確認

Ads Data Hub でファーストパーティ データを使用するには、EU ユーザーの同意ポリシーAds Data Hub ポリシーに則って、Google へのデータ共有に対する EEA のエンドユーザーによる適切な同意を取得していることを確認する必要があります。同意取得の確認は、Ads Data Hub アカウントごとに、新しいファーストパーティ データをアップロードするたびに行う必要があります。1 人のユーザーがアカウント全体を代表してこの確認を行うことができます。

分析クエリに適用される同じ Google サービス クエリルールが UPDM クエリにも適用されます。たとえば、マッチテーブルを作成する際、EEA 内のユーザーに対してサービス間クエリを実行することはできません。

Ads Data Hub で同意獲得を確認する方法については、欧州経済領域の同意に関する要件をご覧ください。

データサイズ

エンドユーザーのプライバシーを保護するため、ユーザー提供データのマッチングでは、データのサイズに関する次の要件が適用されます。

  • ユーザーリストには 1,000 件以上のレコードをアップロードする必要があります。
  • マッチテーブルの更新が成功するたびに、新たにマッチしたユーザーが一定数含まれている必要があります。この動作は差分チェックと同様です。
  • リストはレコードの最大数を超えないようにしてください。データの上限について詳しくは、Google の担当者にお問い合わせください。

データの取り込みを設定する

始める前に、データ接続を作成するように Ads Data Hub アカウントを構成する必要があります。これにより、データ マッチング パイプラインを確立できます。この手順は 1 回だけ行います。

[接続] ページで [設定を開始] をクリックして、UPDM 有効化ステージでアカウント設定ウィザードを開きます。

[接続] に移動

BigQuery と Cloud Storage にどのような権限が付与されますか?

BigQuery または Cloud Storage で使用するように UPDM を設定する場合は、このリファレンスを使用して、Ads Data Hub サービス アカウントに付与される権限を確認してください。

BigQuery

Data Fusion サービス アカウント
目的 Data Fusion サービス アカウントは、Ads Data Hub の UI にソース フィールドのリストを表示するために使用されます。
形式 service-some-number@gcp-sa-datafusion.iam.gserviceaccount.com
必要なアクセス権
BigQuery Data Viewer
roles/bigquery.dataViewer
データソース プロジェクトと宛先 プロジェクトの特定のデータセットに対して
Storage Admin
roles/storage.admin
データソース プロジェクトまたは専用のストレージ バケット
Dataproc サービス アカウント
目的 Dataproc サービス アカウントは、バックグラウンドでのデータ パイプラインの実行を担います。
形式 some-number-compute@developer.gserviceaccount.com
必要なアクセス権
BigQuery Data Viewer
roles/bigquery.dataViewer
データソース プロジェクトと宛先 プロジェクトの特定のデータセットに対して
BigQuery Data Editor
roles/bigquery.dataEditor
宛先 プロジェクト内の特定のデータセット
BigQuery Job User
roles/bigquery.jobUser
データソース プロジェクトと宛先 プロジェクトの両方に対して
Storage Admin
roles/storage.admin
データソース プロジェクトと宛先プロジェクトの両方、または専用のストレージ バケット
UPDM サービス アカウント
目的 UPDM サービス アカウントは、一致するジョブを実行するために使用されます。
形式 service-some-number@gcp-sa-adsdataconnector.iam.gserviceaccount.com
必要なアクセス権
BigQuery Data Viewer
roles/bigquery.dataViewer
宛先プロジェクトの
BigQuery Job User
roles/bigquery.jobUser
宛先プロジェクトの

Cloud Storage

Data Fusion サービス アカウント
目的 Data Fusion サービス アカウントは、Ads Data Hub の UI にソース フィールドのリストを表示するために使用されます。
形式 service-some-number@gcp-sa-datafusion.iam.gserviceaccount.com
必要なアクセス権
Storage Object Viewer
roles/storage.objectViewer
データソース プロジェクト内の特定のストレージ バケットに対して
BigQuery Data Viewer
roles/bigquery.dataViewer
データソース プロジェクトまたは専用のストレージ バケット
Storage Admin
roles/storage.admin
データソース プロジェクトまたは専用のストレージ バケット
Dataproc サービス アカウント
目的 Dataproc サービス アカウントは、バックグラウンドでのデータ パイプラインの実行を担います。
形式 some-number-compute@developer.gserviceaccount.com
必要なアクセス権
Storage Admin
roles/storage.admin
データソース プロジェクトと宛先プロジェクトの両方、または専用のストレージ バケット
BigQuery Job User
roles/bigquery.jobUser
宛先プロジェクトの
UPDM サービス アカウント
目的 UPDM サービス アカウントは、一致するジョブを実行するために使用されます。
形式 service-some-number@gcp-sa-adsdataconnector.iam.gserviceaccount.com
必要なアクセス権
BigQuery Data Viewer
roles/bigquery.dataViewer
宛先プロジェクトの
BigQuery Job User
roles/bigquery.jobUser
宛先プロジェクトの

その他のデータソース

他のデータソースでは不要

ファーストパーティ データを取り込み、照合する

入力用にデータをフォーマットする

データが正しく照合されるようにするには、次の形式要件を満たす必要があります。

  • 次の入力フィールドの説明に記載されている場合は、SHA256 ハッシュを使用してアップロードする必要があります。
  • 入力フィールドは文字列としてフォーマットする必要があります。たとえば、Base16 エンコード関数(TO_HEX)で BigQuery の SHA256 ハッシュ関数を使用している場合は、TO_HEX(SHA256(user_data)) という変換を使用します。
  • UPDM は、Base16 と Base64 の両方のエンコードをサポートしています。ファーストパーティ データのエンコードを、Ads Data Hub クエリで使用されるデコードと合わせる必要があります。ファーストパーティ データのエンコードを変更する場合は、同じベースからデコードするように Ads Data Hub クエリを更新する必要があります。次の例では、Base16 エンコードを使用しています。

ユーザー ID

  • 書式なしテキスト
  • ハッシュ化: なし

メール

  • 先頭と末尾の空白文字を削除する
  • 文字はすべて小文字にしてください
  • すべてのメールアドレスにドメイン名(gmail.com や hotmail.co.jp など)を含めてください
  • アクセントを削除する(例: è、é、ê、ë を e に変更する)
  • gmail.comgooglemail.com のメールアドレスのドメイン名の前にあるすべてのピリオド(.)を削除する
  • ハッシュ化: Base16 でエンコードされた SHA256

有効: TO_HEX(SHA256("jeffersonloveshiking@gmail.com"))

無効: TO_HEX(SHA256("JéffersonLôvesHiking@gmail.com"))

電話

  • 空白文字を削除する
  • E.164 形式で入力します(例: 米国の場合は +14155552671、英国の場合は +442071838750)。
  • 特殊記号はすべて削除する(ただし、国コードの直前の「+」はそのままにする)
  • ハッシュ化: Base16 でエンコードされた SHA256

有効: TO_HEX(SHA256("+18005550101"))

無効: TO_HEX(SHA256("(800) 555-0101"))

  • 空白文字を削除する
  • 文字はすべて小文字にしてください
  • 姓名の前後につく称号や肩書(例: お客様、Ms.、博士
  • アクセント(例: è、é、ê、ë)は削除しないでください
  • ハッシュ化: Base16 でエンコードされた SHA256

有効: TO_HEX(SHA256("daní"))

無効: TO_HEX(SHA256("Daní"))

  • 空白文字を削除する
  • 文字はすべて小文字にしてください
  • 末尾の文字列(Jr.、シニア マネージャー、2nd、3rd、II、III、PHD、MD
  • アクセント(例: è、é、ê、ë)は削除しないでください
  • ハッシュ化: Base16 でエンコードされた SHA256

有効: TO_HEX(SHA256("delacruz"))

無効: TO_HEX(SHA256("de la Cruz, Jr."))

  • 顧客データがすべて同じ国のものである場合も、国コードを含めてください
  • 国データはハッシュ化しないでください
  • ISO 3166-1 alpha-2 の国コードを使用
  • ハッシュ化: なし

有効: US

無効: United States of America または USA

郵便番号

  • 郵便番号のデータはハッシュ化しないでください
  • 米国の郵便番号と国際郵便番号の両方を使用できます
  • 米国の場合:
    • 5 桁の郵便番号を使用できます(例: 94043)
    • 5 桁の後に 4 桁の拡張コードが続く形式も使用できます(例: 94043-1351、940431351)。
  • その他の国の場合:
    • 書式設定は不要(小文字にする必要なし、スペースや特殊文字を削除する必要なし)
    • 郵便番号の拡張コード部分は省略してください
  • ハッシュ化: なし

ハッシュの検証とデータのエンコード

次のハッシュ検証スクリプトを使用して、データの形式が正しいことを確認できます。

JavaScript

Base16

/**
 * @fileoverview Provides the hashing algorithm for User-Provided Data Match, as
 * well as some valid hashes of sample data for testing.
*/

async function hash(token) {
  // Removes leading or trailing spaces and converts all characters to lowercase.
  const formattedToken = token.trim().toLowerCase();
  // Hashes the formatted string using the SHA-256 hashing algorithm.
  const hashArrayBuffer = await crypto.subtle.digest(
      'SHA-256', (new TextEncoder()).encode(formattedToken));
  // Converts the hash buffer to a hexadecimal string.
  return Array.from(new Uint8Array(hashArrayBuffer))
      .map((b) => b.toString(16).padStart(2, '0'))
      .join('');
}

function main() {
  // Expected hash for test@gmail.com:
  // 87924606b4131a8aceeeae8868531fbb9712aaa07a5d3a756b26ce0f5d6ca674
  hash('test@gmail.com').then(result => console.log(result));

  // Expected hash for +18005551212:
  // 61d9111bed3e6d9cfc1bc3b5cb35a402687c4f1546bee061a2bd444fbdd64c44
  hash('+18005551212').then(result => console.log(result));

  // Expected hash for John:
  // 96d9632f363564cc3032521409cf22a852f2032eec099ed5967c0d000cec607a
  hash('John').then(result => console.log(result));

  // Expected hash for Doe:
  // 799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f
  hash('Doe').then(result => console.log(result));
}

main()

Base64

/**
 * @fileoverview Provides the hashing algorithm, as well as some valid hashes of
 * sample data for testing.
*/

async function hash(token) {
  // Removes leading or trailing spaces and converts all characters to lowercase.
  const formattedToken = token.trim().toLowerCase();
  // Hashes the formatted string using the SHA-256 hashing algorithm.
  const hashBuffer = await crypto.subtle.digest(
      'SHA-256', (new TextEncoder()).encode(formattedToken));
  // Converts the hash buffer to a base64-encoded string and returns it.
  const base64Str = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
  return base64Str;
}

function main() {
  // Expected hash for test@gmail.com:
  // h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
  hash('test@gmail.com').then(result => console.log(result));

  // Expected hash for +18005551212:
  // YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
  hash('+18005551212').then(result => console.log(result));

  // Expected hash for John: ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
  hash('John').then(result => console.log(result));

  // Expected hash for Doe: eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
  hash('Doe').then(result => console.log(result));
}

main()

Python

Base16

"""Provides the hashing algorithm, as well as some valid hashes of sample data for testing.

Supports: Python 2, Python 3

Sample hashes:

  - Email 'test@gmail.com': 87924606b4131a8aceeeae8868531fbb9712aaa07a5d3a756b26ce0f5d6ca674
  - Phone '+18005551212':   61d9111bed3e6d9cfc1bc3b5cb35a402687c4f1546bee061a2bd444fbdd64c44
  - First name 'John':      96d9632f363564cc3032521409cf22a852f2032eec099ed5967c0d000cec607a
  - Last name 'Doe':        799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f
"""

import base64
import hashlib

def updm_hash(token):
# Generates a SHA-256 hash of the input token after normalization.
  return hashlib.sha256(token.strip().lower().encode('utf-8')).hexdigest()

def print_updm_hash(token):
# Prints the SHA-256 hash and the original token.
  print('Hash: "{}"\t(Token: {})'.format(updm_hash(token), token))

def main():
# Hashes and prints sample tokens.
  print_updm_hash('test@gmail.com')
  print_updm_hash('+18005551212')
  print_updm_hash('John')
  print_updm_hash('Doe')

if __name__ == '__main__':
  main()

Base64

"""Provides the hashing algorithm, as well as some valid hashes of sample data for testing.

Supports: Python 2, Python 3

Sample hashes:

  - Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
  - Phone '+18005551212':   YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
  - First name 'John':      ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
  - Last name 'Doe':        eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
"""

import base64
import hashlib

def hash(token):
# Generates a base64-encoded SHA-256 hash of a normalized input string.
  return base64.b64encode(
      hashlib.sha256(
          token.strip().lower().encode('utf-8')).digest()).decode('utf-8')

def print_hash(token, expected=None):
# Computes and displays the hash of a token, with optional validation.
  hashed = hash(token)

  if expected is not None and hashed != expected:
    print(
        'ERROR: Incorrect hash for token "{}". Expected "{}", got "{}"'.format(
            token, expected, hashed))
    return

  print('Hash: "{}"\t(Token: {})'.format(hashed, token))

def main():
# Tests the hash function with sample tokens and expected results.
  print_hash(
      'test@gmail.com', expected='h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=')
  print_hash(
      '+18005551212', expected='YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=')
  print_hash('John', expected='ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=')
  print_hash('Doe', expected='eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=')

if __name__ == '__main__':
  main()

Go

Base16

/*
Provides the hashing algorithm, as well as some valid hashes of sample data for testing.

Sample hashes:

  - Email 'test@gmail.com': 87924606b4131a8aceeeae8868531fbb9712aaa07a5d3a756b26ce0f5d6ca674
  - Phone '+18005551212':   61d9111bed3e6d9cfc1bc3b5cb35a402687c4f1546bee061a2bd444fbdd64c44
  - First name 'John':      96d9632f363564cc3032521409cf22a852f2032eec099ed5967c0d000cec607a
  - Last name 'Doe':        799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f
*/
package main

import (
  "crypto/sha256"
  "fmt"
  "strings"
)

// Hash hashes an email, phone, first name, or last name into the correct format.
func Hash(token string) string {
  formatted := strings.TrimSpace(strings.ToLower(token))
  hashed := sha256.Sum256([]byte(formatted))
  encoded := fmt.Sprintf("%x", hashed[:])
  return encoded
}

// PrintHash prints the hash for a token.
func PrintHash(token string) {
  fmt.Printf("Hash: \"%s\"\t(Token: %s)\n", Hash(token), token)

}

func main() {
  PrintHash("test@gmail.com")
  PrintHash("+18005551212")
  PrintHash("John")
  PrintHash("Doe")
}

Base64

/*
Provides the hashing algorithm, as well as some valid hashes of sample data for testing.

Sample hashes:

  - Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
  - Phone '+18005551212':   YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
  - First name 'John':      ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
  - Last name 'Doe':        eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
*/
package main

import (
  "crypto/sha256"
  "encoding/base64"
  "fmt"
  "strings"
)

// Hash hashes an email, phone, first name, or last name into the correct format.
func Hash(token string) string {
  formatted := strings.TrimSpace(strings.ToLower(token))
  hashed := sha256.Sum256([]byte(formatted))
  encoded := base64.StdEncoding.EncodeToString(hashed[:])
  return encoded
}

// PrintHash prints the hash for a token.
func PrintHash(token string) {
  fmt.Printf("Hash: \"%s\"\t(Token: %s)\n", Hash(token), token)

}

func main() {
  PrintHash("test@gmail.com")
  PrintHash("+18005551212")
  PrintHash("John")
  PrintHash("Doe")
}

Java

Base16

package updm.hashing;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.base.Ascii;
import com.google.common.hash.Hashing;

/**
 * Example of the UPDM hashing algorithm using hex-encoded SHA-256.
*
* <p>This uses the Guava Hashing to generate the hash: https://github.com/google/guava
*
* <p>Sample valid hashes:
*
* <ul>
*   <li>Email "test@gmail.com": "87924606b4131a8aceeeae8868531fbb9712aaa07a5d3a756b26ce0f5d6ca674"
*   <li>Phone "+18005551212": "61d9111bed3e6d9cfc1bc3b5cb35a402687c4f1546bee061a2bd444fbdd64c44"
*   <li>First name "John": "96d9632f363564cc3032521409cf22a852f2032eec099ed5967c0d000cec607a"
*   <li>Last name "Doe": "799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f"
* </ul>
*/
public final class HashExample {

  private HashExample() {}

  public static String hash(String token) {
    // Normalizes and hashes the input token.
    String formattedToken = Ascii.toLowerCase(token).strip();
    return Hashing.sha256().hashString(formattedToken, UTF_8).toString();
  }

  public static void printHash(String token) {
    // Calculates and prints the token's hash.
    System.out.printf("Hash: \"%s\"\t(Token: %s)\n", hash(token), token);
  }

  public static void main(String[] args) {
    // Executes hash calculations and prints results for sample tokens.
    printHash("test@gmail.com");
    printHash("+18005551212");
    printHash("John");
    printHash("Doe");
  }
}

Base64

package updm.hashing;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
* Example of the hashing algorithm.
*
* <p>Sample hashes:
*
* <ul>
*   <li>Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
*   <li>Phone '+18005551212': YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
*   <li>First name 'John': ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
*   <li>Last name 'Doe': eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=
* </ul>
*/
public final class HashExample {

private HashExample() {}

public static String hash(String token) {
  // Normalizes and hashes the input token using SHA-256 and Base64 encoding.
  String formattedToken = token.toLowerCase().strip();

  byte[] hash;
  try {
    hash = MessageDigest.getInstance("SHA-256").digest(formattedToken.getBytes(UTF_8));
  } catch (NoSuchAlgorithmException e) {
    throw new IllegalStateException("SHA-256 not supported", e);
  }

  return Base64.getEncoder().encodeToString(hash);
}

public static void printHash(String token) {
  // Calculates and prints the hash for the given token.
  System.out.printf("Hash: \"%s\"\t(Token: %s)\n", hash(token), token);
}

public static void main(String[] args) {
  // Executes hash calculations and prints results for sample tokens.
  printHash("test@gmail.com");
  printHash("+18005551212");
  printHash("John");
  printHash("Doe");
}
}

SQL

Base16

/*
Provides the hashing algorithm, as well as some valid hashes of sample data for testing.

The following code uses Google Standard SQL and can be run on BigQuery to generate match tables from unhashed data.

Sample hashes:

  - Email 'test@gmail.com': 87924606b4131a8aceeeae8868531fbb9712aaa07a5d3a756b26ce0f5d6ca674
  - Phone '+18005551212':   61d9111bed3e6d9cfc1bc3b5cb35a402687c4f1546bee061a2bd444fbdd64c44
  - First name 'John':      96d9632f363564cc3032521409cf22a852f2032eec099ed5967c0d000cec607a
  - Last name 'Doe':        799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f

The unhashed input table schema is assumed to be:

- Column name: UserID, Type: String
- Column name: Email, Type: String
- Column name: Phone, Type: String
- Column name: FirstName, Type: String
- Column name: LastName, Type: String
- Column name: PostalCode, Type: String
- Column name: CountryCode, Type: String
*/

-- Creates a new table with hashed versions of specified columns from the input table.
CREATE TABLE `your_project_name.your_dataset_name.output_hashed_table_name`
AS
SELECT
  UserID,
  TO_HEX(SHA256(LOWER(Email))) AS Email,
  TO_HEX(SHA256(Phone)) AS Phone,
  TO_HEX(SHA256(LOWER(FirstName))) AS FirstName,
  TO_HEX(SHA256(LOWER(LastName))) AS LastName,
  PostalCode,
  CountryCode,
FROM
  `your_project_name.your_dataset_name.input_unhashed_table_name`;

Base64

/*
Provides the hashing algorithm, as well as some valid hashes of sample data for testing.

The following code uses Google Standard SQL and can be run on BigQuery to generate match tables from unhashed data.

Sample hashes:

  - Email 'test@gmail.com': h5JGBrQTGorO7q6IaFMfu5cSqqB6XTp1aybOD11spnQ=
  - Phone '+18005551212':   YdkRG+0+bZz8G8O1yzWkAmh8TxVGvuBhor1ET73WTEQ=
  - First name 'John':      ltljLzY1ZMwwMlIUCc8iqFLyAy7sCZ7VlnwNAAzsYHo=
  - Last name 'Doe':        eZ75KhGvkY4/t0HfQpNPO1aO0tk6wd908bjUGieTKm8=

The unhashed input table schema is assumed to be:

- Column name: UserID, Type: String
- Column name: Email, Type: String
- Column name: Phone, Type: String
- Column name: FirstName, Type: String
- Column name: LastName, Type: String
- Column name: PostalCode, Type: String
- Column name: CountryCode, Type: String
*/

-- Creates a new table with Base64-encoded SHA-256 hashes of specified columns.
CREATE TABLE `your_project_name.your_dataset_name.output_hashed_table_name`
AS
SELECT
  UserID,
  TO_BASE64(SHA256(LOWER(Email))) AS Email,
  TO_BASE64(SHA256(Phone)) AS Phone,
  TO_BASE64(SHA256(LOWER(FirstName))) AS FirstName,
  TO_BASE64(SHA256(LOWER(LastName))) AS LastName,
  PostalCode,
  CountryCode,
FROM
  `your_project_name.your_dataset_name.input_unhashed_table_name`;

統合キー

ユーザー提供データの組み合わせによっては、他の組み合わせよりも強力なものもあります。以下に、ユーザー提供データのさまざまな組み合わせの一覧を示します。相対的な強さに基づいてランク付けされています。住所を使用する場合は、氏名、姓、国、郵便番号を含める必要があります。

  1. メールアドレス、電話番号、住所(最も強力)
  2. 電話番号、住所
  3. メールアドレス、住所
  4. メールアドレス、電話番号
  5. 住所
  6. 電話
  7. メール(最も安全でない)

一致テーブルを作成する

  1. [接続] > [接続を作成] > [ユーザー提供データ マッチング] をクリックします。
  2. データソースを選択して、[接続] をクリックします。
  3. プロンプトが表示されたら認証し、[次へ] をクリックします。

    BigQuery

    [適用] をクリックして、BigQuery へのアクセス権を付与します。

    Cloud Storage

    [適用] をクリックして、Cloud Storage へのアクセスを許可します。

    MySQL

    MySQL データベースの場所、ポート、ユーザー名、パスワードを入力します。

    S3

    Amazon S3 のシークレット アクセスキーを入力します。

    PostgreSQL

    PostgreSQL データベースの場所、ポート、ユーザー名、パスワード、データベースを入力します。

    Redshift

    Redshift データベースの場所、ポート、ユーザー名、パスワード、データベースを入力します。

    sFTP

    sFTP サーバーの場所、ユーザー名、パスワードを入力します。

    Snowflake

    Snowflake アカウント ID、ユーザー名、パスワードを入力します。

  4. データソースを構成して、[次へ] をクリックします。

    BigQuery

    インポートする BigQuery テーブルを選択します。

    Cloud Storage

    gsutil パス(gs://my-bucket/folder/ など)を入力し、ファイルの形式を選択します。

    このリソースに初めて接続する場合は、アラートが表示されます。[適用] をクリックしてアクセス権を付与し、[次へ] をクリックします。注: 関連するバケットの storage.buckets.setIamPolicy を委任する権限を持つロールが必要です。

    MySQL

    使用する MySQL データベースとテーブルを選択します。

    S3

    アップロードするファイルのパス(ホストアドレスに対する相対パス)を入力します。

    PostgreSQL

    PostgreSQL スキーマとテーブル(またはビュー)名を入力します。

    Redshift

    Redshift スキーマとテーブル(またはビュー)の名前を入力します。デフォルトでは、Redshift は cluster-identifier.account-number.aws-region.redshift.amazonaws.com というテンプレートに続くデータベースのロケーション URL を使用します。

    sFTP

    ファイルパスと名前を /PATH/FILENAME.csv の形式で入力します。

    Snowflake

    使用する Snowflake データベース、スキーマ、テーブル(またはビュー)を入力します。

  5. 中間リンク先として使用する BigQuery データセットを選択し、[次へ] をクリックします。このステップにより、データが正しい形式であることを確かめることができます。
  6. 省略可: データの形式を変更します。変換には、ハッシュの計算、小文字/大文字の形式設定、フィールドの結合/分割が含まれます。
    1. [操作] > > [変換] をクリックします。
    2. ポップアップ パネルで、[変換を追加] または [別の変換を追加] をクリックします。
    3. プルダウン メニューから変換タイプを選択し、要件を入力します。
    4. [保存] をクリックします。
  7. 結合キーを 1 つ以上選択し、使用するフィールドをマッピングします。同じ名前のフィールドは自動的にマッピングされ、 で示されます。必要な編集を行い、[次へ] をクリックします。
  8. スケジュールを設定する:
    1. 接続に名前を付けます。
    2. 前の手順で選択したデータセットにデータをインポートする頻度を設定します。各実行で、宛先テーブルのデータが上書きされます。
    3. ユーザー ID の競合を処理する方法を指定します。既存の一致を保持するか、新しいデータで上書きするかを選択できます。
  9. [完了] をクリックします。通常、マッチテーブルは作成から 12 時間後にクエリを実行できるようになります。

接続の詳細を表示する

接続の詳細ページには、特定の接続の最近の実行とエラーに関する情報が表示されます。特定の接続の詳細を表示するには:

  1. [接続] をクリックします。
  2. 接続の名前をクリックして、詳細を表示します。
  3. 接続の詳細と最近の実行が表示されます。それぞれ、接続レベル(接続が実行されなかった)と行レベル(行がインポートされなかった)の 2 種類のエラーが表示されます。
    1. ステータスが [Failed] の場合、接続全体が実行されなかったことを示します(サービス アカウントの権限の問題など)。エラー ステータスをクリックすると、接続に影響したエラーを確認できます。
    2. [Completed] ステータスは、接続が正常に実行されたことを示します。ただし、行レベルのエラーがまだ存在する可能性があります。これは、[エラーのある行] 列に 0 以外の値が表示されることで示されます。値をクリックすると、失敗したレコードの詳細を確認できます。

接続を編集する

次の詳細を編集できます。

  • 接続名
  • スケジュール
  • 宛先テーブル
  • フィールド マッピング

データソースの編集はサポートされていません。データソースを変更するには、新しい接続を作成して古い接続を削除します。

接続の詳細を編集するには:

  1. [接続] をクリックします。
  2. 編集する接続の名前をクリックします。
  3. 変更する詳細を編集します。
    • 接続名: [編集] をクリックして新しい名前を入力し、Enter キーを押します。
    • スケジュール: [編集] をクリックして新しいスケジュールを設定し、[保存] をクリックします。
    • 宛先テーブル: [編集] をクリックして新しい宛先名を入力し、[保存] をクリックします。
    • 項目マッピング: をクリックして項目を変更し、[保存] をクリックします。
  4. をクリックします。

一致したデータをクエリする

マッチテーブルにクエリを実行する

マッチテーブルにプライバシー チェックの発動に十分なデータが蓄積されている場合は、テーブルでクエリを実行できます。

ファーストパーティ データ(1PD)の元のテーブルは my_data で表されます。これには、個人を特定できる情報(PII)と PII 以外のデータの両方が含まれます。元のテーブルを使用すると、照合テーブルと比較して、対象範囲内のすべての 1PD データを表すため、より多くの分析情報を得てレポートを改善できます。

Ads Data Hub スキーマ内で user_id フィールドを含むテーブルは、それぞれ対応するマッチテーブルを持ちます。たとえば adh.google_ads_impressions テーブルに対しては adh.google_ads_impressions_updm というマッチテーブルが自動的に生成され、後者にはユーザー ID が含まれています。ポリシー分離テーブル用に個別のマッチテーブルが作成されます。たとえば adh.google_ads_impressions_policy_isolated_youtube テーブルに対しては adh.google_ads_impressions_policy_isolated_youtube_updm というマッチテーブルが自動的に生成され、後者にはユーザー ID が含まれています。

生成されたテーブルには、元のテーブルのユーザーの中から、user_id によるマッチがあったものだけを抽出したサブセットが格納されています。たとえば、元のテーブルにユーザー A とユーザー B のデータが含まれていて、ユーザー A のみにマッチがある場合、ユーザー B はマッチテーブルに格納されません。

マッチテーブルには customer_data_user_id という列があり、ユーザー ID がバイト型で保存されます。

クエリを記述する際は、フィールドのデータ型を考慮することが重要です。SQL の比較演算子では、比較するリテラル同士は同じデータ型であることを期待されます。自社データのテーブルの user_id の格納方法によっては、データをマッチングする前に、テーブル内の値のエンコードが必要となることもあります。マッチングを成功させるには、結合キーをバイトに型変換する必要があります。

JOIN ON
  adh.google_ads_impressions_updm.customer_data_user_id = CAST(my_data.user_id AS BYTES)

また、SQL の文字列比較では大文字と小文字が区別されます。正確な比較ができるよう、必要に応じて双方の文字列をエンコードしてください。

サンプルクエリ

一致したユーザー数をカウントする

このクエリは、Google 広告のインプレッション テーブルで一致したユーザーの数をカウントします。

/* Count matched users in Google Ads impressions table */

SELECT COUNT(DISTINCT user_id)
FROM adh.google_ads_impressions_updm

マッチ率を計算する

すべてのユーザーがマッチングの対象となるわけではありません。たとえば、ログアウトしているユーザー、お子様、同意していないユーザーは、UPDM で照合されません。is_updm_eligible フィールドを使用すると、より正確な UPDM 一致率を計算できます。is_updm_eligible フィールドは 2024 年 10 月 1 日から利用可能になりました。このフィールドを使用して、その日付より前の一致率を計算することはできません。

/* Calculate the UPDM match rate */

CREATE TEMP TABLE total_events OPTIONS(privacy_checked_export=TRUE) AS
SELECT
  customer_id,
  COUNT(*) AS n
FROM adh.google_ads_impressions
WHERE is_updm_eligible
GROUP BY 1;

CREATE TEMP TABLE matched_events OPTIONS(privacy_checked_export=TRUE) AS
SELECT
  customer_id,
  COUNT(*) AS n
FROM adh.google_ads_impressions_updm
GROUP BY 1;

SELECT
  customer_id,
  SAFE_DIVIDE(matched_events.n, total_events.n) AS match_rate
FROM total_events
LEFT JOIN matched_events
  USING (customer_id)

ファーストパーティ データと Google 広告データを結合する

このクエリは、ファーストパーティ データを Google 広告データと結合する方法を示しています。

/* Join first-party data with Google Ads data. The customer_data_user_id field
contains your ID as BYTES. You need to cast your join key into BYTES for
successful matches. */

SELECT
  inventory_type,
  COUNT(*) AS impressions
FROM
  adh.yt_reserve_impressions_updm AS google_data_imp
LEFT JOIN
  `my_data`
ON
  google_data_imp.customer_data_user_id = CAST(my_data.user_id AS BYTES)
GROUP BY
  inventory_type

UPDM に関するよくある質問

UPDM に関するよくある質問の一覧については、UPDM に関するよくある質問をご覧ください。