This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@@ -186,6 +186,12 @@ Captures materialization run metadata:
## Lineage Visualization
### Option 1: Feast UI (Built-in)
Feast includes a built-in OpenLineage consumer that can receive, store, and visualize lineage from **all** OpenLineage producers (Airflow, Spark, dbt, Feast itself, etc.) directly in the Feast UI. See the [OpenLineage Consumer](#openlineage-consumer) section below.
### Option 2: Marquez
Use [Marquez](https://marquezproject.ai/) to visualize your Feast lineage:
```bash
Expand Down
Expand Up
@@ -216,3 +222,257 @@ Then access the Marquez UI at http://localhost:3000 to see your feature lineage.
Feast can act as an **OpenLineage consumer**, receiving lineage events from any OpenLineage-compatible producer and displaying them in the Feast UI. This eliminates the need for a separate Marquez deployment when you want to visualize cross-system data lineage alongside your feature store.
### Consumer Architecture
```
Producers (Airflow, Spark, dbt, Feast, Flink, …)
│
▼
POST /api/v1/lineage ──→ Event Processor ──→ Lineage Store (SQL)
│
▼
Feast UI
┌──────────────────────────┐
│ Lineage tab │
│ ├─ OpenLineage Graph │
│ │ (all producers) │
│ └─ ☐ Feast Only Lineage │
│ (registry view) │
│ │
│ Events tab │
│ └─ Event browser │
└──────────────────────────┘
```
When the consumer is **not** enabled, the Feast UI shows only the original registry-based lineage view — no tabs are added.
### Enabling the Consumer
Add the `consumer` section under `openlineage` in your `feature_store.yaml`:
| `consumer.enabled` | `false` | Enable the OpenLineage consumer |
| `consumer.store_type` | `sql` | Storage backend type. Currently only `sql` is supported |
| `consumer.connection_string` | - | Optional separate database connection string. If omitted, reuses the SQL registry database |
| `consumer.api_key` | - | API key that producers must provide when sending events |
| `consumer.namespace_mapping` | `{}` | Maps OpenLineage namespaces to Feast projects for RBAC scoping |
### Consumer API Endpoints
When the consumer is enabled, the following endpoints are available on the Feast REST registry server:
#### Event Receiver (Producer-facing)
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/lineage` | `POST` | Receive a single OpenLineage event (or array of events) |
| `/api/v1/lineage/batch` | `POST` | Receive a batch of OpenLineage events |
Both endpoints require the `X-API-Key` header (or `Authorization: Bearer <key>`) if `consumer.api_key` is configured.
#### Admin Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/lineage/openlineage/reset` | `DELETE` | Purge all OpenLineage data. Accepts optional `?namespace=X` to delete only a specific namespace. Requires API key. |
#### OpenLineage Query Endpoints (UI-facing)
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/lineage/openlineage/graph` | `GET` | Full lineage graph with all nodes, edges, and symlinks |
| `/lineage/openlineage/graph/{node_type}/{namespace}/{name}` | `GET` | Lineage graph centered on a specific node |
When both the OpenLineage producer and consumer are enabled, Feast's own events (from `feast apply`, materialization, etc.) are automatically ingested into the local consumer store — no HTTP transport is needed.
```yaml
# In feature_store.yaml
openlineage:
enabled: true
namespace: my_project
consumer:
enabled: true
api_key: change-me # pragma: allowlist secret
```
### Feast UI Lineage Views
When the consumer is enabled, the lineage page in the Feast UI shows two tabs:
**Lineage tab**
- **OpenLineage Graph** (default) — shows lineage from all OpenLineage producers with cross-producer connectivity. Nodes are color-coded by producer (colors generated dynamically). The graph supports filtering by type, producer, and object name. Clicking a node opens a **detail panel** showing description, schema, tags, features, entities, data quality metrics, data source info, other facets, and **run history** (for job nodes — see [Per-Run Lineage](#per-run-lineage-run-history)).
- **Feast Only Lineage** (checkbox) — switches to the original Feast registry view (DataSource → FeatureView → FeatureService) powered entirely by the Feast registry.
**Events tab**
- Browse individual OpenLineage events with filtering by event type, job name, and run ID. Expand any event to inspect the full JSON payload.
### Cross-Producer Lineage Connectivity
The consumer automatically links datasets across different producers when they refer to the same physical data. Linking mechanisms:
1. **Shared namespace + name** — If Airflow writes to `s3://bucket/path` and Spark reads from the same `s3://bucket/path`, the graph connects them automatically.
2. **SymlinksDatasetFacet** — Producers can declare aliases. For example, Feast can declare that its internal `driver_hourly_stats` is a symlink to the Spark output at `s3://bucket/features/driver_hourly_stats/`.
3. **dataSource URI matching** — Datasets with matching `dataSource.uri` facets are linked even if their namespace or name differ.
Compatible producers include Airflow, Spark, dbt, Flink, Feast, Dagster, and Great Expectations.
### RBAC for Lineage
The OpenLineage consumer integrates with Feast's existing RBAC:
- **Write access** (producers sending events): Authenticated via API key in the `X-API-Key` header
- **Read access** (UI viewing lineage): Namespace-based filtering maps OpenLineage namespaces to Feast projects. Users see only lineage data for namespaces they have access to via the `namespace_mapping` configuration
### Lineage Cleanup / Reset
Over time the OpenLineage store accumulates historical data. Two mechanisms are provided for cleanup:
#### Admin Reset Endpoint
Use the `DELETE /lineage/openlineage/reset` endpoint to purge lineage data. The endpoint requires the same API key used for event ingestion.
A full purge deletes data from all seven `openlineage_*` tables. A namespace-scoped purge deletes jobs, datasets, runs, events, edges, and symlinks associated with that namespace, leaving other namespaces intact.
#### Feast Teardown Hook
When you run `feast teardown`, Feast automatically cleans up OpenLineage data for the project's namespace (if the consumer is configured). This ensures that tearing down a Feast project doesn't leave orphaned lineage data behind.
```bash
# Tears down the Feast project AND its OpenLineage lineage
feast teardown
```
### Per-Run Lineage (Run History)
The consumer tracks individual pipeline runs in the `openlineage_runs` table. When you click on a **job node** in the OpenLineage Graph, the detail panel shows a **Run History** section with:
- A table of past runs: truncated run ID, status badge (COMPLETE, FAIL, RUNNING, ABORT), start time, and duration
- Click any run to expand its **inputs and outputs** — the specific datasets that run consumed and produced
The run detail response includes `inputs` and `outputs` arrays, each containing the dataset namespace, name, and any I/O facets recorded by the producer.
### Database Schema
The consumer creates the following tables (automatically on first startup):
| Table | Purpose |
|-------|---------|
| `openlineage_events` | Raw event storage with JSON payloads |
| `openlineage_jobs` | Deduplicated job records with producer, description, and facets |
| `openlineage_datasets` | Deduplicated dataset records with schema, facets, and Feast mapping |
| `openlineage_runs` | Run lifecycle tracking (START/COMPLETE/FAIL) |
| `openlineage_run_io` | Input/output relationships between runs and datasets |
| `openlineage_dataset_symlinks` | Cross-producer dataset linking via `SymlinksDatasetFacet` and `dataSource` URI matching |
By default these tables are created in the **same database** as the SQL registry (hybrid storage). Set `consumer.connection_string` to store them in a separate database instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: Add OpenLineage Consumer to Feast - receive, store, and visualize cross-producer lineage #6549
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
feat: Add OpenLineage Consumer to Feast - receive, store, and visualize cross-producer lineage #6549
Filter by extension
Only manifest files
Viewed files
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.