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

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

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

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

[接続] タブの概要

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

[Connections] ページは、プライバシーを重視した方法で個人情報(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 の高度な機能を使用せずにデータ インポートのスケジュールを設定してデータを変換します。このタイプの接続に必要な Google Cloud プロジェクトは 1 つだけです。
  • データソース: 接続されたプロダクト、インポートされたファイル、またはサードパーティ統合(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 ハッシュを使用してアップロードする必要があります。
  • 入力フィールドは文字列としてフォーマットする必要があります。たとえば、BigQuery の SHA256 ハッシュ関数を Base16 エンコード関数(TO_HEX)とともに使用する場合は、TO_HEX(SHA256(user_data)) という変換を使用します。
  • UPDM は Base16 と Base64 の両方のエンコードをサポートしています。ファーストパーティ データのエンコードは、Ads Data Hub クエリで使用されるデコードと一致している必要があります。ファーストパーティ データのエンコードを変更する場合は、同じベースからデコードするように Ads Data Hub クエリを更新する必要があります。次の例では、Base16 エンコードを使用しています。

ユーザー ID

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

メール

  • 先頭と末尾の空白文字を削除する
  • 文字はすべて小文字にしてください
  • メールアドレス(Email)には必ずドメイン名(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"))

  • 空白文字を削除する
  • 文字はすべて小文字にしてください
  • 敬称(Mrs.、Mr., 様博士
  • アクセント文字(è、é、ê、ë など)は削除しないでください。
  • ハッシュ: Base16 エンコードの SHA256

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

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

  • 空白文字を削除する
  • 文字はすべて小文字にしてください
  • 姓名の後に付く接尾辞(Jr.、Sr.、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

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

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

    MySQL

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

    S3

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

    PostgreSQL

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

    Redshift

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

    sFTP

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

    Snowflake

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

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

接続の詳細を表示する

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

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

接続を編集する

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

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

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

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

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

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

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

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

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

Ads Data Hub スキーマ内で user_id フィールドを含むテーブルは、それぞれ対応するマッチテーブルを持ちます。たとえば adh.google_ads_impressions テーブルに対しては adh.google_ads_impressions_updm というマッチテーブルが自動的に生成され、後者にはユーザー ID が含まれています。ポリシー分離ネットワーク テーブル用に個別のマッチテーブルが作成されます。たとえば adh.google_ads_impressions_policy_isolated_network テーブルに対しては adh.google_ads_impressions_policy_isolated_network_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 に関するよくある質問をご覧ください。