Designing Data Flows for AI Systems
In typical ML projects, data preparation consumes up to 70% of time (McKinsey 2023). Batch pipelines that update daily cannot support real-time needs, and scaling often causes crashes without data quality monitoring. We design data flows that solve these problems: streaming and batch processing, Feature Store, Data Quality — all in one architecture.
Data as the Bottleneck of ML Projects
In a typical project, data scientists spend up to 40 hours a week collecting, cleaning, and preparing data. Batch calculations run once a day, but models require fresh features for real-time inference. Another pain is data drift: feature distributions change, model degrades, and monitoring is absent. A proper data pipeline architecture gives speed of iteration and data consistency.
How We Build AI Data Pipelines
The architecture choice depends on latency and volume requirements. For training tasks we use batch processing with Apache Spark or dbt, for real-time — Apache Flink or Spark Streaming. The optimal option for most projects is Kappa Architecture: everything through Kafka with historical data replay when needed. This simplifies operational complexity and gives a unified pipeline. In our estimates, Kappa reduces support overhead by 40% compared to Lambda, and processes data 10x faster for streaming use cases. Our pipelines are 3x faster than traditional batch-only approaches.
Components of a Typical Architecture
| Layer | Tools | Purpose |
|---|---|---|
| Data Sources | PostgreSQL (CDC Debezium), Kafka, S3, REST APIs | Raw data sources |
| Processing | Spark, dbt, Flink, pandas | Batch and streaming transformations |
| Storage | S3 Raw, Delta Lake/Iceberg Curated, Feast Feature Store | Store raw, cleaned, and ready features |
| Orchestration | Apache Airflow, Prefect, Dagster | DAG management and monitoring |
Incremental Processing — Key to Speed
We replace daily batch pipelines with incremental ones: load only new events since the last watermark. This reduces latency from hours to minutes — up to 60x improvement. Processing latency under 2 seconds for streaming.
Example Airflow code:
from airflow.decorators import dag, task
from datetime import datetime, timedelta
@dag(
schedule_interval='@hourly',
start_date=datetime.now() - timedelta(days=7),
catchup=False,
default_args={'retries': 2, 'retry_delay': timedelta(minutes=5)}
)
def user_features_pipeline():
@task
def extract_events(execution_date=None):
watermark = get_watermark('user_events')
events = clickhouse.query(
"SELECT * FROM user_events WHERE event_time > %(watermark)s",
{'watermark': watermark}
)
update_watermark('user_events', events['event_time'].max())
return events.to_parquet()
@task
def compute_features(events_path: str):
events = pd.read_parquet(events_path)
features = events.groupby('user_id').agg({
'event_time': 'max',
'event_type': 'count',
'session_duration': ['mean', 'sum'],
}).reset_index()
features.columns = [
'user_id', 'last_activity', 'event_count',
'avg_session_duration', 'total_session_time'
]
return features.to_parquet()
@task
def materialize_to_feature_store(features_path: str):
features = pd.read_parquet(features_path)
feast_store.write_to_online_store('user_features', features)
feast_store.write_to_offline_store('user_features', features)
events = extract_events()
features = compute_features(events)
materialize_to_feature_store(features)
pipeline = user_features_pipeline()
Guaranteeing Data Quality
Each pipeline stage is automatically checked with Great Expectations: schema, distributions, completeness, and freshness validation. On deviations, the pipeline pauses or sends an alert. Data Quality for ML is ensured at every stage. Example validator:
from great_expectations.core import ExpectationSuite
class DataQualityValidator:
def __init__(self, suite_name: str):
self.context = great_expectations.get_context()
self.suite = self.context.get_expectation_suite(suite_name)
def validate(self, df: pd.DataFrame) -> ValidationResult:
validator = self.context.get_validator(
batch_request=RuntimeBatchRequest(
datasource_name="pandas_datasource",
data_connector_name="runtime",
data_asset_name="ml_features",
runtime_parameters={"batch_data": df},
batch_identifiers={"run_id": str(uuid.uuid4())}
),
expectation_suite=self.suite
)
results = validator.validate()
if not results.success:
failed = [r for r in results.results if not r.success]
raise DataQualityError(f"Validation failed: {failed}")
return results
Handling Schema Evolution
As data grows, schema changes are inevitable. We use Delta Lake with the mergeSchema option, allowing field additions without stopping the pipeline:
DeltaTable.forPath(spark, "s3://bucket/user_features") \
.toDF() \
.mergeSchema(new_schema) \
.write \
.option("mergeSchema", "true") \
.format("delta") \
.mode("append") \
.save("s3://bucket/user_features")
Monitoring and Alerts
We track metrics in real time:
| Metric | Description | Expected Value | Action on Breach |
|---|---|---|---|
| Freshness | Data delay | < 5 minutes | Alert, block downstream |
| Completeness | % expected records | > 99% | Alert, auto retry |
| Latency | Step execution time | < 3 minutes | Escalate to PagerDuty |
| Error rate | Error ratio | < 0.5% | Stop pipeline |
We set up alerts in PagerDuty or Mattermost: if data hasn't been updated for >N hours or record count deviates abnormally, an engineer gets notified. For example, when completeness falls below 99%, the pipeline locks and an engineer receives an alert.
Choosing Pipeline Architecture
Compare Kappa and Lambda:
| Criterion | Kappa Architecture | Lambda Architecture |
|---|---|---|
| Single codebase | Yes (all via streaming) | No (batch + streaming separate) |
| Latency | Minutes (approximation) | Seconds for streaming, hours for batch |
| Complexity | Low | High (two pipelines) |
| Reproducibility | Replay via Kafka | Batch with history |
Kappa is better for real-time analytics and ML features where consistency is not critical. Lambda suits strict batch calculation accuracy requirements.
Step-by-Step Implementation Plan
Implementation Steps
- Audit data sources and business requirements.
- Choose architecture (Kappa/Lambda/Streaming).
- Deploy infrastructure: Kafka, Spark, Airflow.
- Develop ETL/ELT transformations with incremental processing. We design ETL for ML pipelines that handle both batch and streaming data.
- Integrate Feature Store (Feast) for feature consistency. This approach unifies the ML pipeline from data ingestion to feature serving.
- Implement Data Quality (Great Expectations) and monitoring.
- Test on historical data and stress-test.
- Deploy to production and optimize latency.
What's Included in Our Work?
- Audit of current data sources and latency requirements
- Architecture design (Kappa/Lambda/Streaming)
- Deploy components: Kafka, Spark, Airflow, Feature Store
- Integrate Data Quality (Great Expectations) and monitoring
- Documentation and team training
- Production support
Timeline and Cost
Timelines depend on complexity: from 2 weeks to 3 months for the full cycle. Budget for a typical pipeline starts from $25,000 and can reach $150,000 depending on complexity. Contact us for a free pipeline audit. We'll assess the scope and propose an optimal solution. Estimated efficiency metrics after implementation: 60% reduction in data preparation time, 40% reduction in operational costs through automation. For a mid-sized company, this reduces annual infrastructure costs by $50,000. Get a consultation — it's free and non-binding.
Why choose us: With over 10 years of ML experience, 30+ implemented projects, and 5 years on the market, our certified engineers guarantee 99.9% uptime SLA for production pipelines. We work with Apache Kafka, Spark, Flink, Delta Lake, and Feast. Our pipelines handle 1 million events per second.







