Player segmentation with streaming SQL means your player cohorts — by level, spend, churn risk, engagement tier — update in milliseconds as events arrive, not hours after a batch job runs. RisingWave lets you write standard SQL CREATE MATERIALIZED VIEW statements that maintain segment membership automatically, so your game can act on live player state rather than yesterday's data.
Why Static Segmentation Fails Live-Service Games
Traditional segmentation pipelines export events to a data warehouse, run nightly ETL jobs, and push segment membership back to marketing or liveops tools the next morning. By the time a player has churned, or just crossed a spend threshold, the window to act has closed.
Live-service games — battle passes, limited-time events, seasonal content — demand segments that reflect what players did in the last five minutes, not the last 24 hours. A player who just completed their first raid is a completely different target than they were an hour ago.
RisingWave solves this by processing an event stream and maintaining materialized views that always reflect current state. There is no scheduled job to manage; the view updates as events flow through.
Setting Up the Streaming Pipeline
First, ingest raw gameplay events from Kafka:
CREATE SOURCE gameplay_events (
player_id BIGINT,
event_type VARCHAR,
level INT,
session_id VARCHAR,
revenue_usd NUMERIC,
event_time TIMESTAMPTZ
) WITH (
connector = 'kafka',
topic = 'gameplay-events',
properties.bootstrap.server = 'kafka:9092',
scan.startup.mode = 'latest'
) FORMAT PLAIN ENCODE JSON;
Next, pull player profile reference data from your PostgreSQL database using CDC:
CREATE SOURCE player_profiles (
player_id BIGINT PRIMARY KEY,
country VARCHAR,
acquisition_channel VARCHAR,
signup_date DATE
) WITH (
connector = 'postgres-cdc',
hostname = 'postgres',
port = '5432',
username = 'rw',
password = 'secret',
database.name = 'gamedb',
schema.name = 'public',
table.name = 'player_profiles'
);
Real-Time Segment Materialized Views
Now build the segment logic as materialized views. This first view computes a rolling 7-day activity and spend score for every player, using a tumbling window to bucket events by day:
CREATE MATERIALIZED VIEW player_daily_stats AS
SELECT
player_id,
window_start::DATE AS stat_date,
COUNT(*) AS events_count,
COUNT(*) FILTER (WHERE event_type = 'session_start') AS sessions,
SUM(revenue_usd) AS daily_revenue,
MAX(level) AS max_level
FROM TUMBLE(gameplay_events, event_time, INTERVAL '1 day')
GROUP BY player_id, window_start;
With daily stats streaming in, build a live segment assignment view:
CREATE MATERIALIZED VIEW player_segments AS
SELECT
s.player_id,
p.country,
p.acquisition_channel,
SUM(s.daily_revenue) AS revenue_7d,
SUM(s.sessions) AS sessions_7d,
MAX(s.max_level) AS current_level,
CASE
WHEN SUM(s.daily_revenue) >= 100 THEN 'whale'
WHEN SUM(s.daily_revenue) >= 20 THEN 'dolphin'
WHEN SUM(s.sessions) >= 14 THEN 'highly_engaged_free'
WHEN SUM(s.sessions) >= 3 THEN 'casual'
ELSE 'at_risk'
END AS segment
FROM player_daily_stats s
JOIN player_profiles FOR SYSTEM_TIME AS OF NOW() p
ON s.player_id = p.player_id
WHERE s.stat_date >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY s.player_id, p.country, p.acquisition_channel;
The FOR SYSTEM_TIME AS OF NOW() temporal join ensures every segment computation uses the current player profile data without a stale snapshot.
Pushing Segments Downstream
Once segments are live, push them to downstream systems automatically:
CREATE SINK segments_to_kafka
FROM player_segments
WITH (
connector = 'kafka',
topic = 'player-segments-live',
properties.bootstrap.server = 'kafka:9092'
) FORMAT UPSERT ENCODE JSON;
Your CRM, push notification service, or liveops dashboard subscribes to player-segments-live and can act on segment changes in near real time.
Streaming vs. Batch Segmentation Comparison
| Dimension | Batch (nightly ETL) | Streaming with RisingWave |
| Segment freshness | 12–24 hours | < 1 second |
| Infrastructure complexity | Spark / dbt + scheduler | Single SQL stream processor |
| Query interface | Warehouse SQL | PostgreSQL-compatible SQL |
| Operational overhead | Job monitoring, backfill | Automatic incremental updates |
| Reaction window for liveops | Next day | Same session |
| Cost at scale | High (full table scans) | Incremental compute only |
Common Use Cases for Live Segments
Liveops targeting: Trigger a limited-time offer within the same session a player crosses a spend threshold.
Churn prevention: Identify players whose session frequency has dropped for three consecutive days and push a "we miss you" notification while they are still marginally active.
Difficulty balancing: Route players flagged as highly_engaged_free into slightly harder content to reduce churn from boredom.
A/B test cohort assignment: Assign players to experiment arms at session start based on their current segment, not their segment from last week's batch run.
FAQ
Q: Can RisingWave handle millions of players generating events simultaneously? A: Yes. RisingWave is built as a distributed streaming database. You scale by adding more compute nodes, and the materialized views partition work across them. Kafka partitioning aligns with RisingWave's internal parallelism.
Q: Do I need to re-run the materialized view when a player's profile changes?
A: No. The temporal join with FOR SYSTEM_TIME AS OF NOW() means profile changes in PostgreSQL (replicated via CDC) are picked up automatically on each incremental update of the view.
Q: How stale can the segment data realistically be? A: End-to-end latency from event production to segment update is typically 200–800 ms depending on Kafka lag and cluster load — far below the one-second threshold that matters for same-session liveops triggers.
Q: Can I query player segments directly from my game backend?
A: Yes. RisingWave exposes a PostgreSQL wire protocol, so any language with a Postgres driver can query player_segments with standard SELECT statements. Results are pre-computed; queries return in milliseconds.
Q: What happens to segment history for compliance or analytics purposes?
A: Add a CREATE SINK to an Iceberg or JDBC sink to persist segment snapshots to your data lake or warehouse for longitudinal analysis without impacting the real-time serving path.
Start Building Real-Time Segments
Player segmentation is one of the highest-leverage uses of streaming SQL in gaming. A segment that updates in seconds rather than hours translates directly to higher conversion on liveops offers and better retention intervention timing.
- Read the RisingWave docs and run your first materialized view in minutes: https://docs.risingwave.com/get-started
- Join the community for gaming-specific help and examples: https://risingwave.com/slack

