Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions spanner-bq-fraud-defense/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Spanner & BigQuery: Real-Time Fraud Defense Shield

This README provides setup instructions and query examples to accompany the [Spanner & BigQuery: Real-Time Fraud Defense Shield](https://codelabs.devsite.corp.google.com/codelabs/next26/spanner-bigquery-graph) codelab (Coming soon!).

## Setup Instructions

### 1. Enable APIs
Enable the necessary Google Cloud APIs in your project:
```bash
gcloud services enable spanner.googleapis.com \
bigquery.googleapis.com \
aiplatform.googleapis.com \
run.googleapis.com
```

### 2. Set up BigQuery Dataset and Connection

Set your Project ID:
```bash
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
```

Create the `game_analytics` dataset:
```bash
bq mk -d --location=US game_analytics
```

Create a connection for external resources:
```bash
bq mk --connection --location=US --project_id=$PROJECT_ID \
--connection_type=CLOUD_RESOURCE unicorn-connection
```

Create schemas (requires `bq_schema.sql`):
```bash
bq query --use_legacy_sql=false < bq_schema.sql
```

Load demo data into BigQuery:
```bash
bq load --source_format=AVRO game_analytics.GameplayTelemetry gs://sample-data-and-media/spanner-bq-fraud-heist/GameplayTelemetry
bq load --source_format=AVRO game_analytics.AccountSignals gs://sample-data-and-media/spanner-bq-fraud-heist/AccountSignals
bq load --source_format=AVRO game_analytics.Players gs://sample-data-and-media/spanner-bq-fraud-heist/Players
bq load --source_format=AVRO game_analytics.ChatLogs gs://sample-data-and-media/spanner-bq-fraud-heist/ChatLogs
```

### 3. Set up Spanner

Create a Spanner instance:
```bash
gcloud spanner instances create game-instance \
--config=regional-us-central1 \
--description="Game Instance" \
--processing-units=100 \
--edition=ENTERPRISE
```

Create database `game-db`:
```bash
gcloud spanner databases create game-db --instance=game-instance
```

Update Spanner schema (requires `spanner_schema.sql`):
```bash
gcloud spanner databases ddl update game-db --instance=game-instance --ddl-file=spanner_schema.sql
```

Create the search index:
```bash
gcloud spanner databases ddl update game-db --instance=game-instance \
--ddl="CREATE SEARCH INDEX AvatarSearchIndex ON Players(AvatarDescriptionTokens)"
```

Insert initial data using Spanner Studio (see codelab for query).

---

## Reverse ETL Query (Continuous Query)

> [!WARNING]
> This query requires BigQuery Continuous Queries, which requires a reservation with ENTERPRISE edition or higher.

This query acts as a reverse-ETL engine, ensuring our transactional system (Spanner) is instantly aware of anomalies detected in our analytical system (BigQuery).

```sql
EXPORT DATA
OPTIONS (
uri = 'https://spanner.googleapis.com/projects/<YOUR_PROJECT_ID>/instances/game-instance/databases/game-db',
format='CLOUD_SPANNER',
spanner_options="""{ "table": "AccountSignals" }"""
) AS
SELECT
GENERATE_UUID() as SignalId,
PlayerId,
'SUSPICIOUS_MOVEMENT' as AlertType,
CURRENT_TIMESTAMP() as EventTime
FROM `game_analytics.GameplayTelemetry`
WHERE
EventType = 'player_move'
AND (LocationX > 1000 OR LocationY > 1000);
```

---

## Graph Query Examples

### 📊 Spanner Graph Example
Find the ringleader by tracing the financial web of transactions where victims transfer to a thief, who then transfers to a boss node.

```sql
GRAPH PlayerNetwork
MATCH (victim)-[:Transfers]->(thief)-[t:Transfers]->(boss)
RETURN boss.Name AS RingLeader, COUNT(t) AS TributesReceived, SUM(t.Amount) AS TotalLoot
GROUP BY RingLeader
ORDER BY TotalLoot DESC
LIMIT 5;
```

### 📈 BigQuery Property Graph Example
Trace communication patterns between players.

```sql
SELECT *
FROM GRAPH_TABLE(game_analytics.CatChatNetwork
MATCH (p1:Players)-[c:Communicates]->(p2:Players)
WHERE p1.Name = 'Pixel' OR p2.Name = 'Pixel'
RETURN
p1.Name AS Sender,
p2.Name AS Receiver,
c.Message,
p1.ProfilePictureUrl.uri AS SenderProfilePic
)
ORDER BY Message DESC;
```
1 change: 1 addition & 0 deletions spanner-bq-fraud-defense/SAMPLEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lsubatin
63 changes: 63 additions & 0 deletions spanner-bq-fraud-defense/bq_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
-- Copyright 2026 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

SET @@dataset_id='game_analytics';
-- BigQuery Schema

CREATE TABLE IF NOT EXISTS GameplayTelemetry (
EventId STRING NOT NULL,
PlayerId STRING NOT NULL,
EventType STRING NOT NULL,
EventTimestamp TIMESTAMP NOT NULL,
LocationX FLOAT64,
LocationY FLOAT64,
ActionDetails STRING
)
PARTITION BY DATE(EventTimestamp);

CREATE TABLE IF NOT EXISTS AccountSignals (
SignalId STRING NOT NULL,
PlayerId STRING NOT NULL,
AlertType STRING NOT NULL,
EventTime TIMESTAMP NOT NULL
)
PARTITION BY DATE(EventTime);

CREATE TABLE IF NOT EXISTS Players (
PlayerId STRING NOT NULL,
Name STRING NOT NULL,
Species STRING NOT NULL,
Clan STRING,
ProfilePictureUrl STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>
);

CREATE TABLE IF NOT EXISTS ChatLogs (
MessageId STRING NOT NULL,
SenderId STRING NOT NULL,
ReceiverId STRING NOT NULL,
Message STRING NOT NULL,
Timestamp TIMESTAMP NOT NULL
)
PARTITION BY DATE(Timestamp);

CREATE OR REPLACE PROPERTY GRAPH CatChatNetwork
NODE TABLES (
Players KEY (PlayerId)
)
EDGE TABLES (
ChatLogs KEY (MessageId)
SOURCE KEY (SenderId) REFERENCES Players (PlayerId)
DESTINATION KEY (ReceiverId) REFERENCES Players (PlayerId)
LABEL Communicates
);
64 changes: 64 additions & 0 deletions spanner-bq-fraud-defense/spanner_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
-- Copyright 2026 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.


-- Spanner Schema (GoogleSQL)

CREATE TABLE IF NOT EXISTS Players (
PlayerId STRING(36) NOT NULL,
Name STRING(128) NOT NULL,
Species STRING(32) NOT NULL,
Clan STRING(32),
AvatarDescription STRING(MAX),
AvatarDescriptionTokens TOKENLIST AS (TOKENIZE_FULLTEXT(AvatarDescription)) HIDDEN,
AvatarEmbedding ARRAY<FLOAT64>(vector_length=>128),
ProfilePictureUrl STRING(MAX),

CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (PlayerId);

CREATE TABLE IF NOT EXISTS AccountSignals (
SignalId STRING(36) NOT NULL DEFAULT (GENERATE_UUID()),
PlayerId STRING(36) NOT NULL,
AlertType STRING(64) NOT NULL,
EventTime TIMESTAMP NOT NULL,
CONSTRAINT FK_PlayerSignal FOREIGN KEY (PlayerId) REFERENCES Players (PlayerId)
) PRIMARY KEY (SignalId);

CREATE TABLE IF NOT EXISTS Transactions (
TransactionId STRING(36) NOT NULL,
SenderId STRING(36) NOT NULL,
ReceiverId STRING(36) NOT NULL,
Amount FLOAT64 NOT NULL,
Timestamp TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
IsSuspicious BOOL,
CONSTRAINT FK_Sender FOREIGN KEY (SenderId) REFERENCES Players (PlayerId),
CONSTRAINT FK_Receiver FOREIGN KEY (ReceiverId) REFERENCES Players (PlayerId)
) PRIMARY KEY (TransactionId);

-- Graph Schema
CREATE OR REPLACE PROPERTY GRAPH PlayerNetwork
NODE TABLES (
Players
)
EDGE TABLES (
Transactions
SOURCE KEY (SenderId) REFERENCES Players (PlayerId)
DESTINATION KEY (ReceiverId) REFERENCES Players (PlayerId)
LABEL Transfers
);

-- Search Index for "Multimodal" Description Search (Simulated via token search for now)