TL;DR
Master Google Cloud's data analytics services. Learn about BigQuery, Dataflow, Pub/Sub, Dataproc, and best practices for building scalable data analytics solutions.
GCP Data Analytics Services: Building Modern Data Platforms
Google Cloud Platform provides a comprehensive suite of services for building modern data analytics solutions. This guide covers key services and implementation best practices.
$1
`` graph TB
subgraph Analytics["Analytics Platform"]
direction TB
subgraph Ingestion["Data Ingestion"]
direction LR
PS["Pub/Sub"]
DF["Dataflow"]
DC["Data Connector"]
end
subgraph Processing["Data Processing"]
direction LR
BQ["BigQuery"]
DP["Dataproc"]
CF["Cloud Functions"]
end
subgraph Storage["Data Storage"]
direction LR
GCS["Cloud Storage"]
BT["Bigtable"]
DS["Datastore"]
end
end
subgraph Visualization["Data Visualization"]
direction TB
LS["Looker Studio"]
CH["Charts"]
DB["Dashboards"]
end
Analytics --> Visualization
classDef primary fill:#4285f4,stroke:#666,stroke-width:2px,color:#fff
classDef secondary fill:#34a853,stroke:#666,stroke-width:2px,color:#fff
classDef tertiary fill:#fbbc05,stroke:#666,stroke-width:2px,color:#fff
class Analytics,Ingestion primary
class Processing,Storage secondary
class Visualization tertiary
mermaid
`
$1
$1
` -- Create dataset
CREATE SCHEMA IF NOT EXISTS my_dataset
OPTIONS(
location="US",
default_partition_expiration_days=90,
description="Analytics dataset"
); -- Create partitioned and clustered table
CREATE OR REPLACE TABLE my_dataset.events
(
event_id STRING,
user_id STRING,
event_timestamp TIMESTAMP,
event_type STRING,
device STRING,
location STRING,
properties JSON
)
PARTITION BY DATE(event_timestamp)
CLUSTER BY user_id, event_type
OPTIONS(
require_partition_filter=true,
partition_expiration_days=90,
description="Event tracking table"
);
sql
`
$1
` -- Efficient query with partition filter
WITH UserEvents AS (
SELECT
user_id,
event_type,
COUNT(*) as event_count,
MIN(event_timestamp) as first_event,
MAX(event_timestamp) as last_event
FROM my_dataset.events
WHERE DATE(event_timestamp) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
AND CURRENT_DATE()
GROUP BY user_id, event_type
) SELECT
user_id,
ARRAY_AGG(STRUCT(
event_type,
event_count,
first_event,
last_event
)) as event_details,
SUM(event_count) as total_events
FROM UserEvents
GROUP BY user_id
HAVING total_events > 100
ORDER BY total_events DESC
LIMIT 1000;
sql
`
$1
$1
` import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions def parse_event(element):
"""Parse event data."""
import json
event = json.loads(element)
return {
'event_id': event['id'],
'user_id': event['user_id'],
'timestamp': event['timestamp'],
'event_type': event['type'],
'properties': event.get('properties', {})
} def run_pipeline():
"""Execute batch processing pipeline."""
options = PipelineOptions()
with beam.Pipeline(options=options) as p:
events = (
p
| 'ReadFromGCS' >> beam.io.ReadFromText('gs://my-bucket/events/*.json')
| 'ParseJSON' >> beam.Map(parse_event)
| 'AddTimestamp' >> beam.Map(
lambda x: beam.window.TimestampedValue(x, x['timestamp']))
| 'WindowEvents' >> beam.WindowInto(
beam.window.FixedWindows(60 * 60)) # 1-hour windows
| 'CountByType' >> beam.CombinePerKey(sum)
| 'WriteToBigQuery' >> beam.io.WriteToBigQuery(
'project:dataset.table',
schema='event_type:STRING,count:INTEGER',
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND,
create_disposition=beam.io.BigQueryDisposition.CREATE_NEVER)
)
python
`batch_pipeline.py
$1
` def run_streaming():
"""Execute streaming pipeline."""
options = PipelineOptions()
options.view_as(StandardOptions).streaming = True
with beam.Pipeline(options=options) as p:
events = (
p
| 'ReadFromPubSub' >> beam.io.ReadFromPubSub(
subscription='projects/my-project/subscriptions/my-subscription')
| 'ParseJSON' >> beam.Map(parse_event)
| 'AddEventTimestamp' >> beam.Map(
lambda x: beam.window.TimestampedValue(x, x['timestamp']))
| 'WindowEvents' >> beam.WindowInto(
beam.window.SlidingWindows(
size=60 * 60, # 1-hour windows
period=60)) # Sliding every minute
| 'ProcessEvents' >> beam.ParDo(ProcessEvents())
| 'WriteToBigQuery' >> beam.io.WriteToBigQuery(
'project:dataset.table',
schema='event_type:STRING,count:INTEGER,window_start:TIMESTAMP',
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND,
create_disposition=beam.io.BigQueryDisposition.CREATE_NEVER)
)
python
`streaming_pipeline.py
$1
$1
` gcloud pubsub topics create my-topic gcloud pubsub subscriptions create my-subscription \
--topic=my-topic \
--ack-deadline=30 \
--message-retention-duration=7d \
--expiration-period=never
bash
`Create topic
Create subscription
$1
` from google.cloud import pubsub_v1
import json
import time def publish_messages(project_id, topic_id):
"""Publish messages to Pub/Sub topic."""
publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path(project_id, topic_id)
def get_callback(future, data):
def callback(future):
try:
print(f"Published message ID: {future.result()}")
except Exception as e:
print(f"Error publishing {data}: {e}")
return callback
for i in range(100):
data = {
'message_id': i,
'timestamp': time.time(),
'data': f"Message {i}"
}
data_str = json.dumps(data)
future = publisher.publish(
topic_path,
data_str.encode('utf-8'),
origin="python-sample",
username="gcp-user"
)
future.add_done_callback(get_callback(future, data))
python
`publisher.py
$1
$1
` config:
gceClusterConfig:
zoneUri: us-central1-a
subnetworkUri: projects/my-project/regions/us-central1/subnetworks/my-subnet
internalIpOnly: true
masterConfig:
numInstances: 1
machineTypeUri: n1-standard-4
diskConfig:
bootDiskSizeGb: 100
numLocalSsds: 1
workerConfig:
numInstances: 2
machineTypeUri: n1-standard-4
diskConfig:
bootDiskSizeGb: 100
numLocalSsds: 1
softwareConfig:
imageVersion: 2.0
optionalComponents:
- JUPYTER
- ZEPPELIN
yaml
`cluster-config.yaml
$1
` from pyspark.sql import SparkSession
from pyspark.sql.functions import * def process_data():
"""Process data using Spark."""
spark = SparkSession.builder \
.appName("DataProcessing") \
.getOrCreate()
# Read data
df = spark.read.parquet("gs://my-bucket/data/*.parquet")
# Process data
result = df.groupBy("category") \
.agg(
count("*").alias("total_count"),
sum("amount").alias("total_amount"),
avg("amount").alias("avg_amount")
)
# Write results
result.write \
.mode("overwrite") \
.format("bigquery") \
.option("table", "project.dataset.results") \
.save()
python
`spark_job.py
$1
$1
` -- Create view for dashboard
CREATE OR REPLACE VIEW my_dataset.dashboard_data AS
SELECT
DATE(event_timestamp) as event_date,
event_type,
device,
location,
COUNT(*) as event_count,
COUNT(DISTINCT user_id) as unique_users
FROM my_dataset.events
WHERE DATE(event_timestamp) >= DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY)
GROUP BY event_date, event_type, device, location;
sql
`
$1
` // visualization.js
const drawChart = (data) => {
const config = {
type: 'line',
data: {
labels: data.map(d => d.date),
datasets: [{
label: 'Event Count',
data: data.map(d => d.count),
borderColor: '#4285f4',
tension: 0.1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
};
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, config);
};
javascript
`
$1
$1
` -- Optimize table partitioning
ALTER TABLE my_dataset.events
SET OPTIONS (
require_partition_filter=true,
partition_expiration_days=90
); -- Create materialized view
CREATE MATERIALIZED VIEW my_dataset.daily_metrics
AS SELECT
DATE(event_timestamp) as event_date,
event_type,
COUNT(*) as event_count,
COUNT(DISTINCT user_id) as unique_users
FROM my_dataset.events
GROUP BY event_date, event_type;
sql
`
$1
` def optimize_pipeline(p):
"""Optimize Dataflow pipeline."""
return (p
| 'ReadData' >> beam.io.ReadFromSource(...)
| 'Reshuffle' >> beam.Reshuffle() # Optimize data distribution
| 'Transform' >> beam.ParDo(...)
.with_output_types(...) # Add type hints
| 'Combine' >> beam.CombinePerKey(
combine_fn=MyCombineFn(),
fanout=4) # Optimize combine operation
| 'Write' >> beam.io.WriteToBigQuery(...)
)
python
``pipeline_optimization.py
$1
1. BigQuery Optimization
- Use partitioning effectively
- Implement clustering
- Optimize query patterns
- Use materialized views
2. Pipeline Optimization
- Right-size workers
- Use appropriate machine types
- Optimize data flow
- Implement caching
3. Storage Optimization
- Use appropriate storage classes
- Implement lifecycle policies
- Compress data effectively
- Clean up temporary data
$1
1. Data Management
- Implement data governance
- Use proper schemas
- Regular data cleanup
- Version control
2. Security
- Implement proper IAM
- Encrypt sensitive data
- Monitor access patterns
- Regular security reviews
3. Performance
- Monitor resource usage
- Optimize queries
- Regular maintenance
- Scale appropriately
$1
GCP provides powerful services for building data analytics solutions. Key takeaways:
For more information, refer to the official documentation:
Why This Matters
Understanding the business and technical context helps you make informed decisions rather than blindly following patterns.
Trade-offs to Consider
Every architectural decision involves trade-offs. Consider your specific requirements, team expertise, and scale when evaluating options.
When NOT to Use This
Knowing when a solution doesn't apply is as valuable as knowing when it does. Consider alternatives for your specific situation.
Decision Framework
Use this framework to evaluate whether this approach is right for your use case based on your specific constraints and requirements.