Real-Time Streaming Analytics

HeliosDB Full plans real-time streaming analytics for event pipelines: continuous SQL queries over Kafka topics with windowed aggregation and exactly-once processing, so that dashboards and alerts read their results from the database rather than from a separate stream processor. Continuous queries and Kafka integration are on the roadmap and not in the current release of HeliosDB Full.

Planned: continuous streaming queries and Kafka integration are on the roadmap.

Problem Being Solved

Root Cause: Traditional databases process batch queries; streaming requires separate infrastructure:

  • System Sprawl: Kafka + Flink + PostgreSQL + Redis + API = 5 systems to maintain
  • Data Duplication: Same data in message queue, processing engine, and database
  • Consistency Gaps: Eventually consistent between stream and database
  • Operational Complexity: Different skills for each system

HeliosDB Solution: Unified Streaming

Streaming SQL Interface

-- Create a stream from Kafka topic
CREATE STREAM clickstream (
    user_id UUID,
    page_url VARCHAR(500),
    event_type VARCHAR(50),
    event_time TIMESTAMPTZ,
    session_id UUID
) WITH (
    connector = 'kafka',
    topic = 'user-clicks',
    format = 'json',
    timestamp_column = 'event_time'
);

-- Real-time page view aggregation (tumbling window)
CREATE MATERIALIZED VIEW page_views_per_minute AS
SELECT
    page_url,
    COUNT(*) as view_count,
    COUNT(DISTINCT user_id) as unique_visitors,
    WINDOW_START as minute_start,
    WINDOW_END as minute_end
FROM clickstream
GROUP BY
    page_url,
    TUMBLE(event_time, INTERVAL '1 minute');

-- Query the materialized view (always up-to-date)
SELECT * FROM page_views_per_minute
WHERE minute_start > NOW() - INTERVAL '5 minutes'
ORDER BY view_count DESC
LIMIT 10;

-- Stream-to-stream join (sessionization)
CREATE STREAM user_sessions AS
SELECT
    c.user_id,
    c.session_id,
    MIN(c.event_time) as session_start,
    MAX(c.event_time) as session_end,
    COUNT(*) as event_count,
    ARRAY_AGG(c.page_url ORDER BY c.event_time) as page_sequence
FROM clickstream c
GROUP BY
    c.user_id,
    c.session_id,
    SESSION(c.event_time, INTERVAL '30 minutes');

Stream-Table Joins

-- Join stream with static table for enrichment
CREATE STREAM enriched_clicks AS
SELECT
    c.user_id,
    c.page_url,
    c.event_time,
    u.subscription_tier,
    u.country,
    p.product_category
FROM clickstream c
JOIN users u ON c.user_id = u.id
LEFT JOIN products p ON c.page_url LIKE '%/product/' || p.id || '%';

-- Real-time fraud detection with table lookup
CREATE STREAM fraud_alerts AS
SELECT
    t.transaction_id,
    t.user_id,
    t.amount,
    t.merchant,
    'HIGH_RISK' as alert_type,
    CURRENT_TIMESTAMP as alert_time
FROM transactions_stream t
JOIN user_risk_profiles r ON t.user_id = r.user_id
WHERE t.amount > r.typical_amount * 3
   OR t.merchant_country != r.home_country
   OR t.hour_of_day NOT BETWEEN r.typical_start_hour AND r.typical_end_hour;

Concrete Examples

Example 1: E-commerce Real-Time Analytics

Company Profile: Online retailer with 10M daily visitors

Challenge: Real-time conversion funnel analysis

-- Create streams for user events
CREATE STREAM user_events (
    user_id UUID,
    event_type VARCHAR(50),  -- 'page_view', 'add_to_cart', 'checkout', 'purchase'
    product_id UUID,
    amount DECIMAL(10,2),
    event_time TIMESTAMPTZ
) WITH (connector = 'kafka', topic = 'user-events');

-- Real-time conversion funnel
CREATE MATERIALIZED VIEW conversion_funnel_5min AS
SELECT
    WINDOW_START as time_bucket,
    COUNT(DISTINCT CASE WHEN event_type = 'page_view' THEN user_id END) as visitors,
    COUNT(DISTINCT CASE WHEN event_type = 'add_to_cart' THEN user_id END) as cart_adds,
    COUNT(DISTINCT CASE WHEN event_type = 'checkout' THEN user_id END) as checkouts,
    COUNT(DISTINCT CASE WHEN event_type = 'purchase' THEN user_id END) as purchases,
    ROUND(
        COUNT(DISTINCT CASE WHEN event_type = 'purchase' THEN user_id END)::FLOAT /
        NULLIF(COUNT(DISTINCT CASE WHEN event_type = 'page_view' THEN user_id END), 0) * 100,
        2
    ) as conversion_rate
FROM user_events
GROUP BY TUMBLE(event_time, INTERVAL '5 minutes');

-- Real-time revenue by product category
CREATE MATERIALIZED VIEW revenue_by_category_hourly AS
SELECT
    p.category,
    SUM(e.amount) as revenue,
    COUNT(*) as order_count,
    AVG(e.amount) as avg_order_value,
    WINDOW_START as hour_start
FROM user_events e
JOIN products p ON e.product_id = p.id
WHERE e.event_type = 'purchase'
GROUP BY p.category, TUMBLE(e.event_time, INTERVAL '1 hour');

Example 2: IoT Sensor Monitoring

Company Profile: Smart building management for 500 buildings

Challenge: Real-time anomaly detection across 1M sensors

-- Create sensor data stream
CREATE STREAM sensor_readings (
    building_id VARCHAR(50),
    sensor_id VARCHAR(100),
    sensor_type VARCHAR(50),
    reading FLOAT,
    reading_time TIMESTAMPTZ
) WITH (
    connector = 'mqtt',
    topic = 'sensors/#',
    throughput = '100000/sec'
);

-- Rolling statistics for anomaly baseline
CREATE MATERIALIZED VIEW sensor_baselines AS
SELECT
    sensor_id,
    sensor_type,
    AVG(reading) as avg_reading,
    STDDEV(reading) as stddev_reading,
    MIN(reading) as min_reading,
    MAX(reading) as max_reading,
    COUNT(*) as sample_count
FROM sensor_readings
GROUP BY sensor_id, sensor_type, HOP(reading_time, INTERVAL '1 minute', INTERVAL '1 hour');

-- Real-time anomaly detection stream
CREATE STREAM sensor_anomalies AS
SELECT
    s.sensor_id,
    s.building_id,
    s.sensor_type,
    s.reading,
    s.reading_time,
    b.avg_reading,
    b.stddev_reading,
    ABS(s.reading - b.avg_reading) / NULLIF(b.stddev_reading, 0) as z_score,
    CASE
        WHEN ABS(s.reading - b.avg_reading) > 3 * b.stddev_reading THEN 'CRITICAL'
        WHEN ABS(s.reading - b.avg_reading) > 2 * b.stddev_reading THEN 'WARNING'
        ELSE 'NORMAL'
    END as severity
FROM sensor_readings s
JOIN sensor_baselines b ON s.sensor_id = b.sensor_id
WHERE ABS(s.reading - b.avg_reading) > 2 * b.stddev_reading;

-- Automated alerting
CREATE SINK alert_sink AS
SELECT * FROM sensor_anomalies
WHERE severity IN ('CRITICAL', 'WARNING')
WITH (
    connector = 'webhook',
    url = 'https://alerts.company.com/sensor',
    batch_size = 1,
    latency = '<1s'
);

Example 3: Financial Transaction Processing

-- Create transaction stream
CREATE STREAM transactions (
    transaction_id UUID,
    card_number_hash VARCHAR(64),
    merchant_id VARCHAR(50),
    amount DECIMAL(15,2),
    currency VARCHAR(3),
    country VARCHAR(2),
    transaction_time TIMESTAMPTZ
) WITH (
    connector = 'kafka',
    topic = 'transactions',
    exactly_once = true
);

-- Real-time velocity checks (sliding window)
CREATE MATERIALIZED VIEW card_velocity AS
SELECT
    card_number_hash,
    COUNT(*) as txn_count_1h,
    SUM(amount) as total_amount_1h,
    COUNT(DISTINCT merchant_id) as unique_merchants_1h,
    COUNT(DISTINCT country) as unique_countries_1h
FROM transactions
GROUP BY
    card_number_hash,
    HOP(transaction_time, INTERVAL '1 minute', INTERVAL '1 hour');

-- Real-time fraud scoring
CREATE STREAM fraud_scores AS
SELECT
    t.transaction_id,
    t.card_number_hash,
    t.amount,
    t.merchant_id,
    -- Velocity-based risk factors
    CASE WHEN v.txn_count_1h > 10 THEN 0.3 ELSE 0 END +
    CASE WHEN v.unique_countries_1h > 2 THEN 0.4 ELSE 0 END +
    CASE WHEN t.amount > v.total_amount_1h THEN 0.2 ELSE 0 END +
    -- Pattern-based risk
    CASE WHEN t.amount = ROUND(t.amount) AND t.amount > 100 THEN 0.1 ELSE 0 END
    as fraud_score,
    t.transaction_time
FROM transactions t
LEFT JOIN card_velocity v ON t.card_number_hash = v.card_number_hash;

-- Block high-risk transactions in real-time
CREATE SINK fraud_blocks AS
SELECT
    transaction_id,
    fraud_score,
    'BLOCKED' as decision
FROM fraud_scores
WHERE fraud_score > 0.7
WITH (
    connector = 'kafka',
    topic = 'fraud-decisions',
    latency_sla = '50ms'
);

Example 4: Log Analytics & Observability

Company Profile: SaaS platform with 1000 microservices

Challenge: Real-time log analysis and alerting

-- Create log stream
CREATE STREAM application_logs (
    service_name VARCHAR(100),
    instance_id VARCHAR(50),
    log_level VARCHAR(10),
    message TEXT,
    trace_id UUID,
    log_time TIMESTAMPTZ
) WITH (
    connector = 'kafka',
    topic = 'app-logs',
    format = 'json'
);

-- Error rate monitoring by service (1-minute windows)
CREATE MATERIALIZED VIEW service_error_rates AS
SELECT
    service_name,
    WINDOW_START as minute,
    COUNT(*) as total_logs,
    COUNT(*) FILTER (WHERE log_level = 'ERROR') as error_count,
    COUNT(*) FILTER (WHERE log_level = 'WARN') as warn_count,
    ROUND(
        COUNT(*) FILTER (WHERE log_level = 'ERROR')::FLOAT /
        NULLIF(COUNT(*), 0) * 100, 2
    ) as error_rate_pct
FROM application_logs
GROUP BY service_name, TUMBLE(log_time, INTERVAL '1 minute');

-- Automatic incident detection
CREATE STREAM incidents AS
SELECT
    service_name,
    minute,
    error_rate_pct,
    'ERROR_SPIKE' as incident_type,
    CURRENT_TIMESTAMP as detected_at
FROM service_error_rates
WHERE error_rate_pct > 5  -- More than 5% errors
   OR error_count > 100;   -- Or absolute threshold

-- Trace aggregation for debugging
CREATE MATERIALIZED VIEW trace_summary AS
SELECT
    trace_id,
    ARRAY_AGG(service_name ORDER BY log_time) as service_sequence,
    MIN(log_time) as trace_start,
    MAX(log_time) as trace_end,
    MAX(log_time) - MIN(log_time) as trace_duration,
    COUNT(*) FILTER (WHERE log_level = 'ERROR') as error_count
FROM application_logs
WHERE trace_id IS NOT NULL
GROUP BY trace_id, SESSION(log_time, INTERVAL '5 minutes');

Conclusion

HeliosDB's unified streaming analytics eliminates the traditional separation between stream processing and databases. Organizations can:

  • Simplify Architecture: One system instead of 3-5
  • Ensure Consistency: ACID guarantees on streaming data

Performance depends on workload and hardware. Published figures are measured on representative fixtures; see the benchmarks page and reproduce them on your own workload.