一家餐厅不可能等客人点完菜再去菜地摘菜。真正的后厨会在开门前把食材洗净、切好、按份装袋,客人下单时只要下锅快炒。这个“提前备好的半成品”,就是离线特征。模型要用的特征,很多也可以用历史数据提前算好,存放在一个随取随用的“冷柜”里。这样在线预测时不用临阵磨枪,几毫秒就能出结果。而支撑这一切的,正是批处理架构——它像厨房的排班表、流水线、传菜梯和品控台,负责在正确的时间把正确数据加工成正确特征。本文就从“备菜”的视角,把离线特征计算与批处理架构讲透。

岗位关联

对 AI 从业者来说,理解离线特征计算能帮你设计可靠的训练数据链路、定位特征线上线下的不一致问题,并为工业级特征平台选型打下基础。

目录
  1. 可视化演示
  2. 离线特征概念
  3. 批处理计算模型
  4. 调度依赖管理
  5. 时效性设计
  6. 特征存储与复用
  7. 数据质量保障
  8. 批流一体趋势
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

可视化展示离线特征计算核心架构:离线在线分离设计、点在时间正确性保障、训练服务一致性对齐,交互切换理解特征工程批处理系统。

本节配有交互动效(进入视口后自动加载,约 3KB)。

离线在线分离架构 离线批处理计算特征 在线低延迟读取服务 offline \u2192 store \u2192 online 离线计算与在线服务分离保证性能与一致性

离线特征概念

一家餐厅不可能等客人点完菜再去菜地摘菜。真正的后厨会在开门前把食材洗净、切好、按份装袋——客人下单时只要下锅快炒。这个“提前备好的半成品”,就是离线特征。模型要用的特征,很多也可以用历史数据提前算好,存放在一个随取随用的“冷柜”里。这样在线预测时不用临阵磨枪,几毫秒就能出结果。

在线特征像“现炒”,输入是请求那一刻的实时数据;离线特征像“预制菜包”,输入是昨天、上周、甚至更早的历史行为。它的产出周期通常是小时级或天级,因此天然接受一定延迟,但换来了高可靠、低成本、可回溯。经典产出包括用户近 7 天点击次数、商品近 30 天转化率等。

技术上讲,离线特征计算是一个“批量聚合 + 落表”的过程:从数据仓库或数据湖读取行为日志,按用户、商品等键组合,加上时间窗口做聚合,最后写回特征表。关键点在于时间窗口必须明确:是自然日、滑动窗口还是事件时间窗口?这决定了特征口径。

所以,离线特征不是技术退步,而是聪明的“提前备菜”。每一次模型更新,都从这座冷柜里取食材,而不是临时去菜地里拔。

f^u,d=Φ ⁣({(ek,tk)∣uk=u, tk∈[d−W+1, d]})\displaystyle \hat{f}_{u,d} = \Phi\!\left(\{ (e_k, t_k) \mid u_k = u,\ t_k \in [d-W+1,\, d] \}\right)
这个式子在说:对用户 u 在最近 W 天窗口内产生的所有事件做一次聚合,就得到了第 d 天的离线特征。
  1. 事件集合花括号里的条件是“选出属于用户 u 的事件”,相当于后厨只挑这位客人的订单。
    {(ek,tk)∣uk=u}\displaystyle \{ (e_k, t_k) \mid u_k = u \}
  2. 时间窗口所有事件的发生时间必须落在第 d 天之前的 W 天里。
    tk∈[d−W+1, d]\displaystyle t_k \in [d-W+1,\, d]
  3. 聚合函数$\Phi$ 可以是求和、计数、平均等操作,把多条原始记录压成一个数。
    Φ(⋅)∈{count,sum,avg}\displaystyle \Phi(\cdot) \in \{ \text{count}, \text{sum}, \text{avg} \}
  4. 特征输出$\hat{f}_{u,d}$ 就是最终放进特征表的“半成品菜包”。
    f^u,d=Feature(u,d)\displaystyle \hat{f}_{u,d} = \text{Feature}(u, d)

批处理计算模型

备菜车间不会为每一根胡萝卜单独开一条流水线,而是凑齐一筐再统一切。数据批处理也一样,把一段时间内的数据攒成“一批”,一次性喂给计算引擎。这个模型天然适合离线特征:全量数据都在,可以反复读、反复算。

批处理模型有两种常见的“开工法”。第一种是全量重算:不管之前有没有结果,每天把整个窗口的数据从头算一遍,结果一定正确,但成本高;第二种是增量计算:只处理新增的数据,顺便把过期离开窗口的数据减掉,速度快,但容易积累误差。

在工程上,离线特征一般用 Spark、Hive 等引擎跑定时任务。你需要决定计算粒度:是每小时跑一个分区,还是每天重建整张表?窗口固定时,建议使用“分区覆盖”而不是“全表覆盖”,这样某一天的数据坏了只需重算那一天。

全量重算像“周末大扫除”,增量像“每天擦桌子”;两者配合,才能既保证正确又控制成本。

Fu,dwin=Fu,d−1win+Nu,d−Eu,d−W\displaystyle F_{u,d}^{\text{win}} = F_{u,d-1}^{\text{win}} + \mathcal{N}_{u,d} - \mathcal{E}_{u,d-W}
这是增量计算的“流水账”:昨天的窗口特征,加上今天新进入窗口的数据,再减掉刚好滑出窗口的旧数据。
  1. 昨日结果$F_{u,d-1}^{\text{win}}$ 是昨天已经算好的用户窗口特征,相当于昨晚备好的菜包。
    Fu,d−1win\displaystyle F_{u,d-1}^{\text{win}}
  2. 今日新增$\mathcal{N}_{u,d}$ 是今天刚发生的、应该计入窗口的新事件。
    Nu,d\displaystyle \mathcal{N}_{u,d}
  3. 过期离场$\mathcal{E}_{u,d-W}$ 是第 $d-W$ 天的事件,已经滑出窗口,必须减掉。
    Eu,d−W\displaystyle \mathcal{E}_{u,d-W}
  4. 拼接更新三者相加得到今天的特征,这就是增量模式的本质。
    Fu,dwin=Fu,d−1win+Δu,d\displaystyle F_{u,d}^{\text{win}} = F_{u,d-1}^{\text{win}} + \Delta_{u,d}

调度依赖管理

后厨的菜不是所有厨师同时动手,而是有明确的传菜顺序:切配完成才能交给灶台,灶台完成才能装盘。离线任务也是这样,一个“小时级用户活跃特征”必须等上游的“行为日志”入库完成才能开始。这个先后关系画出来就是一张有向无环图,简称 DAG。

调度系统的职责是保证下游任务在上游任务全部成功后启动,而不是光看时钟。如果只看时间,上游数据晚到了 20 分钟,下游拿到的是残缺数据,特征质量就崩了。因此调度器会监听上游“完成事件”,再触发下游;同时还要管理失败重试和资源队列,避免多个任务抢资源。

工程实现上,Airflow、DolphinScheduler 等工具会把任务建模成 DAG,每个节点包含 SQL 或 Spark 作业。调度依赖不仅是任务依赖,更是“数据就绪依赖”:上游任务成功不代表数据可用,有时要等提交、分区可见。

把 DAG 想成后厨的“传菜梯”:上游没按铃,下游绝不能先动手。调度器不是闹钟,而是那个盯着每道工序是否真的完成的人。

tstart(j)=max⁡i∈parents(j)(tend(i))\displaystyle t_{\text{start}}(j) = \max_{i \in \mathrm{parents}(j)} \bigl(t_{\text{end}}(i)\bigr)
下游任务 j 的启动时间,必须晚于所有上游任务 i 的结束时间。这就是“传菜梯”逻辑:楼上没按铃,楼下不能先动手。
  1. 下游起点$t_{\text{start}}(j)$ 表示任务 j 最早可以开始计算的时刻。
    tstart(j)\displaystyle t_{\text{start}}(j)
  2. 上游集合$\mathrm{parents}(j)$ 是任务 j 的所有直接上游。
    i∈parents(j)\displaystyle i \in \mathrm{parents}(j)
  3. 取最大值对每个上游结束时间取最大,保证所有前置工作都完成。
    max⁡i(tend(i))\displaystyle \max_{i} \bigl(t_{\text{end}}(i)\bigr)
  4. 就绪条件只有满足这个不等式,下游才会被调度器放行。
    tstart(j)≥tend(i), ∀i\displaystyle t_{\text{start}}(j) \geq t_{\text{end}}(i),\ \forall i

时效性设计

半成品也有保质期。凉菜必须当天现拌,炖菜可以提前一天备好。离线特征的时效性设计,就是给每个特征定“保质期”和“上架时间表”。有的特征要求 T+1,也就是第二天早上看到昨天数据;有的要求小时级;有的甚至允许延迟半天。

决定时效性的是业务 SLA,比如模型在早上 8 点要更新用户画像,那么离线任务必须预留出抽取、计算、写入、校验的时间。数据回溯窗口则回答另一个问题:如果我想修正过去 30 天的特征,系统允不允许重算历史分区?这要求存储层不要原地覆盖,而要支持“按日期分区重建”。

技术落地时常见做法是给任务分优先级:核心特征用专有资源池保证准点,实验特征可以排在低峰。还要设置监控告警:如果产出时间超过 SLA 阈值,立即报警,而不是等模型效果掉了才发现。

每个特征都要问一句:这盘菜最晚几点上桌?超过时间就是馊了,再好吃也没人敢端给模型。

tproduce−tevent≤Δmax⁡\displaystyle t_{\text{produce}} - t_{\text{event}} \leq \Delta_{\max}
“特征上架时间”减去“事件发生时间”,必须小于等于业务允许的最大延迟,否则这盘菜就馊了。
  1. 事件时间$t_{\text{event}}$ 是原始行为实际发生的时刻,比如用户昨晚 23 点的点击。
    tevent\displaystyle t_{\text{event}}
  2. 产出时间$t_{\text{produce}}$ 是特征真正写入特征表、可供读取的时刻。
    tproduce\displaystyle t_{\text{produce}}
  3. 延迟差两者相减就是这条特征的新鲜度延迟。
    Δ=tproduce−tevent\displaystyle \Delta = t_{\text{produce}} - t_{\text{event}}
  4. SLA 上限$\Delta_{\max}$ 是业务约定的最长等待时间。
    Δ≤Δmax⁡\displaystyle \Delta \leq \Delta_{\max}

特征存储与复用

备好的菜包不能堆在角落,要放进贴着标签的冷柜:品名、日期、分量一目了然。特征平台就是这个“中央冷柜”,把离线特征统一存储、统一管理,供训练和在线推理共同取用。

没有特征平台时,算法工程师从 Hive 里导出一份特征训练,在线服务再写一份特征代码去查,两边口径很容易不一致。特征平台通过“特征注册 + 版本管理 + 同一份数据源”解决这个问题。训练时用批式导出,在线推理时用 Redis 等 KV 存储查询,但底层特征定义只有一份。

关键技术是点查一致性,也叫 point-in-time join:训练集在时间点 t 的特征,绝不能混入 t 之后才产生的信息。因此离线特征表会带上“生效时间”和“失效时间”,特征平台按时刻切分,保证训练和上线吃到的是同一批配方。

冷柜里的每包菜都有“出厂日期”,厨师和算法工程师用的正是同一批配方。这就是特征复用解决的核心问题。

Ftrain(u,t)=Lookup(FeatureStore, u, τ(u,t)),τ(u,t)≤t\displaystyle F_{\text{train}}(u,t) = \mathrm{Lookup}\bigl(\mathrm{FeatureStore},\, u,\, \tau(u,t)\bigr),\quad \tau(u,t) \le t
训练时查特征,只能取“最接近且不晚于时间 t”的那个版本。这就像冷柜里拿菜包,必须看保质期,不能把明天的菜包拿到今天用。
  1. 训练特征$F_{\text{train}}(u,t)$ 是用户 u 在时刻 t 应该看到的特征。
    Ftrain(u,t)\displaystyle F_{\text{train}}(u,t)
  2. 查冷柜$\mathrm{Lookup}$ 表示从特征平台按用户和时间做一次查询。
    Lookup(FeatureStore,u,τ)\displaystyle \mathrm{Lookup}(\mathrm{FeatureStore}, u, \tau)
  3. 生效时间$\tau(u,t)$ 是训练时刻 t 对应的特征版本时间。
    τ(u,t)\displaystyle \tau(u,t)
  4. 防未来约束 $\tau(u,t) \le t$ 保证不会用未来数据偷看答案。
    τ≤t\displaystyle \tau \leq t

数据质量保障

中央厨房最重要的是品控。切好的萝卜如果有霉点,整锅菜都毁了。离线特征同样要设“品控台”:在特征表发布前,先跑数据校验规则,比如非空比例、取值区间、总量波动。

常见做法是质量规则任务嵌在调度 DAG 里,校验失败就阻塞下游。同时记录血缘,谁生产了这张表、从哪些原始日志来、被哪些模型使用,出问题能快速定位。异常检测告警则可以盯住“今天的点击量比昨天少 50%”这类突变,而不是等模型指标下降。

另一个容易被忽略的点是幂等重跑。批处理任务必须保证用相同输入重跑,得到完全相同的输出。这样某一天数据修复后,可以把历史分区推倒重来,不会和已有的结果叠成两份。实现上通常用“覆盖写分区 + 确定性排序”。

品控不是做一次,而是每次出餐前都做。只有每次重跑都端出一模一样的菜,后厨才敢放心补货。

Rerun(D,S)=S\displaystyle \mathrm{Rerun}(D, S) = S
对同一份输入数据 D 反复执行同一个批处理任务,得到的特征结果 S 必须完全一致。这就是幂等。
  1. 输入数据$D$ 是批处理任务读到的原始事件集合。
    D\displaystyle D
  2. 任务执行$\mathrm{Rerun}$ 表示把整个离线任务再完整执行一遍。
    Rerun(D,S)\displaystyle \mathrm{Rerun}(D, S)
  3. 结果不变等式右边还是 $S$,说明没有叠加、没有重复计数。
    =S\displaystyle = S
  4. 确定性幂等要求任务内部没有随机性,排序、聚合规则都固定。
    Output=Deterministic(D)\displaystyle \text{Output} = \text{Deterministic}(D)

批流一体趋势

再大的中央厨房,也难免有客人想吃现炒的菜。于是后厨开始两条线并行:一条大锅慢炖负责稳定供给,一条小灶快炒负责新鲜热辣。这就是批流一体的思想:离线批处理打底,实时流处理补充。

Lambda 架构最直观:批处理层产出准确但延迟高的基础特征,速度层用流处理产出低延迟的近似特征,最终由服务层合并。Kappa 架构则更进一步,让所有数据都走流处理管道,把批处理视为“重放历史”的特例。两种架构并不是二选一,很多团队会用离线主表 + 实时补丁的方式过渡。

存储层面,湖仓一体把数据湖的灵活性和数据仓库的治理能力结合起来,离线批任务和实时流任务共享同一套表格式,如 Iceberg、Hudi,特征的“批版本”和“流版本”更容易对齐。技术选型时要考虑:特征窗口是秒级还是天级?业务对迟到数据容忍度如何?这决定你需要多重的实时系统。

先有大锅菜保证不饿肚子,再加小炒提升体验,这才是现代特征厨房的完整形态。

Ffinal(u,t)=Fbatch(u,t)+γ⋅Frealtime(u,t)\displaystyle F_{\text{final}}(u,t) = F_{\text{batch}}(u,t) + \gamma \cdot F_{\text{realtime}}(u,t)
最终特征等于稳定的大锅菜再加上一小勺现炒料。γ 控制了实时结果对最终特征的影响权重。
  1. 最终特征$F_{\text{final}}(u,t)$ 是模型实际拿到的融合特征。
    Ffinal(u,t)\displaystyle F_{\text{final}}(u,t)
  2. 批处理底座$F_{\text{batch}}(u,t)$ 是离线层算好的准确但不够新的特征。
    Fbatch(u,t)\displaystyle F_{\text{batch}}(u,t)
  3. 实时补丁$F_{\text{realtime}}(u,t)$ 是流处理层给出的低延迟特征。
    Frealtime(u,t)\displaystyle F_{\text{realtime}}(u,t)
  4. 融合权重$\gamma$ 是 0 到 1 之间的系数,负责权衡准确与新鲜。
    γ∈[0,1]\displaystyle \gamma \in [0, 1]

AI 应用场景

推荐系统离线画像

阶段:特征工程 / 离线特征生产

解决的问题:推荐系统需要“用户近 7 天点击类目分布”“活跃天数”“平均观看时长”等历史特征。如果在线服务临时扫描七天日志做聚合,延迟和数据库压力都不可接受。离线批处理提前把特征算好,在线推理直接查冷柜。

具体案例:短视频平台每天凌晨 0 点启动 DAG:先同步昨日日志,再跑用户特征聚合,最后发布到 Redis;早上 8 点线上模型开始读取新特征,推荐列表随之上线。

金融风控历史特征

阶段:批处理调度 / 特征存储

解决的问题:风控模型需要“近 30 天申请次数”“设备关联账号数”等强历史特征。纯实时计算难以回溯历史,且训练集需要准确的过去视角,不能混入未来信息。

具体案例:银行每天早上 6 点批量更新黑名单和设备关联特征,8 点风控模型开始服务;发现新欺诈模式后,对过去 14 天的特征分区做幂等重跑,重新生成训练集。

广告计费 CTR 预估

阶段:批流一体 / 时效性设计

解决的问题:广告 CTR 模型既要小时级更新的长期兴趣特征,也要分钟级响应的实时上下文特征。单独用 T+1 太旧,单独用流处理成本太高。

具体案例:广告平台每小时用批处理产出用户近期点击特征,同时用 5 分钟窗口的流任务产出现时热度特征,最终通过特征融合公式合成打分特征。

Python 演示

python42 行
from collections import defaultdictfrom datetime import date, timedelta # 模拟原始行为日志: 日期, 用户, 动作RAW_EVENTS = [    ("2025-01-01", "u1", "click"),    ("2025-01-01", "u2", "click"),    ("2025-01-02", "u1", "click"),    ("2025-01-02", "u2", "view"),    ("2025-01-03", "u1", "view"),    ("2025-01-03", "u2", "click"),] def parse_day(text):    return date.fromisoformat(text) def build_offline_features(events, window_days=2):    daily_count = defaultdict(lambda: defaultdict(int))    for day_text, user, action in events:        if action == "click":            daily_count[parse_day(day_text)][user] += 1     all_days = sorted({parse_day(e[0]) for e in events})    all_users = sorted({e[1] for e in events})    features = []     for day in all_days:        for user in all_users:            total = 0            for offset in range(window_days):                total += daily_count[day - timedelta(days=offset)].get(user, 0)            features.append({                "date": day.isoformat(),                "user": user,                "click_in_" + str(window_days) + "d": total,            })    return features if __name__ == "__main__":    result = build_offline_features(RAW_EVENTS, window_days=2)    for row in result:        print(row)
目的:模拟最简单的离线特征批处理:从原始行为日志中按天聚合出“近 2 天点击次数”特征。
  1. daily_count = defaultdict(lambda: defaultdict(int))建立“日期 -> 用户 -> 次数”的三层字典,相当于后厨的分格保鲜盒。
  2. if action == "click":只挑选点击行为,过滤掉浏览等噪音事件。
  3. all_days = sorted({parse_day(e[0]) for e in events})取出去重后的日期并按时间排序,保证加工顺序稳定。
  4. for offset in range(window_days):向前数 2 天,这正是“近 2 天窗口”的计算逻辑。
  5. features.append({...})把算好的特征打包成半成品,模拟写入特征表。
  6. print(row)输出结果,相当于离线任务落盘后的预览。

常见误区

误区离线特征就是“跑得慢”的实时特征,能实时化就尽量实时化,把任务全部改成流处理才先进。

正解离线与实时是分工不是优劣。离线可以低成本回溯、批量重算、保证训练数据可靠;全部实时化会让存储和计算成本爆炸,而且超长窗口在延迟约束下几乎无法计算。中央厨房里,不能为了“新鲜”放弃“备菜”。

为何常见:大众和媒体过度追捧“实时”概念,忽略了批处理在正确性和成本上的价值。

误区调度任务只要定好时间就不会错,每天凌晨 2 点跑,早上 8 点肯定能出数。

正解只看固定时间会忽略依赖链。如果上游日志凌晨 3 点才到,2 点的任务读到的是不完整数据;必须让调度器监听上游完成事件,并对迟到数据做延迟策略。

为何常见:把“定时执行”和“数据就绪”混为一谈,以为任务到点启动就一定读到正确数据。

误区幂等重跑就是失败后重新执行一遍,不报错就万事大吉。

正解幂等的核心是“同输入必同输出”,不能把上次半成品和这次新结果叠加。必须覆盖写目标分区,并保证处理顺序确定,否则重跑会产生双倍计数。

为何常见:很多人只关心任务状态是否成功,而不检查结果集合是否一致。

误区特征表存在 Hive 里就行,搞特征平台是过度设计。

正解小团队临时分析可以,生产环境需要版本管理、口径注册、训练服务同源、点查一致性。特征平台是“半成品冷柜”,不是多此一举。

为何常见:在数据量小、链路短时感受不到维护成本,规模变大后才追悔莫及。

误区在线特征和离线特征可以分开计算,反正都是同一个特征名。

正解名字相同不等于口径相同。在线可能用“当前 5 分钟点击”,离线用“近 7 天点击”,时间点选择不同会导致训练和推理分布漂移。必须通过特征平台统一注册定义。

为何常见:特征命名掩盖了窗口、时间点、聚合方式等细节差异。

面试题

Q1. 下列关于离线特征的说法,正确的是?

单选题 · easy

  • A.必须在用户请求时实时计算
  • B.用历史数据提前批量算好← 正确答案
  • C.只适用于非监督模型
  • D.只能在内存中运行

答案:B。离线特征的核心就是“提前备菜”,用历史数据批量算好存起来,而不是在线请求时才计算。中心厨房不会等客人点完菜才去摘菜。

Q2. 批处理计算最典型的产出周期是?

单选题 · easy

  • A.微秒级实时响应
  • B.毫秒级实时响应
  • C.小时级或自然天级← 正确答案
  • D.纳秒级实时响应

答案:C。批处理把一段时间的数据攒成一筐再统一加工,所以产出周期通常是小时级或天级,而不是毫秒、微秒、纳秒级。

Q3. 离线特征重跑时,为什么要保证幂等?

单选题 · easy

  • A.为了减少存储占用
  • B.为了相同输入得到相同输出← 正确答案
  • C.为了让计算速度更快
  • D.为了兼容所有数据格式

答案:B。幂等表示同一批数据无论重跑多少次,结果都完全一致。这样才能放心修复历史分区,不会把旧结果和新结果叠成两份。

Q4. DAG 调度中,下游任务应该何时启动?

单选题 · mid

  • A.到达设定时间立即启动
  • B.所有上游任务成功后启动← 正确答案
  • C.任意一个上游成功后启动
  • D.等待手工点击启动

答案:B。调度依赖本质是数据就绪依赖,下游必须等所有上游都成功后才能启动。如果只看时间或只看单个上游,就可能用到残缺数据。

Q5. 训练与在线推理的特征一致性,最可靠的做法是?

单选题 · mid

  • A.两边都从原始日志重新算
  • B.统一由特征平台存储复用← 正确答案
  • C.在线用缓存离线用 Hive
  • D.用同一个特征名就行

答案:B。最可靠的是让训练和在线推理读同一份特征平台数据,而不是各算各的。特征名相同不代表口径一致,统一冷柜才能避免配方漂移。

Q6. 训练集在时间 t 做特征关联时,应该选择?

单选题 · mid

  • A.选用时间 t 之后的特征
  • B.最接近且不超过 t 的特征← 正确答案
  • C.当天实时计算出来的特征
  • D.任意一个历史版本的特征

答案:B。这是 point-in-time join 的核心:只能取“最接近且不晚于 t”的特征版本。取未来的特征等于偷看答案,会让模型在离线评估时虚高。

Q7. 离线特征平台应该提供哪些能力?

多选题 · mid

  • A.特征版本管理← 正确答案
  • B.训练服务同源← 正确答案
  • C.即席查询支持← 正确答案
  • D.自动生成推荐文案

答案:ABC。特征平台相当于中央冷柜,需要版本管理、训练服务同源、即席查询。自动生成推荐文案是业务功能,不是特征平台的基础职责。

Q8. Lambda 架构中,实时层的作用是?

单选题 · hard

  • A.完全替代批处理层结果
  • B.用低延迟结果修正批处理← 正确答案
  • C.只负责冷数据的备份存储
  • D.只负责历史数据的回填

答案:B。Lambda 架构里批处理层保证准确,实时层用低延迟特征补新鲜度。最终特征由两层融合,而不是让实时层完全替代或只负责存储。

Q9. 哪些做法可能导致离线在线特征不一致?

多选题 · hard

  • A.都从特征平台读同一张表
  • B.训练用历史值在线用未来值← 正确答案
  • C.窗口口径一个 7 天一个 1 天← 正确答案
  • D.特征名相同但聚合函数不同← 正确答案

答案:BCD。从同一张特征表读取会保持一致;训练用未来值、窗口口径不同、聚合函数不同都会造成训练和推理分布漂移。特征名相同并不等于特征定义相同。

Q10. 点查一致(point-in-time join)主要解决哪类问题?

单选题 · extreme

  • A.把批处理改成流处理
  • B.防止未来数据泄漏到训练集← 正确答案
  • C.让在线查询速度更快
  • D.减少特征表存储空间

答案:B。点查一致保证训练时刻 t 只使用 t 之前已经存在的特征,防止未来数据泄漏。它不负责改流、加速查询或压缩存储,而是保证时间语义正确。