MongoDB Online Store 在线存储指南:Feast 特征仓库的高性能 MongoDB 落地实践
【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast
MongoDB online store 是 Feast 官方提供的一种在线存储实现,用于把特征值物化(materialize)到 MongoDB 中,支撑在线特征检索(online serving)。本文围绕 docs/reference/online-stores/mongodb.md 展开,从配置接入、数据模型、索引策略、异步支持到功能矩阵逐层展开,并结合仓库内 MongoDBOnlineStore 源码 与集成测试,帮助你理解其内部写入/读取原理,并能在自己的特征仓库中直接落地使用。
概述:为什么选择 MongoDB 作为在线存储
Feast 的在线存储负责以低延迟方式提供"最新特征值",支撑线上推理。MongoDB 作为文档型 NoSQL 数据库,天然具备以下适合在线特征服务的能力:
- 支持 MongoDB Atlas、自建 MongoDB、MongoDB 副本集(replica set)等多种部署形态,连接方式灵活;
- 文档模型适合按实体(entity key)聚合特征:同一实体的多个特征视图(feature view)可以共存于同一文档中;
- 自动创建索引、实体键(entity key)同文档聚合(collocation),保证按实体键查询的高效性;
- 基于 PyMongo 4.13+ 的稳定版
AsyncMongoClient提供原生异步读写支持,无需引入 Motor 等额外依赖,可支撑高并发在线特征请求。
在 Feast 中,MongoDB 在线存储的完整实现位于 sdk/python/feast/infra/online_stores/mongodb_online_store/mongodb.py,配置模型为MongoDBOnlineStoreConfig,核心类为MongoDBOnlineStore。
快速开始:安装与接入
安装 MongoDB 扩展
使用 MongoDB 在线存储前,需要安装 Feast 的 MongoDB extra,同时按需安装所选离线存储(offline store)的依赖:
pip install 'feast[mongodb]'该 extra 依赖 PyMongo 客户端。从当前仓库的 CI 依赖锁定文件(如 py3.12-ci-requirements.txt)可以看到,CI 环境中锁定的是pymongo==4.17.0,对应支持异步AsyncMongoClient的 PyMongo 4.13+ 版本线。
从现有模板切换
你可以使用任意 Feast 初始化模板(例如feast init -t gcp、feast init -t snowflake、feast init -t aws)生成特征仓库骨架,然后在feature_store.yaml中把online_store部分替换为 MongoDB 配置即可,离线存储部分保持不变。若未安装 PyMongo,导入MongoDBOnlineStore时会抛出FeastExtrasDependencyImportError提示缺少mongodbextra(见 mongodb.py)。
feature_store.yaml 配置详解
MongoDBOnlineStoreConfig(见 mongodb.py)的完整配置项如下:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | Literal["mongodb"] | "mongodb" | 在线存储类型选择器,固定为mongodb |
connection_string | str | "mongodb://localhost:27017" | MongoDB 连接串,支持 Atlas、自建、副本集等多种形态 |
database_name | str | "features" | 使用的 MongoDB 数据库名 |
collection_suffix | str | "latest" | 集合名后缀,实际集合名形如<project>_<collection_suffix> |
client_kwargs | Dict[str, Any] | {} | 透传给MongoClient/AsyncMongoClient的任意关键字参数 |
vector_enabled | bool | 继承自VectorStoreConfig | 是否启用 Atlas Vector Search 向量检索 |
similarity | str | 继承自VectorStoreConfig | 向量相似度度量(默认cosine) |
vector_index_wait_timeout | int | 60 | 等待新建 Atlas Search 索引变为 READY 的超时秒数 |
vector_index_wait_poll_interval | float | 1.0 | 轮询 Atlas Search 索引状态的间隔秒数 |
下面给出原文档中的四类典型配置场景。
1. 基础配置:MongoDB Atlas
project: my_feature_repo registry: data/registry.db provider: local online_store: type: mongodb connection_string: "mongodb+srv://username:password@cluster.mongodb.net/" database_name: feast_online_storeAtlas 使用mongodb+srv://协议自动解析副本集节点,适合托管部署。
2. 自建 MongoDB(带认证)
project: my_feature_repo registry: data/registry.db provider: local online_store: type: mongodb connection_string: "mongodb://username:password@localhost:27017/" database_name: feast_online_store collection_suffix: features注意此处把collection_suffix设为features,最终集合名为my_feature_repo_features(实际取项目名与后缀拼接,见源码_get_collection中f"{repo_config.project}_{online_config.collection_suffix}")。
3. MongoDB 副本集配置
project: my_feature_repo registry: data/registry.db provider: local online_store: type: mongodb connection_string: "mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplicaSet" database_name: feast_online_store client_kwargs: retryWrites: true w: majority副本集模式下可通过client_kwargs指定写入关注级别(write concern)。retryWrites: true让 MongoDB 驱动在遇到瞬时主从切换错误时自动重试写入,w: majority保证写入被多数节点确认,是生产环境推荐配置。
4. 高级配置:自定义客户端参数
project: my_feature_repo registry: data/registry.db provider: local online_store: type: mongodb connection_string: "mongodb+srv://cluster.mongodb.net/" database_name: feast_online_store collection_suffix: features client_kwargs: maxPoolSize: 50 minPoolSize: 10 serverSelectionTimeoutMS: 5000 connectTimeoutMS: 10000client_kwargs中的参数会以关键字参数形式原样透传给MongoClient/AsyncMongoClient(源码_get_client与_get_client_async均执行MongoClient(connection_string, driver=DRIVER_METADATA, **client_kwargs)),因此 PyMongo 支持的连接池、超时、TLS 等参数均可在这里配置。例如maxPoolSize控制连接池上限、serverSelectionTimeoutMS控制服务器选择超时、connectTimeoutMS控制建连超时,这些参数直接影响高并发下的吞吐与容错表现。
提示:Feast 在创建客户端时还会传入
DriverInfo(name="Feast", version=...)作为驱动元数据(见源码 mongodb.py),便于在 MongoDB 服务端监控中识别来自 Feast 的连接。
数据模型:单集合 + 实体键聚合
设计原则
MongoDB 在线存储采用**每个项目一个集合(single collection per project)**的存储布局,并将同一实体的特征按实体键聚合(entity key collocation)。即:来自多个特征视图、面向同一实体的特征,都存放在同一个文档中。这正好与 Mongo 的文档模型契合,一次find即可取回该实体的全部相关特征,避免多表关联查询。
集合名规则为<project>_<collection_suffix>,例如项目my_feature_repo、后缀features时集合为my_feature_repo_features;不使用后缀时默认为<project>_latest。
文档 Schema 示例
原文档给出如下示例:单个实体包含来自两个特征视图的特征——driver_stats视图的rating与trips_last7d,以及pricing视图的surge_multiplier;每个特征视图拥有独立的事件时间戳(event timestamp),created_timestamp标记该实体的物化时间:
{ "_id": "<serialized_entity_key>", // Binary entity key (bytes) "features": { "driver_stats": { "rating": 4.91, "trips_last_7d": 132 }, "pricing": { "surge_multiplier": 1.2 } }, "event_timestamps": { "driver_stats": ISODate("2026-01-20T12:00:00Z"), "pricing": ISODate("2026-01-21T08:30:00Z") }, "created_timestamp": ISODate("2026-01-21T12:00:05Z") }该 Schema 与源码中MongoDBOnlineStore的类注释完全一致(mongodb.py):_id为序列化后的实体键字节串,features按<feature_view>.<feature>嵌套,event_timestamps按特征视图记录更新时间,created_timestamp为整篇文档的全局写入时间。
关键设计决策
_id字段:使用序列化实体键(bytes)作为主键,实现 O(1) 级别的按键查询。实体键由 Feast 的serialize_entity_key依据entity_key_serialization_version序列化(见 key_encoding_utils)。- 嵌套特征:特征按特征视图名组织,一个实体文档可承载多个特征视图的数据;
- 事件时间戳:按特征视图分别存储,追踪每个特征集合的最后更新时间,支撑 point-in-time 语义;
- 创建时间戳:整篇文档的全局写入时间。
索引策略
在线存储只依赖一个自动索引:_id上的主键索引(MongoDB 自动创建),其值即序列化实体键。由于查询全部以_id({"$in": [ids]})或向量检索索引展开,在线读写无需额外创建二级索引。
读写实现原理:从源码看数据流
写入:bulk_write + upsert
写入入口为online_write_batch(同步)与online_write_batch_async(异步),两者共享_build_write_ops构造更新操作(mongodb.py)。其流程为:
- 用
serialize_entity_key将实体键序列化为字节串,作为_id; - 用
feast_value_type_to_python_type将每个特征的ValueProto转换为 Python 原生类型; - 构造
$set更新文档:特征值写入features.<feature_view>.<feature>,该视图事件时间写入event_timestamps.<feature_view>,行级写入时间写入created_timestamp; - 包装为
UpdateOne(filter={"_id": entity_id}, update=..., upsert=True)——已存在的实体文档原地更新,新实体首次写入时自动创建; - 通过
collection.bulk_write(ops, ordered=False)(异步为await collection.bulk_write(...))一次性批量执行,ordered=False允许并行处理,提升吞吐。
集成测试 test_mongodb_online_retrieval.py 展示了完整的写入-读取回路:向driver_locations、customer_profile、customer_driver_combined三个特征视图写入不同实体键的特征,随后用get_online_features跨视图读取并断言结果。测试中还验证了复合实体键(customer_id+driver_id)与"写入过其他视图但从未写入当前视图"的实体返回None的边界行为。
读取:$in 查询 + 投影裁剪
读取入口为online_read/online_read_async(mongodb.py):
- 将所有实体键序列化为
ids; - 构造
{"_id": {"$in": ids}}查询过滤; - 投影(projection)只取需要的字段:
_id、event_timestamps.<fv>,以及请求的特征字段features.<fv>.<feature>(未指定请求特征时取整个features.<fv>子树)——这保证了网络传输的最小化; - 命中结果经
_convert_raw_docs_to_proto转换:由于 MongoDB 查询是行导向、而 Feast 的类型转换器是列导向(按特征类型批量转换),源码采取"先按列抽取原始值、按特征批量转成ValueProto、再按行重组"的两次转换策略,既保持实体键顺序对齐,又最小化 python/proto 转换调用次数(mongodb.py)。
基础设施管理:update 与 teardown
update():MongoDB 是松散的惰性 Schema,无需预建表结构。它只负责两件事:对tables_to_delete中的特征视图执行$unset删除其features.<fv>与event_timestamps.<fv>字段;当启用向量检索时为保留的特征视图创建/清理 Atlas Search 索引(详见下文向量检索章节)。teardown():直接clxn.drop()删除整个集合,并关闭同步客户端连接(mongodb.py)。异步客户端通过close()释放资源。
原生异步支持:PyMongo AsyncMongoClient
MongoDB 在线存储基于 PyMongo 4.13+ 的稳定版AsyncMongoClient提供原生异步能力,不依赖 Motor。异步支持的能力包括:
- 高并发:异步 I/O 不会受线程池限制,可支撑数千级并发特征请求;
- 真正的异步非阻塞:适合嵌入 FastAPI 等异步在线推理服务;
- 并发场景性能提升:原文档指出相对同步顺序执行,并发负载下可带来 10–20 倍的性能提升(该数据为项目文档口径,实际收益取决于工作负载与部署环境,建议结合自身压测验证)。
同步与异步方法一一对应、完全对等:
| 同步 | 异步 |
|---|---|
online_read | online_read_async |
online_write_batch | online_write_batch_async |
类属性async_supported返回SupportedAsyncMethods(read=True, write=True),显式声明读写均支持异步(mongodb.py)。异步客户端与同步客户端相互独立缓存:_client/_collection与_client_async/_collection_async分别持有连接,异步写入同样复用_build_write_ops生成UpdateOne操作,再经await clxn.bulk_write(ops, ordered=False)执行,保证读写行为与同步路径完全一致。
扩展能力:MongoDB Atlas Vector Search
MongoDB 在线存储还支持向量检索($vectorSearch),可支撑 RAG 等语义检索场景。启用方式是在配置中设置vector_enabled: true,并在特征定义中为向量字段标注vector_index=True、vector_length、vector_search_metric。
update()阶段会自动为每个 (feature_view, vector_field) 组合创建名为<fv>__<field>__vs_index的 Atlas Search 索引,并通过轮询等待其变为 READY(vector_index_wait_timeout/vector_index_wait_poll_interval控制等待行为);索引创建是幂等的,重复调用update()不会重复建索引。特征视图被删除时,对应的向量索引也会被清理。
检索入口retrieve_online_documents_v2使用$vectorSearch聚合阶段按余弦/欧氏等相似度返回top_k个最近文档,并将向量搜索得分以distance特征返回。集成测试 test_mongodb_vector_search.py 使用mongodb/mongodb-atlas-local:8.0.4本地 Atlas 镜像验证了索引创建、写入-检索往返、top_k限制、更新幂等性与 teardown 清理等完整链路。仓库内的 RAG 示例(如 examples/rag)即采用此类向量检索能力构建检索增强生成应用。
功能矩阵:能力边界一览
原文档给出了 MongoDB 在线存储相对 overview.md 功能定义的能力矩阵:
| 功能 | MongoDB |
|---|---|
| 向在线存储写入特征值 | yes |
| 从在线存储读取特征值 | yes |
| 更新在线存储基础设施(如表) | yes |
| 销毁在线存储基础设施(如表) | yes |
| 生成基础设施变更计划 | no |
| 支持 on-demand transforms | yes |
| 可被 Python SDK 读取 | yes |
| 可被 Java 读取 | no |
| 可被 Go 读取 | no |
| 支持无实体特征视图(entityless) | yes |
| 支持并发写入同一键 | yes |
| 检索时支持 TTL(time to live) | no |
| 支持删除过期数据 | no |
| 按特征视图聚合(collocated by feature view) | no |
| 按特征服务聚合(collocated by feature service) | no |
| 按实体键聚合(collocated by entity key) | yes |
要点解读:
- 基础设施变更计划(plan)不支持:与 Postgres、Redis 等"表驱动"存储不同,MongoDB 采用集合 + 文档的惰性 Schema,
update()中几乎无结构变更可言,因此不生成变更计划; - TTL 与过期数据删除不支持:目前 MongoDB 在线存储不基于特征视图 TTL 做检索过滤或物理清理,需要结合应用侧或 MongoDB TTL 索引自行规划;
- 按实体键聚合:这是其核心布局,与"单集合 + 文档"设计一致;
- 读写语言覆盖:目前仅 Python SDK 可读,Java / Go 特征服务器尚不消费该存储。
完整的能力对比矩阵见 overview.md。
测试与本地验证
仓库为 MongoDB 在线存储提供了多层测试,便于本地复现验证:
- 单元/集成检索测试:test_mongodb_online_retrieval.py 通过
testcontainers的MongoDbContainer(mongo:latest,内置用户名/密码认证)启动容器,验证多特征视图写入、跨视图读取、复合实体键与缺失特征视图返回None等行为; - 通用在线存储测试:test_universal_online.py 覆盖所有通用在线存储的公共行为契约;
- 向量检索测试:test_mongodb_vector_search.py 覆盖 Atlas Vector Search 全链路;
- 测试仓库配置:mongodb_repo_configuration.py 注册了 MongoDB 的
IntegrationTestRepoConfig,复用MongoDBOnlineStoreCreator在mongo:latest容器中建立带认证的连接串。
这些测试均要求本机 Docker 可用(测试内以_requires_docker跳过),可用于理解连接串格式与认证场景的配置范式。
总结
MongoDB online store 以"每项目单集合 + 实体键文档聚合"的设计,为 Feast 在线特征服务提供了一种部署灵活、扩展简单的存储选项:支持 Atlas / 自建 / 副本集多形态连接,client_kwargs可精细调优连接池与超时;_id主键索引 + 投影裁剪保证按键查询高效;同步/异步双通道读写支撑高并发在线推理;并可通过 Atlas Vector Search 扩展语义检索能力。接入时只需在feature_store.yaml中配置type: mongodb与连接参数,即可在既有特征仓库中无缝启用。
【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考