从“数据出库“到“模型入库“:DolphinDB 库内机器学习全流程实践

摘要

机器学习落地企业时序场景,模型本身往往不是最贵的部分,最贵的是数据搬运:数据从数据库导出到 Python 环境,做特征工程、训练成模型,再把模型部署成独立服务,预测结果最后还得写回数据库。一个流程四次搬运,每次都附带格式转换、管道维护和口径漂移的风险。DolphinDB 对这条链路的回答是把流程折叠进库内:特征工程复用库内的向量化计算与滑动窗口函数族;经典算法(回归、分类、聚类、降维)以内置函数形式存在,直接吃分布式数据源;深度模型训练可以留在 Python 生态,但通过 Tensor 数据形式与 LibTorch 插件,推理回到数据库内核完成;AI DataLoader 又反向打通了训练取数。官方教程里"流数据引擎实时算特征、订阅特征流触发模型推理"的波动率预测案例,展示了同一套特征代码从离线回测直接走进实时流的完整闭环。本文沿官方文档的线索,把这条"数据不动、模型进库"的路线完整走一遍。


一、引言:机器学习的隐性成本,藏在搬运里

一个典型的企业机器学习项目,数据链路大致是这样的:行情、传感器读数、负荷曲线先躺在时序数据库里;做模型时,先按条件导出一批数据到文件,搬进 Python 环境;用 Pandas 做特征工程,滚动窗口、滞后项、聚合统计;训练出模型后,再把模型打包部署成一个独立的推理服务;线上来新数据时,服务读数据、算特征、出预测,结果最后写回数据库,供报表和下游系统使用。

这条流水线能跑,但每个环节都有税。TB 级数据的导出导入要等;DataFrame 和数据库表之间的格式转换要写胶水代码;训练侧和服务侧各维护一套特征计算逻辑,两边一旦不同步,就会出现训练与服务偏斜(training-serving skew)------线下评估指标很好,上线表现却对不上,排查半天发现问题出在两套代码对"过去十天的均值"这类特征的理解差了一个边界条件。Google 在机器学习工程实践里专门给这类偏斜立过规矩:训练与服务的特征计算,应该用同一套实现。

时序场景把这个问题放大了。时序数据建模的特征,大头是滑动窗口统计:过去 N 行的均值、相关性、波动率,不同分组的窗口各自滚动。在 Python 里对全量数据做这件事,要先排序、分组、再逐窗口遍历,数据量一大内存先扛不住,于是又引出采样、分块、降频这些折中------每个折中都在悄悄改变特征的口径。

DolphinDB 的立场很直接:数据不动,让算法和模型动。这个立场展开成四层:特征工程复用库内本来就擅长的向量化与时序计算;经典机器学习算法做成内置函数,直接对分布式数据源训练;深度模型训练留在 Python 生态里,但推理通过插件回到数据库内核;上线时同一套特征代码从批量计算切换成流式增量计算。本文按这个顺序逐层展开,素材以 DolphinDB 官方文档和教程为据。


二、特征工程:最重的活,本来就是它的主场

时序机器学习项目里,特征工程占掉的工作量通常超过一半。这一步恰恰是时序数据库的看家本领,也是"数据不出库"收益最大的环节。

DolphinDB 的函数库里有一族专门为时序窗口设计的函数:m 系列滑动窗口函数(mavgmsummcorrmstdmrank 等)在流式和批量两种模式下共享同一套实现;prevnextmoveshift 处理滞后与超前对齐;ffillbfill 填充缺失;context by 子句让分组上下文计算直接写进 SQL;量化场景还有 ta 模块提供 RSI、MACD 这类现成技术指标。

官方机器学习教程里的一个分布式逻辑回归例子,能说明特征工程在库内能做到什么程度。数据是 2010 到 2018 年的股票日行情,预测目标是"第二天的收盘价是否高于今天",9 个自变量:开盘价、最高价、最低价、收盘价、当天开盘价与前一天收盘价的差、当天开盘价与前一天开盘价的差、10 天移动平均、相关系数、RSI。整个预处理是一个函数:

暂时无法在飞书文档外展示此内容

值得注意的不只是函数齐全,而是特征和标签在一条语句里对齐生成Targetnext(Close) 向未来借一行构造标签,特征全部用 prevmavg 只向过去看,两者拼在同一张表里,行对齐由引擎保证。做过特征工程的人知道,"标签不小心泄漏了未来的信息"是时序建模最常翻车的地方之一;在一条 SQL 语句里同时完成特征与标签构造,口径关系是显式的,代码审查时一眼能看出谁看过去、谁看未来。

把场景换到电力,这套函数族同样直接:负荷预测的特征------过去 24 小时负荷滑动均值、负荷与温度的滑动相关、同类型日的历史分位------就是 mavgmcorrmpercentile 加一个日期条件;风机振动预警的特征------振动均方根、频带能量的滑动统计------是同一族函数换列名。特征工程的"领域知识"体现在选哪些窗口、哪些指标,而窗口计算的机械部分,库内一行一个。


三、经典模型:算法长在数据源上

特征备好,下一步是训练。DolphinDB 把常用的经典机器学习算法做成了内置函数。按官方教程附录的清单,训练函数覆盖:分类(logisticRegressionrandomForestClassifiergaussianNBmultinomialNBadaBoostClassifierknnglm)、回归(ols/olsExridgelassoelasticNetrandomForestRegressoradaBoostRegressor)、聚类(kmeans)、降维(pca)。其中逻辑回归、随机森林、AdaBoost、广义线性模型、最小二乘(olsEx)、PCA 明确支持分布式训练。

当前版本函数手册的"机器学习"分类比教程附录更宽:正则化回归家族补齐了带交叉验证的 lassoCVridgeCVelasticNetCV,无监督侧有高斯混合模型 gmm,回归侧有核岭回归 kernelRidge,时序统计模型有向量自回归 vectorARgarch,还有高斯过程拟合与预测 gpFit/gpPredict。这个清单还在随版本加宽------对一个数据库来说,这组函数构成了一个够用的经典统计学习工具箱。

比清单更重要的是这些函数的吃法。DolphinDB 的训练函数第一个参数是数据源(data source),由 sqlDS 函数从 SQL 查询生成:sqlDS(<select * from distributedTable>) 会把一个分布式查询按分区切成多个数据源对象,算法函数拿到后在各分区上并行训练。中间不导出文件、不落内存副本。预处理怎么接?用 transDS! 把预处理函数挂到数据源上,每个分区的数据在被训练消费前先流过这个函数。上面那个 preprocess 就是这样接进去的:

暂时无法在飞书文档外展示此内容

四行脚本,完成"分布式表 → 分区并行预处理 → 分布式逻辑回归训练"。教程里对 AAPL 单只股票验证,分类准确率 0.756------对一个演示性的特征集来说,这个数字不重要,重要的是整个过程没有一行代码在搬数据。

训练出来的模型在 DolphinDB 里是一等对象:model.predict(table) 直接对任意同结构表打分,saveModel 把模型持久化成文件,loadModel 随时载回。文件路径、训练时间、数据范围、评估指标这些元信息建一张表登记,就是一个轻量的模型版本管理------不花哨,但够用。

第三方算法也不缺席。XGBoost 插件提供 xgboost::trainxgboost::predictxgboost::saveModelxgboost::loadModel 一组接口,对库内表直接训练和预测;trainxgbModel 参数支持在已有模型基础上增量训练,适合数据滚动到达、模型需要定期续训的场景。基于 libsvm 的 svm 插件同理。同一个库里的 XGBoost 插件教程用同样的 wine 数据训练,测试集准确率 0.963。


四、深度模型:训练可以留在 Python,推理要回数据库

到深度学习这一层,DolphinDB 没有硬造轮子。训练生态在 Python,框架、算子、调参工具链都在那边成熟------承认这个现实,把力气花在两个接口上:训练数据怎么高效地出库,训练好的模型怎么低摩擦地进库。

出库方向是 AI DataLoader ,随 2.00.12 与 3.00.0 版本发布。它解决的问题是:深度学习训练要求数据以 mini-batch 流水线式供给,传统做法是先从数据库导出一份数据文件,转成训练框架的格式,再写 Dataset 类管理分批读取------数据从此多了一份副本,特征更新就要重新导一轮。AI DataLoader 提供 DDBDataLoader,把存储在 DolphinDB 里的因子数据直接转换成 PyTorch、TensorFlow 可识别的 tensor,内部维护多个取数线程分批供给训练。数据量级大时不必单独存储一份训练副本,库里因子更新,下次训练直接取到新的。官方的波动率预测和 Kronos 金融时序模型两个深度学习案例都用它做训练侧的数据供给。

入库方向是 Tensor 数据形式加 LibTorch 插件 。DolphinDB 实现了自己的 Tensor 数据形式------按官方教程的描述,实现方式类似 Torch 的 strided tensor:一块连续内存 storage 加形状、步长等元信息。tensor 函数把库内数据形式转换成张量:向量转一维,矩阵和表转二维,向量的元组、矩阵的元组逐级嵌套上去就是三维、n 维。

LibTorch 插件则在 3.00.1 及以上版本的 Shark(GPU 版 DolphinDB)中通过插件市场安装,提供 CPU 与 GPU 两个版本:

暂时无法在飞书文档外展示此内容

用法是两个接口:LibTorch::load 加载模型文件返回句柄,LibTorch::predict 拿张量输入做推理。模型文件要求 TorchScript 格式,Python 侧一行 torch.jit.trace(model, example_input) 就能把普通 PyTorch 模型转出来。

官方教程的 LSTM 股价预测案例值得完整看一遍,因为它展示了"推理回库"之后链路短到什么程度。数据是某标的一年的收盘价,直接在库内读入:

暂时无法在飞书文档外展示此内容

预处理、转张量、推理,全部是库内脚本:先做 -1,1 归一化,用 moving 函数按 20 大小的滑动窗口把序列展开成三维输入,tensor() 转成张量,然后:

暂时无法在飞书文档外展示此内容

预测输出做反归一化,得到未来收盘价的预测值。整个过程里,Python 只出现了两次:一次是当初训练模型,一次是 torch.jit.trace 那行转换。数据没有出过库。对比插件推出之前的流程------教程里有一张对比图说得很直白:此前需要通过 Python API 把数据取到 Python 环境,用 PyTorch 做预测,再把结果送回来;现在模型部署在数据库内核里,数据入库即推理,没有一次外部服务的网络往返。官方 AI 页面把这称为"嵌入式深度学习推理引擎",并给出支持清单:PyTorch、TensorFlow、XGBoost、LightGBM 等主流框架模型可以在库内完成推理,配合 GPU 并行加速。

一句话概括这一层的分工:训练在算力与生态所在处,推理在数据所在处。两端各做自己最擅长的事,中间靠 TorchScript 文件和 AI DataLoader 这对接口缝合,缝合线比"四处搬运"的传统链路短得多。


五、上线:流批一体,从回测直接走进实时流

模型训好、验证过,最后一关是上线。传统流程里这是重活:训练时用 Python 批量算特征,上线时要用另一套技术栈重写在数特征,两边口径对齐靠人肉,对不齐就是训练与服务偏斜。

DolphinDB 的流批一体在这里兑现。同一套 m 系列窗口函数、同一套特征代码,对历史数据是批量计算,对实时流是增量计算,逻辑一致由同一份实现保证。官方"股票实时波动率预测"教程给出的在线架构是这条管线的标准形态:

  1. 行情快照实时写入流表 SnapshotStream;
  2. 流数据时间序列引擎订阅快照流,滚动计算特征,结果写入特征流表 aggrFeatures10min;
  3. 订阅特征流表,新特征一到就触发 LibTorch::predict 实时推理;
  4. 预测结果落库,供监控与下游使用。

训练时用 AI DataLoader 从库里取同样的特征喂给 PyTorch,上线后特征改由流引擎增量产出、LibTorch 在库内打分------特征定义自始至终是同一份代码。教程原文点出了这个闭环的要害:每当特征流表有新数据,模型推理随之触发,无需人工干预。

这条管线不挑行业。金融侧是波动率预测,工业侧的教程同样现成:物联网实时数据异常率预警案例用内置 knn 构建回归模型,学到设备读数的正常模式,对实时流入的传感器数据持续输出异常率,超过阈值即预警。电网负荷预测、风机振动监测,换的是数据列和阈值,管线骨架不变。

模型生命周期也闭合在库内:saveModel/loadModel 管持久化,XGBoost 的增量训练管滚动续训,元数据表管版本与指标。配合定时任务框架,"每天收盘后用新数据续训、评估、决定是否切换上线"可以固化成一组脚本------一个朴素但完整的 MLOps 循环,没有引入任何额外平台。


六、结尾:AI 版图上的计算层

把这个系列的文章摆在一起看,DolphinDB 的 AI 版图在三篇文章里各占一层:DolphinX 系列讲的是交互层,让大模型和 Agent 能查数、算指标、执行分析;向量引擎与 TextDB 讲的是检索层,让语义和词法检索长在时序数据旁边;这一篇讲的是计算层------预测、分类、异常检测这些数值智能,训练与推理都不必离开数据。

三层拼起来是一个完整的面:会对话、会检索、会算。而无论哪一层,底层的支点都是同一件事------数据不动。RAG 的上下文在数据原生地拼装,Agent 的工具直接操作库内对象,机器学习的特征与推理在库内闭环。

回到开头那个判断:机器学习落地企业,瓶颈常常不在模型,在管道。模型是标准件,管道是每家企业的手工活。把管道缩短到零------特征不出库、训练数据不出库(AI DataLoader 直取)、推理不出库(LibTorch 进内核)------是数据库能对机器学习做出的最实在的贡献。DolphinDB 用内置算法、Tensor、LibTorch、AI DataLoader 和流批一体这一组互相咬合的部件,把这条路线走通了。对被数据搬运困扰的团队来说,值得照着官方教程亲手走一遍:从一条 update 语句生成特征开始,到流表上触发第一次实时推理结束------全程数据没有离开过库,这个体验本身就是最有说服力的论证。

相关推荐
Sagittarius_A*1 小时前
【好靶场】SQL注入-时间盲注
数据库·sql
神明不懂浪漫2 小时前
【第二章】库、表、增删改查操作
开发语言·数据库·经验分享·笔记
其实防守也摸鱼2 小时前
OpenClaw 深度解析:从原理到实战的完整指南
运维·服务器·数据库·github·copilot
hzp6662 小时前
doris学习6:参数调优
数据库·doris·参数·数据库调优
盟道科技3 小时前
小程序电商订单超时自动取消的三种实现方案:定时扫描、Redis 过期监听、延迟消息对比与生产落地
数据库·redis·小程序
剑锋所指,所向披靡!3 小时前
MySQL存储引擎
数据库·mysql
reasonsummer3 小时前
【办公类-146-05】20260901《一分园、二分园四大教育》(优化版:标题excle+复制AI文字+Python占位符录入)
开发语言·数据库·c#
2301_800954993 小时前
关系型数据库与非关系型数据库详解
数据库·nosql
崖边看雾3 小时前
MySQL——SQL 经典练习题:学生选课成绩查询(附详细注释)
大数据·数据库·sql·mysql