AML transaction monitoring with a streaming database means evaluating every transaction against structuring rules, velocity thresholds, and network patterns the moment it hits the wire — enabling financial institutions to generate Suspicious Activity Reports faster and with far fewer false positives than legacy batch systems.
The Compliance Cost of Slow Detection
Anti-money laundering compliance is one of the most resource-intensive obligations in banking. U.S. banks paid over $2.7 billion in AML-related fines in a recent five-year period, and the cost of running compliance operations — analysts, case management, and system infrastructure — routinely exceeds $1 billion annually for large institutions.
A core problem: most AML systems are batch-based. They collect transactions throughout the day, run rule engines overnight, and surface alerts the next morning. By then, funds have often moved through multiple hops. Structuring activity — breaking large deposits into smaller amounts to avoid reporting thresholds — can complete across multiple branches before any alert fires.
Streaming databases eliminate the batch window. Rules run continuously over live transaction streams, and alerts fire within seconds.
Key AML Detection Patterns
Effective AML monitoring targets several behavioral patterns:
- Structuring (smurfing): Multiple transactions just below reporting thresholds within a short time window
- Velocity anomalies: Unusual transaction frequency for a given account or customer
- Dormant account activation: Accounts with no activity suddenly moving large volumes
- Round-trip flows: Funds sent out and returned within a short period
- Network clustering: Multiple accounts transacting with the same counterparties
Streaming SQL handles all of these through windowed aggregations and temporal joins.
Ingesting Transaction Data
Connect RisingWave to your core banking transaction stream:
CREATE SOURCE bank_transactions (
transaction_id VARCHAR,
account_id VARCHAR,
counterparty_id VARCHAR,
txn_type VARCHAR, -- 'deposit', 'withdrawal', 'transfer', 'wire'
amount NUMERIC,
currency VARCHAR,
branch_id VARCHAR,
txn_time TIMESTAMPTZ,
channel VARCHAR
)
WITH (
connector = 'kafka',
topic = 'core.banking.transactions',
properties.bootstrap.server = 'broker:9092',
scan.startup.mode = 'latest'
)
FORMAT PLAIN ENCODE JSON;
CREATE TABLE aml_watchlist (
entity_id VARCHAR PRIMARY KEY,
entity_type VARCHAR, -- 'account', 'customer', 'counterparty'
watchlist_type VARCHAR, -- 'sanctions', 'pep', 'high_risk'
added_date DATE
);
Structuring Detection with Tumbling Windows
The most common AML pattern — structuring — involves making multiple deposits just below the $10,000 Currency Transaction Report threshold. Detect it using a tumbling window over 24-hour periods:
CREATE MATERIALIZED VIEW structuring_alerts AS
SELECT
account_id,
COUNT(*) AS txn_count,
SUM(amount) AS total_amount,
MAX(amount) AS max_single_txn,
MIN(amount) AS min_single_txn,
COUNT(DISTINCT branch_id) AS distinct_branches,
window_start,
window_end
FROM TUMBLE(
bank_transactions,
txn_time,
INTERVAL '24 HOURS'
)
WHERE
txn_type IN ('deposit', 'cash_deposit')
AND amount BETWEEN 8000 AND 9999
GROUP BY
account_id,
window_start,
window_end
HAVING
COUNT(*) >= 3
OR (COUNT(*) >= 2 AND COUNT(DISTINCT branch_id) >= 2);
This query continuously maintains counts of sub-threshold cash deposits per account per day. Any account hitting the HAVING threshold immediately surfaces as a structuring candidate.
Velocity and Dormant Account Detection
Hop windows allow overlapping time periods, ideal for detecting velocity spikes:
CREATE MATERIALIZED VIEW velocity_and_dormancy_alerts AS
SELECT
t.account_id,
COUNT(*) AS txn_count_7d,
SUM(t.amount) AS total_volume_7d,
AVG(t.amount) AS avg_txn_amount,
cp.last_activity_date,
CASE
WHEN cp.last_activity_date < NOW() - INTERVAL '180 DAYS'
THEN 'DORMANT_REACTIVATION'
ELSE 'VELOCITY_SPIKE'
END AS alert_type,
window_start,
window_end
FROM HOP(
bank_transactions,
txn_time,
INTERVAL '1 DAY',
INTERVAL '7 DAYS'
) t
LEFT JOIN customer_risk_profiles FOR SYSTEM_TIME AS OF t.txn_time AS cp
ON t.account_id = cp.account_id
GROUP BY
t.account_id,
cp.last_activity_date,
window_start,
window_end
HAVING
COUNT(*) > (cp.avg_weekly_txns * 5)
OR (cp.last_activity_date < NOW() - INTERVAL '180 DAYS' AND SUM(t.amount) > 50000);
Routing Alerts to Case Management
Route confirmed alerts to your case management system via JDBC or Kafka:
CREATE SINK aml_case_management_sink
FROM (
SELECT
account_id,
'STRUCTURING' AS alert_type,
txn_count AS txn_count,
total_amount,
window_start AS period_start,
window_end AS period_end,
NOW() AS generated_at
FROM structuring_alerts
UNION ALL
SELECT
account_id,
alert_type,
txn_count_7d,
total_volume_7d,
window_start,
window_end,
NOW()
FROM velocity_and_dormancy_alerts
)
WITH (
connector = 'jdbc',
jdbc.url = 'jdbc:postgresql://case-mgmt-db:5432/aml',
table.name = 'aml_alerts',
user = 'rw_sink',
password = 'secret'
)
FORMAT PLAIN ENCODE JSON;
Legacy Batch AML vs. Streaming AML
| Dimension | Legacy Batch AML | Streaming AML (RisingWave) |
| Alert latency | 12–24 hours | Seconds |
| Structuring detection | Next day | Within transaction window |
| False positive rate | High (stale context) | Lower (fresh aggregates) |
| Analyst workload | High (manual triage) | Reduced (pre-prioritized) |
| SAR filing timeliness | Risk of deadline breach | Easily within window |
| Infrastructure complexity | High | SQL-only |
| Regulatory exam readiness | Difficult to demonstrate | Real-time audit trail |
FAQ
Q: Does streaming AML replace existing rule engines like Actimize or Mantas? A: Not necessarily. RisingWave can feed pre-processed, enriched alert signals into existing case management platforms. Many institutions use it as a high-speed aggregation layer upstream of their existing AML platform, significantly reducing false positives before alerts reach analysts.
Q: How does RisingWave handle multi-currency transaction normalization? A: Currency conversion rates can be maintained in a RisingWave reference table and joined in real time using temporal joins, normalizing all amounts to a base currency within the materialized view.
Q: Can we perform network analysis (detecting money mule networks) in RisingWave? A: Graph-based network analysis is typically better handled by specialized graph databases. However, RisingWave can identify high-frequency counterparty relationships using aggregations over counterparty_id, which can then feed a graph analytics system.
Q: How do we ensure audit trail completeness for regulators? A: RisingWave sinks to Kafka or JDBC can be configured with exactly-once semantics. Combined with immutable storage targets like Iceberg, this creates a tamper-evident audit trail of all transactions and generated alerts.
Q: What is the typical false positive reduction when moving from batch to streaming? A: Institutions that have moved from nightly batch to streaming AML systems report 30–60% reductions in false positives, primarily because streaming systems use accurate, current behavioral context rather than stale prior-day snapshots.
Get Started
Bring your AML compliance into the real-time era with RisingWave's streaming SQL:
- Start with the quickstart: docs.risingwave.com/get-started
- Talk to practitioners in the community: risingwave.com/slack

