TemporalStore for Ads Serving
Ads serving needs temporal features, not just profile lookup.
Ads systems depend on fast-changing user intent, campaign state, retrieval signals, ranking features, budget pacing, frequency caps, and policy windows. TemporalStore can serve the sequence and aggregate state behind targeting, retrieval, and ranking without forcing every new signal into a separate cache, stream job, or offline materialized table.
Beyond regular feature serving
Regular feature serving can read a user profile or a campaign attribute. Ads serving often needs the temporal shape: recent ad exposures, conversion paths, interest changes, advertiser/category velocity, campaign spend windows, and per-policy counters. Those signals are naturally sequence and aggregate workloads.
Ads is especially sensitive because the serving decision has many clocks at once: user intent changes in seconds, budgets and pacing move in minutes, conversions feed back over hours, and policy windows may last days. TemporalStore gives those clocks a shared request-time model instead of scattering them across caches and jobs.
Targeting sequences
Recent views, searches, clicks, ad impressions, conversions, skips, reports, and negative actions.
Retrieval signals
User-category, user-advertiser, query-ad, and session-ad interactions keyed by time and context.
Ranking aggregates
Windowed CTR/CVR, dwell, conversion, bid-quality, freshness, fatigue, and engagement counters.
Policy state
Frequency caps, budget windows, pacing counters, safety blocks, consent state, and cooldown periods.
Example: ad eligibility and ranking in one request
A single ad request may need to know whether an ad is eligible, whether the campaign is pacing correctly, whether the user is fatigued, and whether recent actions suggest intent. That is not one feature. It is a temporal decision bundle.
Ad request for user_42:
targeting sequence:
searched "cloud gpu pricing" 3 minutes ago
visited ml-infra page twice today
clicked competitor campaign yesterday
frequency cap:
campaign_9 impressions_1h = 1
campaign_9 impressions_24h = 4
cooldown_until = none
pacing aggregate:
campaign_9 spend_5m = 812.45
budget_remaining = 18214.10
pacing_status = healthy
ranking aggregate:
user_advertiser_24h clicks = 2
user_category_1h conversions = 0
fatigue_score = low
Serving model
TemporalStore can keep ads state in typed temporal models. Retrieval can read recent intent sequences, ranking can read aggregate windows, and policy can read cap and pacing counters. The important part is that the system stores time as a serving primitive, not as a log field discovered later.
AdsServingState:
sequence:user:{user_id}:ad_events
fields = ad_id, advertiser_id, campaign_id, action, surface, ts
aggregate:user_advertiser:{user_id}:{advertiser_id}:24h
fields = impressions, clicks, conversions, reports, last_seen_ts
aggregate:campaign:{campaign_id}:pacing_5m
fields = spend, impressions, clicks, budget_remaining, last_update_ts
cap:user_campaign:{user_id}:{campaign_id}
fields = impressions_1h, impressions_24h, cooldown_until, policy_version
How the latest TemporalStore code informs the ads design
The C++ code shows three useful building blocks for ads serving. Timestamped feature rows support bounded reads over recent actions. Temporal aggregates encode metric, sorted dimensions, bucket width, and bucket id so spend, CTR, CVR, and cap windows can be updated and queried online. The IPS-style model adds table schemas, slots, action types, time ranges, top-k, filters, TTL, compaction, and quota control for large action histories.
| Ads workload | TemporalStore primitive | Why it matters |
|---|---|---|
| Targeting and retrieval history | Timestamped sequences with filters and count limits. | Recent intent can be served directly instead of being hidden in a stale profile value. |
| Pacing, fatigue, and frequency caps | Bucketed aggregates for metric and dimension windows. | Policy and ranking can read the same fresh counters through one serving path. |
| User-advertiser-category state | Schema-driven slots, action types, top-k, sort, and filter operators. | High-cardinality histories become queryable without creating a separate service for every ranking idea. |
Where it helps
Sequence features
Aggregated features
Why ads is a strong TemporalStore fit
- Ads ranking depends on recent intent and temporal feedback loops.
- Targeting and retrieval need user, query, advertiser, category, campaign, and session dimensions.
- Frequency caps and pacing counters need online windows with durable recovery.
- High-cardinality aggregates are expensive to scatter across cache keys, jobs, and services.
- Replayable serving state helps explain why an ad was eligible, ranked, capped, or blocked.
Compared with the usual ads stack
| Layer | Common workaround | TemporalStore advantage |
|---|---|---|
| Frequency caps | Redis TTL keys plus repair jobs. | Windowed cap state with durable recovery and replayable decision metadata. |
| Pacing | Separate counter service and stream jobs. | Typed campaign aggregates that ranking and policy can read through one serving API. |
| Targeting history | Session cache plus nearline joins. | Bounded user/ad event sequences with filters by advertiser, category, surface, and time. |
| Debugging | Join logs, counters, cache snapshots, and ranker traces after the fact. | Replay the temporal state that made the ad eligible, ranked, capped, or blocked. |