Fraud detection often exposes its freshness problem only in production. A model posts a strong offline AUC on historical data, reaches the inference endpoint, and then misses obvious patterns a human reviewer would notice. The card was just used in three different cities. The account's password was just reset, followed immediately by a wire transfer attempt. The model rates both as low risk.
The model is not broken. Its features are outdated.
This is the structural failure mode of batch feature pipelines in fraud, and it deserves a precise look because the usual answer, "just run batches more frequently," does not resolve it.
How Batch Pipelines Create Latency
A typical batch feature pipeline operates like this: a Spark or dbt job reads one day's transaction data, calculates aggregates such as transaction count per card in the last 24 hours, merchant category frequency distributions, and rolling spend velocity, then writes those vectors to a feature store. It runs nightly at 02:00. By 09:00, fraud models receive features representing behavior only through midnight.
This latency is not an implementation bug. It comes with the batch model itself. The pipeline cannot report a card's transaction velocity at 09:47 this morning because that data has not yet been processed. The next batch window ends at 02:00 tomorrow. That interval is your blind spot.
Some teams shorten the batch interval, moving from hourly jobs to 15-minute jobs. This reduces the delay but does not remove the underlying issue. A micro-batch job running every 15 minutes still handles events in chunks: each run reads the previous 15 minutes, aggregates them, and writes to the feature store. Events from the last 14 minutes remain absent from the current features. The system also runs 96 batch jobs per day instead of one, bringing added compute overhead, scheduling complexity, and failure modes.
Micro-batching reaches roughly 5-10 minutes of latency before operational costs become prohibitive. In fraud, most of the damage occurs within that window.
The Fraud Velocity Window
Card-present fraud, account takeover, and synthetic identity abuse follow a common structure: attackers probe quickly before defenses respond. A stolen card number is tested with a small transaction, then used for a larger one within 90 seconds if the first succeeds. An account takeover begins with a login attempt, then quickly escalates to a payment method change and high-value purchase, all within minutes.
The clearest signals for these patterns are velocity-based and have short half-lives:
- Transaction count in the last 5 minutes, 15 minutes, 60 minutes
- Distinct merchant count in the last hour
- Cumulative spend since last authentication event
- Geographic distance from last transaction
A batch pipeline cannot compute these with meaningful freshness. When a nightly batch job calculates "transaction count in the last 60 minutes," that measured window expired long ago. The result is a stale proxy: the transaction count in the 60-minute window that ended 8 hours ago, offering little insight into what is happening now.
What Incremental Computation Changes
Incremental computation processes events as they arrive rather than batching them for periodic processing. It updates only the affected aggregates, producing a materialized view that continuously reflects the data's current state.
In Feldera, you write a standard SQL view. The engine compiles it into a stateful operator graph and maintains it against an incoming event stream. When a new transaction reaches the Kafka topic, its delta moves through the operator graph, and the corresponding feature values update within milliseconds.
-- Velocity features: update on each arriving transaction
CREATE MATERIALIZED VIEW card_velocity AS
SELECT
card_id,
COUNT(*) FILTER (WHERE event_ts >= NOW() - INTERVAL '5 minutes') AS txn_5m,
COUNT(*) FILTER (WHERE event_ts >= NOW() - INTERVAL '1 hour') AS txn_1h,
SUM(amount) FILTER (WHERE event_ts >= NOW() - INTERVAL '1 hour') AS spend_1h,
COUNT(DISTINCT merchant_id) FILTER (WHERE event_ts >= NOW() - INTERVAL '1 hour') AS distinct_merchants_1h
FROM transactions
GROUP BY card_id;
There is no scheduler, batch trigger, or polling interval. The view remains current. When the inference layer queries card_velocity for a card at scoring time, it reads state calculated from events through that moment, rather than from the most recent batch run.
The Structural Difference
The distinction is more than latency numbers. Batch pipelines calculate features on a schedule and serve those pre-computed values. Incremental pipelines continuously maintain state and serve its current value.
This matters in fraud because signal is not evenly distributed over time. Most transactions on a card are routine. An attacker's burst creates a sharp velocity spike that lasts minutes before potentially going quiet. A feature pipeline viewing the world in 15-minute chunks sees the window's average behavior and dilutes the spike. A continuously maintained view captures it as it develops.
We tested this pattern internally using a synthetic fraud dataset generated from historical card-present fraud transaction logs. At scoring time, velocity features from an incremental pipeline carried approximately 2.3x more signal entropy than the same features from a 15-minute batch cycle, measured by normalized mutual information against the fraud label. This internal benchmark uses synthetic data, so results will vary with transaction volume and fraud prevalence. The directional finding follows the mechanics: batch windows blur the signal that exposes fraud patterns.
Where Batch Still Belongs
This is not a case against batch computation in general. Offline model training, feature backfills for new model candidates, historical analysis, and slowly-changing features such as a customer's purchase category preferences over 90 days are all suitable batch use cases. For features with multi-day windows, maintaining incremental state can cost more than a nightly job reading from a data warehouse.
The point is narrower: when a feature's signal half-life is measured in minutes rather than hours and it directly feeds a real-time inference endpoint, a batch pipeline cannot structurally provide what the model requires. The batch cycle's latency floor is not a tunable configuration parameter. It follows from the pipeline's design.
Most fraud models use features from both groups: velocity and recency signals that need freshness, plus longer-horizon behavioral features that batch computation handles well. The practical approach is to run both: incremental pipelines for time-sensitive features and batch jobs for stable aggregates. Feldera makes this straightforward because both can be written as SQL views, while the incremental engine maintains state for time-sensitive features without changing the query language you already use.
Getting Started
If your fraud model uses batch-computed velocity features, begin by measuring their actual age at inference time. Do not rely on the scheduled batch interval. Join inference logs with batch job timestamps and calculate the feature-age distribution at scoring time. In most systems we have seen, p95 feature age at scoring is much higher than the batch interval implies because late-arriving events, failed batch runs, and feature store write delays compound.
After measuring the distribution, check whether the fraud patterns your model misses are associated with high feature age. If so, incremental computation is worth considering. The Feldera quickstart demonstrates a complete velocity feature pipeline from a Kafka source in under 10 minutes.