SQLFlow 源码走读:从扩展 SQL 语法到 gRPC 训练服务与 Python 执行器的完整链路 人工智能机器学习后端编译器【免费下载链接】sqlflowBrings SQL and AI together.项目地址https://gitcode.com/gh_mirrors/sq/sqlflow点击查看免费下载本文以 SQLFlow 官方 Code Walkthrough 为骨架结合当前仓库源码系统梳理 SQLFlow 的整体架构与核心执行链路用户如何在 Jupyter Notebook 或命令行中编写TO TRAIN/TO PREDICT扩展 SQL 语句gRPC 服务端如何依次经过解析、校验、代码生成与执行四个环节最终把 SQL 程序翻译成调用 TensorFlow / XGBoost 的 Python 程序并探讨其可扩展设计与作业管理方案的演进含 Argo 工作流模式。读完本文你将掌握 SQLFlow 端到端的工作原理并能在源码层面定位每一步对应的实现文件。用户体验用 SQL 直接写机器学习SQLFlow 允许用户在 Jupyter Notebook通过 SQLFlow magic 插件或命令行工具中编写带扩展语法的 SQL 程序。扩展语法的精髓在于把机器学习任务写成一条 SQL 语句。例如下面这条语句训练一个名为DNNClassifier的 TensorFlow 模型DNNClassifier是派生自tf.estimator.Estimator的 Python 类SELECT * FROM a_table TO TRAIN DNNClassifier WITH learning_rate0.01 INTO sqlflow_models.my_model;而下面这条语句则使用训练好的模型进行预测并把结果写入b_table.predicted_label列SELECT * FROM b_table TO PREDICT b_table.predicted_label USING sqlflow_models.my_model;README 中给出了更完整的示例参见 README.mdsqlflow SELECT * FROM iris.train TO TRAIN DNNClassifier WITH model.n_classes 3, model.hidden_units [10, 20] COLUMN sepal_length, sepal_width, petal_length, petal_width LABEL class INTO sqlflow_models.my_dnn_model; ... Training set accuracy: 0.96721 Done trainingsqlflow SELECT * FROM iris.test TO PREDICT iris.predict.class USING sqlflow_models.my_dnn_model; ... Done predicting. Predict table : iris.predict这里有一个非常关键的设计点也是理解 SQLFlow 系统实现的基础上述语句中TO TRAIN、TO PREDICT等扩展关键字之前的全部内容本身就是一条标准 SQL 语句。正是这一设计大幅简化了 SQLFlow 系统的实现——标准的 SQL 部分可以被原样交给 SQL 引擎去解析和执行SQLFlow 只需要处理扩展关键字的语义。系统实现总览SQLFlow 对两类语句采取完全不同的处理路径标准 SQL 语句SQLFlow 直接把它转发proxy给 SQL 引擎执行并把查询结果重定向回用户端。扩展语法语句SQLFlow 把它翻译成一个 Python 程序即文档中所称的 submitter / code generator 产物。在 MVP最小可行产品阶段生成的 Python 程序做两件事把标准 SQL 部分SELECT交给 MySQL然后在一个训练循环里读取查询结果并训练模型。文档明确提出了后续的扩展方向接入更多 SQL 引擎如 Oracle、Hive、SparkSQL并生成调用分布式 TensorFlow、PyTorch、XGBoost 等更多机器学习框架的程序。当前仓库中这些方向大多已经落地详见下文可扩展性一节。SQLFlow 是一个 gRPC 服务从架构上看SQLFlow 本身是一个 gRPC 服务器可同时连接多个客户端。文档中提到的典型客户端包括pysqlflowJupyter Notebook 服务器的 SQLFlow 插件magic 命令命令行客户端即仓库中的 go/cmd/sqlflow/main.go它通过 gRPC 与服务端交互支持交互式 REPL 和-e执行字符串、-f执行文件等模式。两者的交互模型如下Jupyter Notebook ---(SQL statements)-- SQLFlow gRPC server (SQLFlow magic command) --(a stream of messages)--gRPC 服务的 protobuf 定义位于 go/proto/sqlflow.proto核心服务接口为rpc Run (Request) returns (stream Response)执行 SQL 语句返回一个Response流。每个Response要么是表头Head、一行数据Row要么是一条日志消息Message还可能是EndOfExecution一次执行结束或JobArgo 模式下提交的工作流 ID。rpc Fetch (FetchRequest) returns (FetchResponse)以轮询方式获取作业的阶段与日志Argo 工作流模式使用。表头和行通常来自标准 SQL 语句如SELECT、DESCRIBE日志消息通常来自生成的 Python 程序运行过程。在 go/proto/response.go 中可以看到Head、Row的编码细节每一行数据通过google.protobuf.Any承载覆盖 nil、bool、各类整型、浮点、字符串、字节数组与时间戳等类型。从命令行客户端的实现go/cmd/sqlflow/main.go可以看到完整的客户端视角通过-s/--sqlflow-server指定服务端地址默认读取环境变量SQLFLOW_SERVER默认端口50051通过-d/--data-source指定数据源默认读取SQLFLOW_DATASOURCE通过-c/--cert-file指定证书默认读取SQLFLOW_CA_CRT支持 TLS客户端调用client.Run(ctx, req)获得响应流由 tablewriter 渲染成 ASCII 表格输出。SQLFlow gRPC 服务端的执行流水线当 gRPC 服务端通过一次Run调用收到一批 SQL 语句后对应实现见 go/sqlflowserver/sqlflowserver.go 的Run方法会对每条语句依次执行以下四个步骤parser解析器语法定义见 go/parser/extended_syntax_parser.y生成解析结果verifier校验器语义校验见 go/verifier/verifier.go根据解析结果验证语义code generator代码生成器见 go/codegen从解析结果生成一个 Python 程序即 submitterexecutor执行器见 go/sql/executor_ir.go在本地运行这个 submitter。其中第 3、4 步仅针对扩展语法语句对于标准语法语句服务端直接把它代理给 SQL 引擎执行。第 1 步协作式解析解析是整个链路的第一步。SQLFlow 的解析器采用协作式设计标准 SQL 部分交给第三方解析器扩展语法部分由自己的语法文件处理。go/parser/sqlflow_parser.go 中的Parse函数体现了这一机制它循环调用thirdPartyParse解析标准 SQL 段依据 dialect 选择 MySQL、Hive、MaxCompute 等第三方解析器见 go/parser/external一旦遇到TO TRAIN、TO PREDICT等扩展关键字再调用parseFirstSQLFlowStmt解析扩展语法部分并将两者拼接为一条完整的SQLFlowStmt。该结构体定义于同一文件同时保存Original完整原始语句与SQLFlowSelectStmt扩展部分解析结果IsExtendedSyntax()用于判断语句是否包含扩展语法。go/parser/extended_syntax_parser.ybison/yacc 语法文件则定义了扩展语法的全部子句从源码结构看扩展语法目前支持TrainClauseTO TRAIN含 Estimator、训练属性、COLUMN 子句、LABEL、USING预训练模型、INTO保存位置PredictClauseTO PREDICT、ExplainClauseTO EXPLAIN、EvaluateClauseTO EVALUATEOptimizeClauseTO MAXIMIZE/MINIMIZE数学规划、RunClauseTO RUN自定义任务、ShowTrainClauseSHOW TRAIN。第 2 步语义校验校验器位于 go/verifier/verifier.go。核心函数Verify的做法是把标准 SELECT 部分真实下发到数据库执行取回 1 行样本FetchSamples必要时自动追加LIMIT借助rows.ColumnTypes()获取字段类型返回FieldTypes字段名 → 数据库类型名映射并检查是否有重名字段。VerifyColumnNameAndType还负责校验预测语句的字段与类型必须与训练语句一致除 label 外为预测的正确性提供保障。从 go/sql/executor_ir.go 的initializeAndCheckAttributes还可以看到另一层属性校验对 Train 语句会按模型类型分别调用xgboost.InitializeAttributes、pai.InitializeKMeansAttributes或tensorflow.InitializeAttributes来初始化并检查超参数如train.batch_size、train.epoch、validation.metrics等定义见 go/codegen/tensorflow/codegen.go。第 3 步与第 4 步代码生成与执行ResolveSQLProgram见 go/sql/executor_ir.go把解析结果转换为 IR中间表示见 go/ir扩展语法按语句类型生成TrainStmt、PredictStmt、ExplainStmt、EvaluateStmt、OptimizeStmt、RunStmt、ShowTrainStmt标准语句则包装为NormalStmt。随后由 executor 执行。执行器的接口定义在 go/executor/executor.go 的Executor接口中覆盖ExecuteQuery、ExecuteTrain、ExecutePredict、ExecuteExplain、ExecuteEvaluate、ExecuteOptimize、ExecuteRun、ExecuteShowTrain等全部语句类型New()依据环境变量SQLFLOW_submitter或 Session 中的 submitter 字段选择具体实现default/local对应pythonExecutor另有pai、pai_local、alisa、alps等平台执行器。执行器调用 Go 标准库os/exec启动 submitter 进程捕获其 stdout 与 stderr并通过管道把结果回传给 gRPC 客户端。这里值得注意的设计是打印日志是 submitter 自身的职责——它需要把日志打到 stdout/stderr 上。Go 端通过 go/pipe/pipe.go 提供的进程内同步管道把日志逐行写入 gRPC 响应流logChanWriter见 go/executor/executor.go负责按行切分并转发。运行 Python 程序的具体方式见 go/executor/cmd.go 的sqlflowCmd它按环境自动选择本地已安装 Python TensorFlow 数据库驱动时直接以python -u运行否则若存在 Docker则以docker run --rm挂载工作目录并执行sqlflow/sqlflow镜像仅有 Python 时直接运行适用于预装 Python 的服务器镜像。最小可行产品MVPSQLFlow 实际做了什么文档指出MVP 中代码生成器生成的 Python 程序由两部分组成把扩展语句中的标准 SELECT 部分通过 ODBC 抛给 MySQL一个循环读取 SELECT 语句的运行输出训练模型或用训练好的模型做预测。训练部分调用 TensorFlow 来更新TO TRAIN子句中指定模型的参数。这一设计在当前仓库的代码生成模板中有清晰体现go/codegen/tensorflow/template_train.go 生成训练 Python 程序其结构为import tensorflow as tf、从runtime.tensorflow.train导入train、导入DNNClassifier等 estimator、构造feature_column_names/feature_metas/label_meta等元数据最终调用train(...)go/codegen/tensorflow/template_pred.go 生成预测程序同样携带特征列元数据调用runtime.tensorflow.predict的pred。执行训练时pythonExecutor.ExecuteTrain见 go/executor/executor.go按模型类型调用xgboost.Train或tensorflow.Train生成代码 →runProgram运行 →SaveModel把模型保存到INTO指定的位置。预测时ExecutePredict还会先用createPredictionResultTable建好结果表再运行生成的预测代码。标准查询语句则由ExecuteQuery见 go/executor/sql_stmt.go 的runNormalStmt处理通过isQuery粗略判断语句是查询SELECT无INTO、SHOW CREATE/DATABASES/TABLES、DESC、EXPLAIN还是写操作分别走runQuery与runExec路径。可扩展性用更多代码生成器接入更多引擎与框架文档指出通过编写更多代码生成器SQLFlow 可以扩展支持更多 SQL 引擎如 Hive、Oracle和机器学习工具包如 PyTorch、XGBoost并运行在各种计算平台上。文档当时设想的代码生成器示例包括codegen_distributed_tf.go生成类似 MVP 但运行分布式 TensorFlow 训练作业的 submitter 程序codegen_kubernetes_tf.go在 Kubernetes 集群上启动分布式 TensorFlow 作业而不是在 SQLFlow gRPC 服务所在容器内本地运行codegen_gcloud_pytorch.go生成在 Google Cloud 上调用 PyTorch 而非 TensorFlow 训练的程序。从当前仓库的源码结构看这一可扩展设计已经大规模落地代码生成器目录 go/codegen 下已存在tensorflow、xgboost、pai阿里云 PAI 平台含 KMeans、随机森林等、optimize数学规划、experimentalCouler / 新 IR 路径等多个代码生成器执行器层面支持default/local、pai、pai_local、alisa、alps等 submittergo/executor/executor.go数据库接入层面支持 MySQL、Hive、MaxCompute 等go/database、go/sql/session.goPython 运行时 python/runtime 下提供了 tensorflow、xgboost、optimize 等对应的执行模块。作业管理Job Management与 Argo 工作流模式文档指出了 gRPC 接口设计中的一个关键假设客户端如 Jupyter Notebook与 SQLFlow 服务端之间的连接在训练程序运行期间必须保持存活。这个假设在多数场景下是合理的——即使数据科学家关闭浏览器、断开与 Jupyter Notebook 服务器的连接Jupyter 到 SQLFlow 的连接仍可能保持。但若 Jupyter Notebook 服务器运行在用户笔记本上且进程被杀gRPC 服务端就无法再把消息流回客户端导致 submitter 失败。文档提出的解决方案是把 gRPC 接口改为——一个提交作业并立即返回的方法以及另一个给定作业 ID 获取最近一批消息的方法。这一设计在当前仓库中已经实现即 go/proto/sqlflow.proto 中的Fetch接口与Job消息配合 Argo 工作流模式服务端入口 go/cmd/sqlflowserver/main.go 通过-argo-mode标志选择注册SubmitWorkflow而不是本地执行路径RunSQLProgram监听端口默认50051可通过-port调整并支持-ca-crt/-ca-key启用 TLSSubmitWorkflow见 go/sqlflowserver/sqlflowserver.go把 SQL 程序编译为 Argo workflow YAML或 Couler 提交代码通过 go/workflow/argo 的Submit提交到 Kubernetes随后立即把工作流 ID 作为Job消息返回给客户端客户端随后以轮询方式调用Fetchgo/workflow/argo/fetch.go 的Fetch根据 Job ID 读取 Argo 工作流状态与 Pod 日志输出形如Step [1/3] Execute Code: ...、Step [1/3] Status: Running的进度消息直至工作流完成。详细的 Argo 工作流设计参见 doc/design/argo_workflow_on_sqlflow.md。这一演进正好呼应了文档中We will make a design for that soon的规划也让 SQLFlow 从必须保持长连接的本地执行模型走向了可在 Kubernetes 上可靠运行、可断点拉取日志的工作流模式。赞分享人工智能机器学习后端编译器【免费下载链接】sqlflowBrings SQL and AI together.项目地址https://gitcode.com/gh_mirrors/sq/sqlflow点击查看免费下载相关推荐TiDB 源码阅读之 Executor从 SQL 语句到执行器的完整链路解析TiDB 源码阅读之 Executor从 SQL 语句到执行器的完整链路解析 本文是 Go 夜读第 47 期「TiDB 源码阅读之 Executor」分享的深文档教程从 SELECT 到训练流水线SQLFlow 扩展 SQL 语法的设计与实现详解从 SELECT 到训练流水线SQLFlow 扩展 SQL 语法的设计与实现详解 本文以 SQLFlow 仓库中的总体设计文档 doc/design/synt人工智能机器学习后端编译器MyBatis 动态 SQL 源码解析从 DynamicSqlSource 到 SQL 执行全链路MyBatis 动态 SQL 源码解析从 DynamicSqlSource 到 SQL 执行全链路 MyBatis 的 if 、 trim 、 wher文档教程知识库上一篇Laravel依赖注入容器掌握现代PHP应用的核心架构下一篇深入解析PHP源码php-src揭秘Zend引擎的核心架构与实现原理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考