1. Problem and Motivation
In production artificial intelligence and machine learning systems, model accuracy is bound by data quality and freshness:
- Real-time fraud detection engines must evaluate user transaction velocity over the last 60 seconds.
- E-commerce recommendation engines must personalize product rankings based on items clicked in the active user session.
- Retrieval-Augmented Generation (RAG) agents must query vector databases containing documents indexed seconds or minutes ago.
Historically, organizations struggled with the “Training-Serving Skew” crisis:
+---------------------------------------------------------------------------------------------------+
| THE TRAINING-SERVING SKEW PARADOX |
+---------------------------------------------------+-----------------------------------------------+
| Offline Model Training (Data Science) | Online Real-Time Inference (Production Eng) |
+---------------------------------------------------+-----------------------------------------------+
| Environment: Jupyter, Python, Pandas, Spark, SQL | Environment: Java, Go, C++, gRPC microservices|
| Execution: Batch processing over historical logs | Execution: Real-time event streams (< 5ms SLA)|
| Feature Logic: 90-day rolling average in SQL | Feature Logic: Re-implemented in Java / Redis |
+---------------------------------------------------+-----------------------------------------------+
| RESULT: Subtle mathematical discrepancies between training and serving code corrupt production |
| predictions, causing catastrophic model performance degradation that is invisible to unit tests. |
+---------------------------------------------------+-----------------------------------------------+
Furthermore, generating training datasets from raw operational tables frequently introduces Future Data Leakage: training records incorporate feature state from hours or days after the event occurred, creating models that boast 99% accuracy in training but fail completely in live production.
AI Feature Stores (Feast, Tecton) and Real-Time Vector Pipelines solve this by serving as the unified data layer for AI: defining features once, serving them consistently across both offline training and online inference, and maintaining fresh vector embeddings.
2. Mental Model & Architectural Overview
The modern AI data infrastructure decouples feature engineering into a Dual-Storage Architecture:
1. The Training-Serving Skew Problem & Online Store (Redis / Cassandra)
Establishes the ingress and structural boundary across The Training-Serving Skew Problem & Online Store (Redis / Cassandra): Training uses Python/Pandas on historical logs; serving uses Java/C++ on live database caches; Code divergence: logic mismatch in production; Feature Store defines logic ONCE in registry Guarantees 100% training-serving consistency!.
2. The Data Leakage Catastrophe & The Time-Travel Invariant
Coordinates core data-plane execution and state transitions through The Data Leakage Catastrophe & The Time-Travel Invariant: User transacted at t=14:30. A naive SQL join takes the user's current 30-day spend total; Spend at 12:00: $120 (Historical truth); Spend at 18:00: $850 (FUTURE LEAKAGE!) Model memorizes future fraud signals in training, then fails completely in real-world inference!.
3. Streaming Embedding Generation & Real-Time Sharded HNSW Ingestion
Enforces durability, state convergence, and output verification across Streaming Embedding Generation & Real-Time Sharded HNSW Ingestion: Continuous live text / media ingestion; Kafka text events → GPU Worker Fleet; Dynamic batching (32/64 items per tensor).
The Architectural Triad:
- Feature Registry & Catalog:
- Centralized GitOps or declarative metadata repository (Feast / Tecton registry).
- Defines entity keys (
user_id,merchant_id), feature data types, computation logic, and ownership. - Enforces identical feature transformation logic across both offline training and online serving.
- Dual-Storage Engine:
- Online Store (Low-Latency Cache - Redis, Cassandra, DynamoDB): Stores only the single latest feature vector for each entity. Optimized for point lookups with sub-2ms response times at 100,000+ QPS.
- Offline Store (Historical Lakehouse - Parquet, Apache Iceberg, Delta Lake): Stores an append-only log of every historical feature update with precise timestamps. Optimized for multi-terabyte batch scans and Point-in-Time joins.
- Real-Time Streaming Vector Pipeline:
- Streaming event queue (Apache Kafka) ingests text, audio, and image changes.
- GPU-accelerated microservices execute dynamic batching to generate 1,024-dimensional transformer embeddings.
- Real-time vector databases ingest embeddings into Sharded HNSW Graphs with dynamic node updates and background tombstone compaction.
3. Mathematical Foundations & Point-in-Time Correctness
3.1 Point-in-Time (Time-Travel / ASOF) Join Formulation
Let an observation event in a training dataset be denoted as:
Where:
- is the target entity (e.g.,
user_1234). - is the exact timestamp when the event occurred (e.g.,
2026-10-31 14:30:00 UTC). - is the target label (e.g.,
fraud_flag = 1).
Let the historical feature update stream for that entity be:
Where is the feature vector computed at timestamp .
The Point-in-Time Invariant:
The feature vector assigned to training event must be the most recent feature state that occurred strictly prior to or at event time :
Feature Updates: [t=10:00: $100] ------------> [t=14:00: $250] -----------------------> [t=18:00: $900]
^ ^
Event: [Event: 14:30] |
| |
Point-in-Time Join: Uses $250 (CORRECT!) |
Naive Database Join: Uses $900 (CATASTROPHIC FUTURE LEAKAGE!) <------+
If leaks into the feature vector, the model learns a spurious correlation based on future information that will be absent during real-world inference.
3.2 Streaming Sliding-Window Aggregation Math
Real-time feature pipelines compute streaming windowed aggregates over time intervals :
In Apache Flink or streaming workers, maintaining state over continuous time windows requires Incremental Aggregation. For an associative and commutative aggregation function :
This maintains computation time per event rather than re-scanning historical event buffers.
3.3 Vector Index RAM Sizing Equation
In real-time retrieval pipelines, High-Dimensional Vector Embeddings reside in RAM for sub-millisecond search:
Let be the number of stored vectors (e.g., ). Let be the embedding dimension (e.g., for modern LLM embeddings). Let be the HNSW graph bi-directional links per node (e.g., ).
Applying Product Quantization (PQ) or Scalar Quantization (SQ8) compresses FP32 vectors down to 1 byte per dimension, reducing RAM requirements from to with drop in retrieval accuracy.
4. Core Architectural Mechanics
4.1 Dual-Storage Synchronization Pipeline
+---------------------------------------+
| Streaming Kafka Events |
+---------------------------------------+
| |
v v
+-------------------------------+ +-------------------------------+
| Flink Real-Time Aggregator | | S3 / Lakehouse Ingestion |
+-------------------------------+ +-------------------------------+
| |
v v
+-------------------------------+ +-------------------------------+
| ONLINE STORE (Redis) | | OFFLINE STORE (Parquet) |
| Latest Features (< 2ms) | | Historical Log (Time-Travel) |
+-------------------------------+ +-------------------------------+
^ ^
| |
Live Inference Serving Model Training Pipelines
- Continuous Streaming Ingestion: Kafka topics stream live operational events (clicks, transactions). Apache Flink maintains in-memory sliding windows (e.g., 5-minute transaction count) and pushes updates directly to Redis in .
- Batch Materialization: Complex offline batch aggregations (e.g., 90-day customer affinity scores) computed in Apache Spark are periodically materialized into the online Redis store via high-throughput bulk loaders.
4.2 Dynamic GPU Batching for Real-Time Embeddings
Generating transformer embeddings on GPUs introduces an architectural tension between throughput and latency:
- Processing 1 text string per GPU kernel invocation achieves latency but wastes of GPU Tensor Core compute capacity.
- Waiting for 256 items to accumulate maximizes GPU throughput but degrades tail latency to .
Production Dynamic Batcher Solution:
A high-concurrency microservice maintains an adaptive microsecond queue:
- Condition 1 (Batch Full): As soon as 32 text items accumulate, trigger immediate GPU execution.
- Condition 2 (Time Ceiling): If fewer than 32 items arrive, trigger GPU execution as soon as elapses.
This achieves optimal GPU saturation while enforcing a strict p99 SLA.
5. Concrete Production Implementation
Below is a complete, production-grade TypeScript implementation demonstrating:
- An AI Feature Store Registry managing dual Online and Offline storage.
- A mathematically rigorous Point-in-Time (ASOF) Join engine preventing future data leakage.
- A Streaming Vector Ingestion Pipeline supporting real-time cosine distance updates and tombstone purging.
/**
* AI Feature Store & Real-Time Vector Pipeline Engine
* Demonstrates:
* - Dual-Storage Architecture (Online Key-Value Cache vs Offline Historical Log)
* - Point-in-Time (Time-Travel) Join Algorithm
* - Streaming Vector Pipeline with Cosine Distance & Tombstones
*/
export interface FeatureRecord {
entityId: string;
timestamp: number;
features: Record<string, number | string>;
}
export interface TrainingEvent {
eventId: string;
entityId: string;
timestamp: number;
label: number;
}
/**
* AI Feature Store Dual-Storage Engine
*/
export class FeatureStore {
private onlineStore: Map<string, Record<string, number | string>> = new Map();
private offlineStore: FeatureRecord[] = [];
/**
* Ingest a streaming feature update
*/
public ingest(record: FeatureRecord): void {
// 1. Update Offline Store (Append-only historical log)
this.offlineStore.push(record);
// 2. Update Online Store (Latest state only)
const existing = this.onlineStore.get(record.entityId) || {};
this.onlineStore.set(record.entityId, { ...existing, ...record.features });
}
/**
* Online Serving: Ultra-low latency point lookup for live model inference (<2ms)
*/
public getOnlineFeatures(entityId: string): Record<string, number | string> | null {
return this.onlineStore.get(entityId) || null;
}
/**
* Offline Training: Point-in-Time (ASOF) Time-Travel Join
* Mathematically eliminates Future Data Leakage!
*/
public pointInTimeJoin(
events: TrainingEvent[],
featureKeys: string[]
): Array<TrainingEvent & { features: Record<string, number | string> }> {
// Sort historical records chronologically
const sortedHistory = [...this.offlineStore].sort((a, b) => a.timestamp - b.timestamp);
const trainingDataset: Array<TrainingEvent & { features: Record<string, number | string> }> = [];
for (const ev of events) {
// Find latest feature update strictly on or before ev.timestamp (t <= T_event)
let bestRecord: FeatureRecord | null = null;
for (const hist of sortedHistory) {
if (hist.entityId === ev.entityId && hist.timestamp <= ev.timestamp) {
bestRecord = hist;
} else if (hist.timestamp > ev.timestamp) {
break; // Stop scanning: future updates forbidden!
}
}
const extractedFeatures: Record<string, number | string> = {};
for (const k of featureKeys) {
extractedFeatures[k] = bestRecord ? (bestRecord.features[k] ?? 0) : 0;
}
trainingDataset.push({
...ev,
features: extractedFeatures,
});
}
return trainingDataset;
}
}
/**
* Streaming Vector Pipeline & HNSW Mutation Simulator
*/
export interface VectorEntity {
id: string;
vector: number[];
isTombstone: boolean;
updatedAt: number;
}
export class StreamingVectorPipeline {
private vectorIndex: Map<string, VectorEntity> = new Map();
public static cosineSimilarity(a: number[], b: number[]): number {
let dot = 0;
let normA = 0;
let normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1e-9);
}
/**
* Stream a newly computed embedding vector into the active index
*/
public upsertVector(id: string, vector: number[]): void {
this.vectorIndex.set(id, {
id,
vector,
isTombstone: false,
updatedAt: Date.now(),
});
}
/**
* Soft-delete: Mark vector as tombstone to prevent graph corruption
*/
public deleteVector(id: string): void {
const existing = this.vectorIndex.get(id);
if (existing) {
existing.isTombstone = true;
}
}
/**
* Approximate Nearest Neighbor Search (skipping tombstones)
*/
public searchKnn(queryVector: number[], topK = 5): Array<{ id: string; score: number }> {
const results: Array<{ id: string; score: number }> = [];
for (const entity of this.vectorIndex.values()) {
if (entity.isTombstone) continue; // Skip soft-deleted vectors
const score = StreamingVectorPipeline.cosineSimilarity(queryVector, entity.vector);
results.push({ id: entity.id, score });
}
results.sort((a, b) => b.score - a.score);
return results.slice(0, topK);
}
/**
* Background Compaction: Purge tombstones and reclaim memory
*/
public compact(): { purgedCount: number; remainingCount: number } {
let purgedCount = 0;
for (const [id, entity] of this.vectorIndex.entries()) {
if (entity.isTombstone) {
this.vectorIndex.delete(id);
purgedCount++;
}
}
return {
purgedCount,
remainingCount: this.vectorIndex.size,
};
}
}
function runDemo(): void {
console.log("=== Streaming Feature Store & Vector Pipeline ===");
const pipeline = new StreamingVectorPipeline();
pipeline.upsertVector("user-101", [0.85, 0.12, 0.33, 0.05]);
pipeline.upsertVector("user-102", [0.10, 0.90, 0.40, 0.02]);
pipeline.upsertVector("user-103", [0.82, 0.15, 0.30, 0.08]);
console.log(`Ingested 3 user embedding vectors into real-time pipeline`);
const results = pipeline.searchKnn([0.84, 0.13, 0.32, 0.06], 2);
console.log(`Top-2 Cosine Similarities for query near user-101/103:`);
for (const r of results) {
console.log(` Entity [${r.id}]: score = ${r.score.toFixed(4)}`);
}
}
runDemo();
6. Real-World Failure Modes, Edge Cases & Operational War Stories
War Story 1: The $40M Fraud Data Leakage Catastrophe
Incident:
A tier-1 payment processor deployed an automated machine learning fraud model.
During offline validation, the model achieved a staggering 99.4% ROC-AUC score.
Within 48 hours of production deployment, fraudulent transactions surged by 400%, costing \$40 million in losses.
Root Cause:
The training pipeline used a naive SQL join:
SELECT t.*, u.total_confirmed_fraud_events
FROM transactions t
JOIN users u ON t.user_id = u.user_id;
The column `total_confirmed_fraud_events` was taken from the LIVE user profile table at the time the training
script was run (weeks after the transactions occurred!).
If a transaction was fraudulent, the fraud investigation completed 3 days later, incrementing the counter.
The model simply learned: IF total_confirmed_fraud_events >= 1 THEN FRAUD.
In live production, at the moment a fraudster initiates a transaction, the fraud investigation has NOT happened yet,
so the counter is 0! The model classified all fraud as legitimate!
Remediation:
Mandated Feature Store Point-in-Time (ASOF) joins across all ML teams. Training pipelines can only query
features with timestamp <= transaction_time.
War Story 2: Redis Online Feature Store Out-of-Memory Cascade
Incident:
A ride-sharing platform configured their online feature store in Redis to serve driver-rider matching.
On a rainy Friday evening, the primary Redis cluster abruptly crashed with `OOM command not allowed when used memory > 'maxmemory'`.
The backup replicas also crashed upon failover, taking down the entire dispatch system.
Root Cause:
Feature definitions for `driver_recent_geohashes` accumulated unbounded lists of GPS coordinate records.
Furthermore, keys lacked an explicit TTL (Time-To-Live). Over 18 months, 400 million inactive guest users
and historical coordinates accumulated in Redis RAM, consuming 256 GB of memory until the cluster collapsed.
Remediation:
1. Enforced mandatory TTLs (e.g., 14 days) on all online feature definitions.
2. Migrated long-tail features from Redis RAM to SSD-backed key-value stores (RocksDB / DynamoDB).
War Story 3: Stale Vector Embeddings in Customer Support RAG Agent
Incident:
An airline deployed an AI customer service agent powered by RAG to answer passenger flight policies.
During a blizzard, the airline updated its cancellation policy to offer free refunds.
Despite updating the CMS, the AI agent spent 36 hours stubbornly telling stranded passengers that tickets
were strictly non-refundable, triggering viral customer outrage.
Root Cause:
The vector ingestion pipeline was designed as a nightly batch job running at 03:00 AM UTC.
When documents were edited in the CMS, no event was emitted to trigger immediate re-indexing.
The agent retrieved stale vector embeddings from the previous night's index.
Remediation:
Migrated the RAG pipeline to an Event-Driven Streaming Vector Architecture:
CMS publishes document mutations to Kafka; GPU microservices generate embeddings and mutate the live
sharded vector database within 5 seconds of publication.
7. Benchmarks, Capacity Planning & Sizing Math
7.1 Feature Store Serving Latency Spectrum
+---------------------------------------------------------------------------------------------------+
| FEATURE STORE SERVING LATENCY BENCHMARK |
+--------------------------+---------------------+-------------------+------------------------------+
| Access Layer | Read Latency (p99) | Max Throughput | Storage Media |
+--------------------------+---------------------+-------------------+------------------------------+
| In-Memory Cache (Redis) | 0.8 - 1.8 ms | 100,000+ QPS/node | DRAM |
| Key-Value SSD (Cassandra)| 2.5 - 6.0 ms | 40,000 QPS/node | NVMe SSD |
| Relational DB (Postgres) | 8.0 - 25.0 ms | 5,000 QPS/node | SSD Buffer Pool |
| Data Lakehouse (Parquet) | 15.0 - 60.0 seconds | High throughput | Object Storage (S3 / GCS) |
| Analytical Warehouse | 2.0 - 15.0 seconds | Batch scans | Columnar Cloud Warehouse |
+--------------------------+---------------------+-------------------+------------------------------+
7.2 GPU Embedding Worker Sizing Math
If a platform ingests new text documents per second: Using an embedding model with average forward-pass latency on NVIDIA A10G at batch size :
Provisioning GPUs (incorporating redundancy) guarantees sustained sub-second vector ingestion SLAs.
8. Comparative Trade-off Matrix
+---------------------------------------------------------------------------------------------------+
| AI DATA LAYER COMPARISON |
+----------------------+--------------------+--------------------+----------------------------------+
| System Type | Read Latency | Historical Auditing| Best Use Case |
+----------------------+--------------------+--------------------+----------------------------------+
| Feature Store | Dual: <2ms online, | Native (ASOF | Machine learning model training |
| (Feast / Tecton) | Batch offline | Time-Travel joins) | and real-time inference features |
+----------------------+--------------------+--------------------+----------------------------------+
| Vector Database | 5 - 25 ms | Typically latest | Semantic search, RAG retrieval, |
| (Milvus / Pinecone) | (k-NN graph search)| state only | clustering, recommendation embeddings|
+----------------------+--------------------+--------------------+----------------------------------+
| Streaming Processor | Streaming state | Sliding window | Continuous real-time windowed |
| (Apache Flink) | buffer in memory | states only | aggregations (clicks, spend) |
+----------------------+--------------------+--------------------+----------------------------------+
| Relational Database | 5 - 50 ms | Slow (Requires | Relational transactions, user |
| (PostgreSQL) | (Index lookup) | temporal tables) | accounts, order billing |
+----------------------+--------------------+--------------------+----------------------------------+
9. Verification, Testing & Failure Injection
9.1 Synthetic Validation Pipeline
- Automated Time-Travel Leakage Verification: Inject synthetic training events paired with randomized future feature updates. Assert that
pointInTimeJoinoutput strictly reflects historical states with zero future values. - Online-Offline Drift Test: Compare the mathematical distribution of feature values between the online Redis store and the offline Parquet store using Kolmogorov-Smirnov statistical tests. Trigger alerts if drift exceeds .
- Vector Tombstone Fragmentation Audit: Inject 100,000 vector upserts followed by 50,000 deletions. Verify that vector recall remains above and run background compaction to reclaim allocated RAM.
10. Key Takeaways & Best Practices Checklist
+---------------------------------------------------------------------------------------------------+
| FEATURE STORE & VECTOR CHECKLIST |
+---------------------------------------------------------------------------------------------------+
| [x] Eliminate Training-Serving Skew by defining feature transformation logic once in a central |
| declarative feature registry. |
| [x] Enforce Point-in-Time (Time-Travel / ASOF) joins for all model training datasets to mathematically|
| prevent future data leakage and spurious correlations. |
| [x] Deploy Dual-Storage architectures: Low-latency in-memory caches for live inference; append-only|
| columnar lakehouses for historical batch training. |
| [x] Configure explicit TTLs on all online feature keys to prevent catastrophic Redis OOM crashes. |
| [x] Use dynamic GPU batching on embedding workers to maximize Tensor Core occupancy without |
| violating real-time streaming ingestion SLAs. |
| [x] Regularly compact mutable HNSW vector indices to purge deleted tombstones and repair routing. |
+---------------------------------------------------------------------------------------------------+
11. Guided Design Exercises
Exercise 1 (Foundational — Dual Online/Offline Feature Store & Vector Index Sizing)
You are sizing a dual-storage feature store and streaming vector index for an e-commerce platform with registered users (only active within a 14-day TTL window) and catalog item vectors (, HNSW ).
- Each user entity stores float features ( serialized protobuf payload + Redis key/dict metadata ). Calculate the Redis Cluster DRAM required with and without a 14-day TTL policy (including Redis fragmentation/replication overhead).
- Calculate the item HNSW index RAM before and after applying Scalar Quantization (
SQ8, ) while keeping Layer-0 HNSW edges () uncompressed.
Exercise 2 (Intermediate — Point-in-Time ASOF Join & Dynamic GPU Embedding Batcher)
- Given a fraud training observation and historical feature log entries for
'u_42'at(10:00, $100),(14:00, $250),(14:30, $310), and(18:00, $900), state the exact feature value selected by a Point-in-Time join and write the SQLASOF JOIN(orQUALIFY ROW_NUMBER()) query that prevents future data leakage. - A Kafka topic streams to NVIDIA A10G embedding workers. At batch size , one GPU forward pass takes . Calculate the minimum GPU count for target utilization and the maximum dynamic batching wait window to satisfy a embedding SLA.
Exercise 3 (Staff-Level — Online-Offline Skew & Tombstone Compaction Runbook)
Following a Kafka consumer rebalance and a flash-sale catalog purge of discontinued items, production alerts fire simultaneously: (a) the Kolmogorov-Smirnov (KS) drift statistic between online Redis features and offline Parquet features jumps to , and (b) vector search latency spikes from to . Formulate the root-cause diagnosis, online-offline reconciliation backfill, and HNSW tombstone compaction remediation.
View Reference Architecture & Worked Solutions (AI-C07-001)
1. Worked Solution — Exercise 1: Dual Feature Store & Vector Index Sizing
- Online Redis Feature Store Memory (, overhead):
- Without TTL ( total users):
- With 14-Day TTL ( active users):
- HNSW Vector Index Memory ():
- Uncompressed FP32: Raw vectors ; Layer-0 edges .
- Scalar Quantized (
SQ8): Quantized vectors ; Layer-0 edges ( / RAM saved).
2. Worked Solution — Exercise 2: Point-in-Time ASOF Join & GPU Batcher Sizing
- Point-in-Time Feature Selection & SQL Query:
- For , the condition matches
(10:00, $100),(14:00, $250), and(14:30, $310). The maximum timestamp is14:30, yielding$310while strictly excluding(18:00, $900).
SELECT e.event_id, e.entity_id, e.event_ts, e.label, f.rolling_spend_24h FROM training_events e LEFT JOIN feature_history_log f ON e.entity_id = f.entity_id AND f.feature_ts <= e.event_ts QUALIFY ROW_NUMBER() OVER ( PARTITION BY e.event_id ORDER BY f.feature_ts DESC ) = 1; - For , the condition matches
- Dynamic GPU Embedding Batcher Sizing ():
- Single-GPU max throughput: .
- Minimum GPUs at utilization:
- Maximum batching queue timeout for (allowing network + tokenization overhead):
3. Worked Solution — Exercise 3: Online-Offline Skew & Tombstone Remediation
- Online-Offline Skew Recovery:
- Root Cause: If the Flink job restarted without restoring its RocksDB checkpoint, sliding-window counters reset to zero in Redis while offline Parquet retained complete history (causing KS drift ).
- Remediation: Configure Flink
ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATIONon S3, and run a deterministic Spark/DuckDB materialization backfill (feast materialize-incremental) from the offline Parquet log to overwrite corrupted keys in Redis using monotonic timestamp compare-and-set (HSETonly ifincoming_ts >= stored_ts).
- HNSW Tombstone Compaction:
- Root Cause: Deleting of items ( tombstones) forces HNSW beam search to traverse dead bridge nodes, inflating distance evaluations by and causing tail-latency spikes.
- Remediation: Trigger rolling background segment compaction across shards (throttled via I/O cgroups to CPU cores per node) to rebuild sealed HNSW segments with only live vectors and atomically swap segment pointers.
12. Authoritative References & Production Standards
- Yu A. Malkov and D. A. Yashunin (2018), “Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs”, IEEE TPAMI — doi.org/10.1109/TPAMI.2018.2889473
- Feast: The Open Source Feature Store for Machine Learning Documentation — docs.feast.dev
- Hopsworks Feature Store Architecture Guide — docs.hopsworks.ai/latest/
- Version Context: Architecture aligns with Feast 0.38+ with Redis 7.2+ online key-value backends and Apache Spark 3.5+ offline historical feature retrieval.