ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Feast Feature Service(ADR-0001):为模型而生的检索级特征分组设计决策与源码实现剖析

Feast Feature Service(ADR-0001):为模型而生的检索级特征分组设计决策与源码实现剖析 Feast Feature ServiceADR-0001为模型而生的检索级特征分组设计决策与源码实现剖析【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast本文围绕 Feast 的架构决策记录 ADR-0001: Feature Services 展开完整还原这一决策的背景动机、API 设计含 Pandas 风格的特征选择与别名、在线/离线统一检索、命名与可变性等关键取舍及其正反两方面影响并对照当前仓库中 sdk/python/feast/feature_service.py、sdk/python/feast/feature_view_projection.py 与 sdk/python/feast/base_feature_view.py 的源码验证 FeatureService 从设计文档到持久化、特征推断的完整落地路径。读完后你应能理解 Feast 中“存储级分组Feature View”与“检索级分组Feature Service”的分工并掌握FeatureService的定义、注册与特征检索用法。一、决策背景Feature View 只管“存储”缺一个“检索”层契约ADR-0001 的状态为Accepted已接受。其背景指出Feast 的 Feature View 允许按特征的生产方式进行存储层面的分组但一直缺少一个与模型对应的、检索层面的特征分组概念。这一缺失带来三个具体问题引自 ADR 原文 Context 一节无法追踪模型血缘没有办法记录“哪些特征被用来训练了某个模型”或“哪些特征在支撑某个特定模型的服务”训练期特征清单易出错检索训练特征时必须手动提供并持久化一份完整的特征列表这种方式繁琐且容易出错缺乏兼容性保护当 Feature View 发生变更时没有办法确保下游消费方不会遭遇破坏性变更breaking changes。换句话说Feature View 解决的是“特征如何被生产和存放”而模型消费方需要的是“我这个模型/服务需要的一组特征”。ADR-0001 要解决的正是后者。二、决策内容引入 FeatureService 对象ADR 的决策是引入FeatureService对象让用户为特定 ML 用例声明要使用哪些特征。一个 feature service 将一个或多个 feature view 中的特征分组在一起共同服务于模型训练与在线服务online serving。2.1 API 设计Pandas 风格的直接引用Feature services 采用类似 Pandas 的 APIfeature view 可以被直接引用引用整个 view 即选取其全部特征用[[...]]索引则只选取指定列引自 ADR “API Design” 一节from feast import FeatureService feature_service FeatureService( namemy_model_v1, features[ shop_raw, # 选取该 view 的全部特征 customer_sales[[average_order_value, max_order_value]], # 只选取指定特征 ], )这个view[[列名列表]]的选取语法并非凭空设计。从 sdk/python/feast/base_feature_view.py#L141-L160 的源码看BaseFeatureView重写了__getitem__传入一个特征名列表后它先对 view 做一次深拷贝self.__copy__()再把选中特征写入副本的projection.features并返回副本——原 view 不被修改返回的是一个“带投影projection的副本”。若 view 已带 schema未选中的特征会立即抛出ValueErrorFeature xxx does not exist in this feature view若 view 尚未确定 schema则把列名暂存到projection.desired_features留待后续推断见 3.2 节。2.2 带别名的特征选择ADR 中还给出了为特征起别名的示例feature_service FeatureService( namemy_model_v1, features[ shop_raw, customer_sales[[average_order_value, max_order_value]] .alias({average_order_value: avg_o_val}), ], )在 ADR 定稿时这类别名机制落在投影projection的名称别名上。从当前源码结构看别名的承载体是 sdk/python/feast/feature_view_projection.py#L16-L57 中的FeatureViewProjection数据类其中name_alias字段被明确注释为“An optional alias for the name”而name_to_use()方法返回name_alias or name——即检索、建表等下游环节实际使用的是别名若存在。sdk/python/feast/base_feature_view.py#L215-L226 的with_name()方法则是产生别名的入口它复制 view 并把cp.projection.name_alias name设置到副本上注释特别说明“该改名副本只用于查询操作不会修改底层 view”。此外FeatureViewProjection还支持join_key_map在检索时改写 join key 列、timestamp_field、date_partition_column、created_timestamp_column等字段说明 ADR 中“对检索行为做细粒度定制”的设想在当前实现里被进一步扩展了。2.3 统一检索一个名字在线与离线通用FeatureService 的价值在于训练与在线服务只需引用同一个服务名从而保证“训练用哪些特征”与“服务时取哪些特征”始终一致引自 ADR “Retrieval” 一节# 在线推理online inference row store.get_online_features( feature_servicemy_model_v1, entity_rows[{customer_id: 123, shop_id: 456}], ).to_dict() # 训练historical featurespoint-in-time 关联 historical_df store.get_historical_features( feature_servicemy_model_v1, entity_dfentity_df, )get_online_features走在线存储读取路径经由 feature server / 在线存储get_historical_features走离线存储的历史时间点关联路径两条路径都以 FeatureService 声明的 feature view 投影集合为输入。这正对应 ADR 正面影响中“为在线与离线特征检索提供一致接口”的表述。2.4 关键设计决策Key DecisionsADR 明确记录了三项关键取舍这是理解该对象设计边界的核心决策点选择理由ADR 原文要点命名定为FeatureService而非FeatureSet“Service”传达的是介于模型与数据之间的服务层概念与模型服务系统model serving中的 model service 类比可变性Feature services 是可变的mutable未来可考虑不可变性但首版不强制版本管理首版不包含版本机制由用户通过命名约定naming conventions自行管理版本其中命名决策颇有意味Feature View 已经是“数据视角”的词汇若再叫 FeatureSet检索层与存储层在语义上难以区分FeatureService 则明确指向“为某个服务/模型供给特征”的运行时语义。而“可变的 无版本”的组合把版本治理的责任留给了用户——这一点在当前源码中已有后续演进见 3.3 节。三、决策影响ConsequencesADR 对影响做了正负两方面的评估正面影响用户可以追踪哪些特征被用于训练和在线服务某个特定模型血缘可追溯为在线与离线特征检索提供了一致的接口减少了易错的手工特征清单维护error-prone manual feature list management为日志记录logging、监控monitoring、端点供给endpoint provisioning等未来能力铺路。负面影响在 Feast 数据模型中增加了一层抽象Feature service 可变若管理不当可能导致训练/服务两侧看到的特征集合不一致。值得注意的是正面影响第 4 条在当时只是“预留能力”在当前仓库中部分已经落地FeatureService类本身就携带logging_config特征日志配置字段且precompute_online标志位为“为单读在线检索预计算特征向量”的场景提供了开关见 3.1 节。四、源码印证FeatureService 在当前仓库中的完整落地ADR 的 References 一节指明实现位于sdk/python/feast/feature_service.py对应的协议定义位于 protos/feast/core/FeatureService.proto。以下基于源码逐点印证 ADR 的设计是否、以及如何被实现。4.1 类定义ADR 设想之外的演进字段sdk/python/feast/feature_service.py#L32-L99 中的FeatureService类定义如下核心属性name: str—— 唯一名称ADR 中“通过命名约定管理版本”的载体_features: List[Union[FeatureView, OnDemandFeatureView, LabelView]]—— 用户传入的 view 列表类型比 ADR 定稿时更广除普通FeatureView外还纳入了按需转换视图OnDemandFeatureView与标签视图LabelViewfeature_view_projections: List[FeatureViewProjection]—— 每个 view 在检索层的投影这是整个 FeatureService 的持久化核心description/tags/owner—— 元信息created_timestamp/last_updated_timestamp—— 注册与更新时刻印证了“可变”定位last_updated_timestamp的存在本身即表明对象会被反复更新logging_config: Optional[LoggingConfig]—— 对应 ADR 正面影响中预留的 logging 能力precompute_online: bool默认False—— 构造参数注释说明为True时按实体维护一份预计算的特征向量用于单读在线检索。__init__在构造时即为每个BaseFeatureView生成投影并追加到feature_view_projectionsfeature_service.py#L97-L99self.feature_view_projections.append(feature_grouping.projection)。也就是说用户写的features列表在对象层面立即被“压扁”成投影列表投影才是注册表与检索路径实际消费的内容。4.2 特征推断infer_features解决“view 未定 schema 时选哪些列”ADR 示例中customer_sales[[average_order_value, ...]]隐含一个前提选中的列必须真实存在。当前实现通过 feature_service.py#L101-L169 的infer_features()处理三种情形逻辑与 2.1 节所述__getitem__的双分支一一对应投影带desired_featuresview 定义时未声明 schema靠推断先用注册表中该 view 已推断出的特征集合做子集校验assert desired_features.issubset(actual_features)再把选中的字段写回projection.features投影已带featuresview 已有已知 schema或整 view 引用无需操作直接跳过投影两者皆空整 view 引用且 view 无 schema把推断出的全部特征赋给projection.features。任一分支中若注册表里找不到对应 view都会抛出FeatureViewMissingDuringFeatureServiceInference定义于 sdk/python/feast/errors.py。这条推断链正是 ADR 所抱怨的“手工维护特征清单易出错”问题的工程化解法清单只声明意图具体列集合在 apply 时由注册表统一解析、校验和固化。此外feature_service.py#L171-L267 的prepare_for_apply()在注册写入前完成了“投影物化”若服务是从 proto 反序列化而来_features为空、只有投影它会按投影名回查注册表、重建可解析的 view 列表再走一遍infer_features。从源码结构看这意味着 FeatureService 无论经由 SDK 直接构造还是经由 Registry Server 请求重建最终收敛到同一套投影解析路径——这是“在线/离线接口一致”能够成立的底层保证之一。4.3 持久化以 Protobuf 投影而非 view 对象入册ADR 中 FeatureService 与 Feature View 的关系是“引用一组 view”但入库时存的是快照式的投影。feature_service.py#L314-L378 的to_proto/from_proto展示了这一机制to_proto把feature_view_projections逐个转为FeatureViewProjectionProto投影内的name、name_alias、feature_columns、join_key_map、时间字段等见 feature_view_projection.py#L59-L82连同tags、description、owner、logging_config、precompute_online打包进FeatureServiceSpecProto并把两个时间戳放进FeatureServiceMetaProtofrom_proto反向重建注意此时features[]不恢复 view 对象本体只恢复投影与元数据。换言之注册表里持久化的是“从哪些 view 选了哪些列”的投影快照而不是 Python view 对象的引用。这有两个工程后果一是服务侧Go/Java 等其它语言 SDK、feature server只需投影信息即可执行检索无需 Python 运行时二是 ADR 中“可变”特性的风险——若 view 的 schema 变更后 feature service 未重新 apply投影快照仍停留在旧列集合上——也由此变得具体可查一致性维护重新 apply 触发infer_features重算是用户的责任与 ADR 负面影响的评估一致。4.4 后续演进版本化引用与校验钩子ADR 记录“首版不含版本管理靠命名约定”。从当前源码结构看检索层已出现版本化的雏形FeatureViewProjection带有version_tag: Optional[int]字段feature_view_projection.py#L50且name_to_use()在存在version_tag时返回形如{name}v{tag}的版本限定名feature_view_projection.py#L53-L57同时BaseFeatureView.ensure_valid()明确禁止 view 名中包含字符并注释说明该字符“保留给版本限定引用如fvv2:feature”base_feature_view.py#L200-L213。这与仓库中后续的版本化设计记录如 docs/adr/ADR-0008-feature-view-versioning.md方向一致ADR-0001 留下的“版本由用户自理”缺口正沿着投影层的版本限定引用逐步补齐——可以推断这是 FeatureService 检索层对 view 版本演进的天然承接点。另一处演进是校验钩子feature_service.py#L422-L433 的validate()在precompute_onlineTrue时会检查服务内是否包含write_to_online_storeFalse的OnDemandFeatureView若是则拒绝——“服务端时刻计算的按需转换无法被预计算”。这类约束体现了 FeatureService 抽象在功能扩张预计算、按需转换后对一致性所做的主动防守。五、小结分层语义Feature View 是按生产方式划分的存储级分组FeatureService 是按模型用例划分的检索级分组后者通过投影FeatureViewProjection引用前者形成“存储 → 投影 → 服务”的三层结构ADR 背景与决策的核心主张。一致接口get_online_features与get_historical_features都以 feature service 为入口训练与服务共享同一特征契约消除了手工特征清单ADR Retrieval 一节。实现要点构造时 view 列表即被转为投影列表apply 时infer_features完成列推断与校验入库持久化的是 protobuf 投影快照而非 view 对象precompute_online、logging_config等字段则把 ADR 预留的监控与端点能力逐步实体化。权衡与演进可变性带来的不一致风险仍由用户通过重新 apply 管理版本管理从“命名约定”演进为投影层的版本限定引用vN与 ADR-0008 的方向衔接。想进一步动手实践的读者可以对照 docs/adr/ADR-0001-feature-services.md 的原始决策、sdk/python/feast/feature_service.py 的完整实现、protos/feast/core/FeatureService.proto 的协议定义以及 examples/quickstart/quickstart.ipynb 中 FeatureService 的端到端示例从设计文档一直追到检索运行时的完整链路。【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表