Feast MySQL Online Store 接入指南:配置、物化与在线特征读取实战
【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast
MySQL 是当前 Feast 官方路线图中尚未正式规划的存储系统,但社区通过在sdk/python/feast/infra/online_stores/mysql_online_store目录下的实现,为其提供了完整的 Online Store 支持。本文基于仓库内 mysql_online_store/README.md 与 mysql.py 源码,讲解如何在 Feature Repository 中把 MySQL 配置为在线特征存储、执行物化(materialize)并把最新特征实时读取出来。读完本文,你将掌握 MySQL Online Store 的完整配置参数、端到端使用流程,以及其底层表结构与读写实现的原理。
MySQL Online Store 在 Feast 中的定位
Feast 的 Online Store 抽象定义在 online_store.py,它要求实现类提供online_write_batch(批量写入)、online_read(按实体键读取)、update(基础设施调和)和teardown(清理资源)等核心方法。MySQL 实现即遵循这套接口:
- 配置类
MySQLOnlineStoreConfig负责解析feature_store.yaml中的online_store段; - 存储类
MySQLOnlineStore负责与 MySQL 建连、读写特征数据; - 每次
materialize(物化)调用时,Feast 会把离线特征写入以<project_name>_<feature_view_name>命名的 MySQL 表,供低延迟在线读取。
从 repo_config.py 可以看到类型映射:"mysql"被注册为feast.infra.online_stores.mysql_online_store.mysql.MySQLOnlineStore,因此在feature_store.yaml中只需把online_store.type设为mysql即可被 Feast 自动加载。
第一步:创建 Feature Repository
沿用 Feast 标准初始化流程,在 shell 中执行:
feast init feature_repo cd feature_repo初始化后会生成一个包含feature_store.yaml与示例特征定义(如example.py)的最小仓库骨架,本文后续的apply、materialize-incremental命令都基于该目录执行。
第二步:配置feature_store.yaml使用 MySQL
编辑仓库根目录下的feature_store.yaml,将online_store的类型设置为mysql,完整配置如下:
project: feature_repo registry: data/registry.db provider: local online_store: type: mysql host: 127.0.0.1 # mysql endpoint, default to 127.0.0.1 port: 3306 # mysql port, default to 3306 user: test # mysql user, default to test password: test # mysql password, default to test database: feast # mysql database, default to feast batch_write: false # supporting batch write and commit per batch batch_size: 100 # batch size, default to 100各参数的含义与默认值,与 mysql.py 中MySQLOnlineStoreConfig的字段定义一一对应:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | 字符串 | mysql | 固定字面量,用于触发 Online Store 类型映射 |
host | 字符串 | 127.0.0.1 | MySQL 服务端点 |
port | 整数 | 3306 | MySQL 端口 |
user | 字符串 | test | MySQL 用户名 |
password | 字符串 | test | MySQL 密码 |
database | 字符串 | feast | 目标数据库名,表会被创建在该库中 |
batch_write | 布尔 | false | 是否启用批量写入并按批提交 |
batch_size | 整数 | None | 批量写入时的批大小 |
这些默认值并非文档承诺,而是源码中_get_conn的连接逻辑直接体现的:host or "127.0.0.1"、user or "test"、password or "test"、database or "feast"、port or 3306,且autocommit由batch_write决定(见 mysql.py)。因此即使省略大部分字段,Feast 也能按默认参数连接本地 MySQL。
第三步:应用特征定义
在example.py中定义好 Entity 与 FeatureView 后,执行:
feast -c feature_repo applyapply会注册实体与特征视图,并在 MySQL 中创建对应的基础设施。参考输出:
Registered entity driver_id Registered feature view driver_hourly_stats_view Deploying infrastructure for driver_hourly_stats_viewDeploying infrastructure这一步实际触发了MySQLOnlineStore.update方法:对每个需要保留的 FeatureView,执行CREATE TABLE IF NOT EXISTS <project>_<feature_view_name>建表,并检查information_schema.statistics,若缺少以表名加_ek后缀命名的索引则通过ALTER TABLE ... ADD INDEX补建实体键索引(见 mysql.py)。
MySQL 中的表结构
由update方法可以确定,每张在线特征表拥有如下结构:
CREATE TABLE IF NOT EXISTS <project>_<feature_view_name> ( entity_key VARCHAR(512), feature_name VARCHAR(256), value BLOB, event_ts timestamp NULL DEFAULT NULL, created_ts timestamp NULL DEFAULT NULL, PRIMARY KEY(entity_key, feature_name) );即:同一行数据以“实体键 + 特征名”作为联合主键,value列存放 protobuf 序列化后的特征值,event_ts记录事件时间,created_ts记录写入时间;同时表名形如feature_repo_driver_hourly_stats_view,符合文档所述“每次物化都会更新该表”的命名与更新约定。
第四步:物化最新数据到 MySQL
离线特征通过物化命令写入 MySQL。先在 shell 中取当前时间,再执行增量物化:
$ CURRENT_TIME=$(date -u +"%Y-%m-%dT%H:%M:%S") $ feast -c feature_repo materialize-incremental $CURRENT_TIME参考输出:
Materializing 1 feature views from 2022-04-16 15:30:39+05:30 to 2022-04-19 15:31:04+05:30 into the mysql online store. driver_hourly_stats_view from 2022-04-16 15:30:39+05:30 to 2022-04-19 15:31:04+05:30: 100%|████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 120.59it/s]底层写入路径:逐条提交与批量提交
物化最终调用的是MySQLOnlineStore.online_write_batch(见 mysql.py),其行为由batch_write配置分支:
- 非批量模式(默认):逐条执行
INSERT ... ON DUPLICATE KEY UPDATE,每处理完一个实体键的所有特征后立即commit(),适合数据量小、需要实时可见的场景; - 批量模式(
batch_write: true):先把特征值序列化结果累积到insert_values列表,达到batch_size后调用cursor.executemany一次性写入并提交;批量末尾的剩余数据也会在循环结束后补写提交,任一批失败时执行rollback()并抛出异常。
两种模式写入时都使用ON DUPLICATE KEY UPDATE语义(见 mysql.py):若主键(entity_key, feature_name)已存在,则用新值覆盖value、event_ts、created_ts,实现“最新物化结果覆盖旧数据”的效果,这正对应 README 中“每次 materialize 调用更新表数据”的描述。需要留意的是,从源码实现看,批量模式读取的是config.online_store.bacth_size(注意该拼写为源码中的实际写法),且批大小小于 2 时会抛出ValueError("Batch size must be at least 2"),配置时建议显式给出合理的batch_size。
第五步:在线读取最新特征
物化完成后,即可在应用侧使用 Python SDK 按实体键读取在线特征:
from pprint import pprint from feast import FeatureStore store = FeatureStore(repo_path=".") feature_vector = store.get_online_features( features=[ "driver_hourly_stats:conv_rate", "driver_hourly_stats:acc_rate", "driver_hourly_stats:avg_daily_trips", ], entity_rows=[ {"driver_id": 1004}, {"driver_id": 1005}, ], ).to_dict() pprint(feature_vector)参考输出:
{'acc_rate': [0.01390857808291912, 0.4063614010810852], 'avg_daily_trips': [69, 706], 'conv_rate': [0.6624961495399475, 0.7595928311347961], 'driver_id': [1004, 1005]}读取路径的源码实现
get_online_features经由OnlineStore.get_online_features编排后,最终落到MySQLOnlineStore.online_read(见 mysql.py):
- 对每个实体键,先用
serialize_entity_key序列化并转成十六进制字符串作为entity_key; - 执行
SELECT feature_name, value, event_ts FROM <table> WHERE entity_key = %s取出该实体全部特征; - 将
value列中的二进制通过ValueProto.ParseFromString反序列化为特征值; - 若查询无记录则返回
(None, None),否则返回(event_ts, {feature_name: value})。
整个流程是逐实体键串行查询,依赖update阶段创建的表名索引(<table>_ek)来加速entity_key等值查找。另外,从 online_store.py 的_is_versioned_read_supported可以看出,MySQL Online Store 被显式列入支持版本化(versioned)在线读取的存储类型名单中,可配合enable_online_feature_view_versioning与版本化表名(形如_v1、_v2)使用,teardown时也会按^<base>_v[0-9]+$正则清理全部版本表。
依赖与测试验证
MySQL Online Store 的 Python 连接层基于pymysql(mysql.py),运行前需确保环境已安装该依赖。仓库内的通用测试配置 mysql_repo_configuration.py 注册了两套测试场景:
MySQLOnlineStoreCreator:默认逐条提交模式;BatchWriteMySQLOnlineStoreCreator:batch_write: True、批大小 1000 的批量提交模式。
两者对应的实现位于 tests/universal/feature_repos/universal/online_store/mysql.py,通过testcontainers.mysql.MySqlContainer启动mysql:latest容器并暴露 3306 端口,使用root/test用户与test数据库完成端到端验证。这意味着非批量与批量两条写入路径都被覆盖在 Feast 的通用在线存储测试集中,是验证本配置可行性的直接参考。
使用建议与注意事项
- 建库先行:
MySQLOnlineStore只负责建表与索引,不会创建数据库本身,使用前需确保database: feast指定的库已存在,且连接用户具备建表、索引和读写权限。 - 选择写入模式:小规模数据与实时验证可直接使用默认逐条提交模式;数据量大、追求物化吞吐时开启
batch_write: true并合理设置batch_size(源码要求不小于 2,建议按千级设置以减少提交开销)。 - 键值存储模型:在线表按“实体键 + 特征名”组织,同一 FeatureView 的多个特征对应同一实体键下的多行记录,主键冲突时由
ON DUPLICATE KEY UPDATE保证“后物化者覆盖先物化者”。 - 生命周期管理:
feast teardown会调用MySQLOnlineStore.teardown删除对应 FeatureView 的表(版本化开启时连同全部版本表一并清理),不再使用的特征可据此安全释放 MySQL 存储空间。
至此,你已经可以基于这份社区实现,把 MySQL 作为 Feast 的低延迟在线特征存储,走通“定义特征 → apply → 物化 → 在线读取”的完整链路,并为已有 MySQL 基础设施的团队省去额外引入 Redis、DynamoDB 等专用在线存储的成本。
【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考