Visitar URL original
Merge branch 'master' into feature/spark-bfv-compute-on-read · feast-dev/feast@fcdf0e6 · GitHub
Skip to content

Commit fcdf0e6

Browse files
authored
Merge branch 'master' into feature/spark-bfv-compute-on-read
2 parents c14a183 + 3eccc2e commit fcdf0e6

9 files changed

Lines changed: 234 additions & 9 deletions

File tree

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ The list below contains the functionality that contributors are planning to deve
185185
* [x] [Athena (contrib plugin)](https://docs.feast.dev/reference/data-sources/athena)
186186
* [x] [Clickhouse (contrib plugin)](https://docs.feast.dev/reference/data-sources/clickhouse)
187187
* [x] [Oracle (contrib plugin)](https://docs.feast.dev/reference/data-sources/oracle)
188+
* [x] [MongoDB (contrib plugin)](https://docs.feast.dev/reference/data-sources/mongodb)
188189
* [x] [Ray source (contrib plugin)](https://docs.feast.dev/reference/data-sources/ray)
189190
* [x] Kafka / Kinesis sources (via [push support into the online store](https://docs.feast.dev/reference/data-sources/push))
190191
* **Offline Stores**
@@ -204,6 +205,7 @@ The list below contains the functionality that contributors are planning to deve
204205
* [x] [Clickhouse (contrib plugin)](https://docs.feast.dev/reference/offline-stores/clickhouse)
205206
* [x] [Ray (contrib plugin)](https://docs.feast.dev/reference/offline-stores/ray)
206207
* [x] [Oracle (contrib plugin)](https://docs.feast.dev/reference/offline-stores/oracle)
208+
* [x] [MongoDB (contrib plugin)](https://docs.feast.dev/reference/offline-stores/mongodb)
207209
* [x] [Hybrid](https://docs.feast.dev/reference/offline-stores/hybrid)
208210
* [x] [Custom offline store support](https://docs.feast.dev/how-to-guides/customizing-feast/adding-a-new-offline-store)
209211
* **Online Stores**

‎docs/SUMMARY.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
* [Athena (contrib)](reference/data-sources/athena.md)
114114
* [Clickhouse (contrib)](reference/data-sources/clickhouse.md)
115115
* [Ray (contrib)](reference/data-sources/ray.md)
116+
* [MongoDB (contrib)](reference/data-sources/mongodb.md)
116117
* [Offline stores](reference/offline-stores/README.md)
117118
* [Overview](reference/offline-stores/overview.md)
118119
* [Dask](reference/offline-stores/dask.md)
@@ -129,6 +130,7 @@
129130
* [Ray (contrib)](reference/offline-stores/ray.md)
130131
* [Oracle (contrib)](reference/offline-stores/oracle.md)
131132
* [Athena (contrib)](reference/offline-stores/athena.md)
133+
* [MongoDB (contrib)](reference/offline-stores/mongodb.md)
132134
* [Remote Offline](reference/offline-stores/remote-offline-store.md)
133135
* [Hybrid](reference/offline-stores/hybrid.md)
134136
* [Online stores](reference/online-stores/README.md)

‎docs/reference/data-sources/README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,7 @@ Please see [Data Source](../../getting-started/concepts/data-ingestion.md) for a
6969
{% content-ref url="ray.md" %}
7070
[ray.md](ray.md)
7171
{% endcontent-ref %}
72+
73+
{% content-ref url="mongodb.md" %}
74+
[mongodb.md](mongodb.md)
75+
{% endcontent-ref %}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# MongoDB source (contrib)
2+
3+
## Description
4+
5+
MongoDB data sources are [MongoDB](https://www.mongodb.com/) collections that can be used as a source for feature data. The `MongoDBSource` points at a MongoDB collection and provides the metadata Feast needs to read historical features from the offline store's collection.
6+
7+
## Examples
8+
9+
Defining a MongoDB source:
10+
11+
```python
12+
from feast.infra.offline_stores.contrib.mongodb_offline_store.mongodb import (
13+
MongoDBSource,
14+
)
15+
16+
driver_stats_source = MongoDBSource(
17+
name="driver_stats",
18+
timestamp_field="event_timestamp",
19+
created_timestamp_column="created_at",
20+
)
21+
```
22+
23+
The `name` field becomes the `feature_view` discriminator stored in every document in the `feature_history` collection.
24+
25+
Configuration options such as `connection_string`, `database`, and `collection` are inherited from the offline store configuration in `feature_store.yaml`.
26+
27+
The full set of configuration options is available [here](https://rtd.feast.dev/en/master/#feast.infra.offline_stores.contrib.mongodb_offline_store.mongodb.MongoDBSource).
28+
29+
## Vector Search
30+
31+
The MongoDB online store supports [Atlas Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/), enabling similarity search over feature embeddings stored in MongoDB Atlas. This is powered by the `$vectorSearch` aggregation stage and requires MongoDB Atlas (or the `mongodb/mongodb-atlas-local` Docker image for local development).
32+
33+
See [PR #6344](https://github.com/feast-dev/feast/pull/6344) for full implementation details.
34+
35+
### Configuration
36+
37+
Enable vector search in your `feature_store.yaml`:
38+
39+
```yaml
40+
project: my_project
41+
provider: local
42+
online_store:
43+
type: mongodb
44+
connection_string: mongodb+srv://<user>:<pass>@cluster.mongodb.net
45+
vector_enabled: true
46+
similarity: cosine # cosine | euclidean | dotProduct
47+
vector_index_wait_timeout: 60 # seconds to wait for index to become queryable
48+
vector_index_wait_poll_interval: 1.0 # seconds between polls
49+
```
50+
51+
### Defining a Feature View with Vector Index
52+
53+
Mark embedding fields with `vector_index=True` and specify `vector_length`:
54+
55+
```python
56+
from feast import Entity, FeatureView, Field, FileSource
57+
from feast.types import Array, Float32, Int64, String
58+
from datetime import timedelta
59+
60+
item_embeddings = FeatureView(
61+
name="item_embeddings",
62+
entities=[Entity(name="item_id", join_keys=["item_id"])],
63+
schema=[
64+
Field(
65+
name="embedding",
66+
dtype=Array(Float32),
67+
vector_index=True,
68+
vector_length=384,
69+
vector_search_metric="cosine",
70+
),
71+
Field(name="title", dtype=String),
72+
Field(name="item_id", dtype=Int64),
73+
],
74+
source=FileSource(path="items.parquet", timestamp_field="event_timestamp"),
75+
ttl=timedelta(hours=24),
76+
)
77+
```
78+
79+
When `feast apply` (or `store.update()`) runs with `vector_enabled=True`, Atlas vector search indexes are automatically created for any field with `vector_index=True`. Indexes are also automatically dropped when feature views are removed.
80+
81+
### Retrieving Documents via Vector Search
82+
83+
Use `retrieve_online_documents_v2()` to perform similarity search:
84+
85+
```python
86+
source = FeatureStore(repo_path=".")
87+
results = store.retrieve_online_documents_v2(
88+
config=repo_config,
89+
table=item_embeddings,
90+
requested_features=["embedding", "title"],
91+
embedding=[0.1, 0.2, ...], # query vector
92+
top_k=5,
93+
)
94+
95+
# Each result is a (event_timestamp, entity_key_proto, feature_dict) tuple.
96+
# feature_dict includes a synthetic "distance" key with the vector search score.
97+
for ts, entity_key, features in results:
98+
print(features["title"].string_val, features["distance"].float_val)
99+
```
100+
```
101+
102+
### How It Works
103+
104+
- **Index creation**: `update()` creates an Atlas vector search index named `<feature_view>__<field>__vs_index` for each vector-indexed field. It waits for the index to reach `READY` status before proceeding.
105+
- **Query execution**: `retrieve_online_documents_v2()` builds a `$vectorSearch` aggregation pipeline with `numCandidates = max(top_k * 10, 100)` and the specified `limit`.
106+
- **Score**: Results include a `distance` field populated from `$meta: "vectorSearchScore"`.
107+
- **BSON compatibility**: Query vectors are coerced to native Python floats to avoid numpy serialization issues.
108+
- **Idempotency**: Calling `update()` multiple times will not duplicate indexes.
109+
110+
## Supported Types
111+
112+
MongoDB data sources support all eight primitive types (`bytes`, `string`, `int32`, `int64`, `float32`, `float64`, `bool`, `timestamp`) and their corresponding array types. Complex types such as `Map` and `Struct` are preserved through the MongoDB document model.
113+
For a comparison against other batch data sources, please see [here](overview.md#functionality-matrix).

‎docs/reference/offline-stores/README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ Please see [Offline Store](../../getting-started/components/offline-store.md) fo
6262
[clickhouse.md](clickhouse.md)
6363
{% endcontent-ref %}
6464

65+
{% content-ref url="mongodb.md" %}
66+
[mongodb.md](mongodb.md)
67+
{% endcontent-ref %}
68+
6569
{% content-ref url="remote-offline-store.md" %}
6670
[remote-offline-store.md](remote-offline-store.md)
6771
{% endcontent-ref %}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# MongoDB offline store (contrib)
2+
3+
## Description
4+
5+
The MongoDB offline store provides support for reading [MongoDBSource](../data-sources/mongodb.md).
6+
* Uses a single shared collection with a compound index for all FeatureViews, distinguished by a `feature_view` discriminator field.
7+
* Entity dataframes can be provided as a Pandas dataframe. The offline store converts entity identifiers into serialized entity keys for efficient lookup against the collection.
8+
9+
## Getting started
10+
11+
In order to use this offline store, you'll need to run `pip install 'feast[mongodb]'`.
12+
13+
## Example
14+
15+
{% code title="feature_store.yaml" %}
16+
```yaml
17+
project: my_project
18+
registry: data/registry.db
19+
provider: local
20+
offline_store:
21+
type: feast.infra.offline_stores.contrib.mongodb_offline_store.mongodb.MongoDBOfflineStore
22+
connection_string: "mongodb+srv://user:pass@cluster.mongodb.net" # pragma: allowlist secret
23+
database: feast
24+
collection: feature_history
25+
online_store:
26+
type: mongodb
27+
connection_string: "mongodb+srv://user:pass@cluster.mongodb.net" # pragma: allowlist secret
28+
database_name: feast_online_store
29+
collection_suffix: latest
30+
client_kwargs: {}
31+
```
32+
{% endcode %}
33+
34+
The full set of configuration options is available in [MongoDBOfflineStoreConfig](https://rtd.feast.dev/en/master/#feast.infra.offline_stores.contrib.mongodb_offline_store.mongodb.MongoDBOfflineStoreConfig).
35+
36+
## Data Model
37+
38+
The offline store uses a single shared collection (by default `feature_history`) that stores append-only historical feature rows for all feature views. Each document represents one observation of one entity for one FeatureView at a specific event timestamp:
39+
40+
```json
41+
{
42+
"entity_id": "Binary(...)",
43+
"feature_view": "driver_stats",
44+
"event_timestamp": "ISODate(2024-01-15T12:00:00Z)",
45+
"created_at": "ISODate(2024-01-15T12:01:00Z)",
46+
"features": {
47+
"conv_rate": 0.72,
48+
"acc_rate": 0.91,
49+
"avg_daily_trips": 14
50+
}
51+
}
52+
```
53+
54+
Key properties:
55+
56+
* **Append-only**: Historical data is treated as immutable; corrections are written as new rows with newer `created_at` timestamps rather than in-place updates.
57+
* **Time-series friendly**: `event_timestamp` represents when the feature value was observed; `created_at` is used as a tie-breaker when multiple observations share the same event timestamp.
58+
* **Feature grouping by FeatureView**: `feature_view` identifies which FeatureView the row belongs to, so a single collection can host multiple FVs.
59+
60+
A single compound index supports all major query patterns:
61+
62+
```
63+
(entity_id ASC, feature_view ASC, event_timestamp DESC, created_at DESC)
64+
```
65+
66+
This index enables efficient range scans over entities and feature views, while ensuring that the most recent observation per `(entity_id, feature_view)` is seen first during aggregation. The index is created lazily on first use and cached per connection string.
67+
68+
## Key Optimizations
69+
70+
* **Scoring vs. training paths**: When each entity appears only once in `entity_df` (scoring/inference — one feature lookup per entity), server-side `$group $first` efficiently returns the single latest value per entity. When the same entity appears at multiple timestamps (training — building a dataset with many historical snapshots per entity), the store retrieves all candidate rows and uses `pd.merge_asof` to select the correct point-in-time value for each request timestamp.
71+
* **Two-level chunking**: `CHUNK_SIZE` (50,000 rows) controls the size of intermediate DataFrames in memory; `MONGO_BATCH_SIZE` (10,000 entity IDs) limits the query size sent to MongoDB.
72+
73+
## Functionality Matrix
74+
75+
The set of functionality supported by offline stores is described in detail [here](overview.md#functionality).
76+
Below is a matrix indicating which functionality is supported by the MongoDB offline store.
77+
78+
| | MongoDB |
79+
| :----------------------------------------------------------------- | :------ |
80+
| `get_historical_features` (point-in-time correct join) | yes |
81+
| `pull_latest_from_table_or_query` (retrieve latest feature values) | yes |
82+
| `pull_all_from_table_or_query` (retrieve a saved dataset) | yes |
83+
| `offline_write_batch` (persist dataframes to offline store) | yes |
84+
| `write_logged_features` (persist logged features to offline store) | no |
85+
86+
Below is a matrix indicating which functionality is supported by `MongoDBRetrievalJob`.
87+
88+
| | MongoDB |
89+
| ----------------------------------------------------- | ------- |
90+
| export to dataframe | yes |
91+
| export to arrow table | yes |
92+
| export to arrow batches | no |
93+
| export to SQL | no |
94+
| export to data lake (S3, GCS, etc.) | no |
95+
| export to data warehouse | no |
96+
| export as Spark dataframe | no |
97+
| local execution of Python-based on-demand transforms | yes |
98+
| remote execution of Python-based on-demand transforms | no |
99+
| persist results in the offline store | yes |
100+
| preview the query plan before execution | no |
101+
| read partitioned data | no |
102+
103+
To compare this set of functionality against other offline stores, please see the full [functionality matrix](overview.md#functionality-matrix).

‎docs/roadmap.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The list below contains the functionality that contributors are planning to deve
2020
* [x] [Athena (contrib plugin)](https://docs.feast.dev/reference/data-sources/athena)
2121
* [x] [Clickhouse (contrib plugin)](https://docs.feast.dev/reference/data-sources/clickhouse)
2222
* [x] [Oracle (contrib plugin)](https://docs.feast.dev/reference/data-sources/oracle)
23+
* [x] [MongoDB (contrib plugin)](https://docs.feast.dev/reference/data-sources/mongodb)
2324
* [x] [Ray source (contrib plugin)](https://docs.feast.dev/reference/data-sources/ray)
2425
* [x] Kafka / Kinesis sources (via [push support into the online store](https://docs.feast.dev/reference/data-sources/push))
2526
* **Offline Stores**
@@ -39,6 +40,7 @@ The list below contains the functionality that contributors are planning to deve
3940
* [x] [Clickhouse (contrib plugin)](https://docs.feast.dev/reference/offline-stores/clickhouse)
4041
* [x] [Ray (contrib plugin)](https://docs.feast.dev/reference/offline-stores/ray)
4142
* [x] [Oracle (contrib plugin)](https://docs.feast.dev/reference/offline-stores/oracle)
43+
* [x] [MongoDB (contrib plugin)](https://docs.feast.dev/reference/offline-stores/mongodb)
4244
* [x] [Hybrid](https://docs.feast.dev/reference/offline-stores/hybrid)
4345
* [x] [Custom offline store support](https://docs.feast.dev/how-to-guides/customizing-feast/adding-a-new-offline-store)
4446
* **Online Stores**

‎sdk/python/feast/infra/offline_stores/contrib/mongodb_offline_store/README.md‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
# MongoDB Offline Store
22

33
This offline store lets you train models and run batch scoring directly from it.
4-
All feature views share a single collection (`feature_history`). Reads use
4+
All feature views share a single collection. Reads use
55
MongoDB aggregation pipelines with a compound index, so per-entity cost is
6-
O(log n_observations) regardless of collection size, and K feature views with the same
7-
entity key collapse into one round-trip instead of K (1 if your data shares a unique id.)
6+
O(log n_observations) regardless of collection size.
87

98
## Schema
109

‎sdk/python/feast/infra/offline_stores/contrib/mongodb_offline_store/mongodb.py‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@
1717
1818
Single-collection schema. Key optimizations:
1919
20-
1. K-collapse: feature views that share the same join key set are batched
21-
into a single ``$match + $sort`` aggregation instead of K separate find
22-
queries. Reduces round-trips from K to |unique join key signatures|.
23-
24-
2. Server-side deduplication (scoring path): when entity_df has unique
20+
1. Server-side deduplication (scoring path): when entity_df has unique
2521
entity IDs the aggregation adds a ``$group`` stage that returns at most
2622
one document per (entity_id, feature_view) pair — O(N×K) transfer
2723
instead of O(N×P×K). The compound index backs the entire pipeline,
@@ -561,7 +557,7 @@ def get_historical_features(
561557
562558
Training path (repeated entity IDs at different timestamps):
563559
Omits ``$group`` and uses ``merge_asof`` in Python, matching
564-
standard PIT behaviour but still with K-collapsed queries.
560+
standard PIT behaviour.
565561
566562
Args:
567563
strict_pit: When True (default) features whose document timestamp

0 commit comments

Comments
 (0)