Hotdry.
ai-systems

ShapedQL 混合查询规划器设计:向量检索与标量计算的统一执行模型

深入解析 ShapedQL 如何将向量检索、近邻搜索与标量过滤、ML 评分统一编译为混合执行计划,涵盖算子融合调度与结果归并策略的工程化实现。

在传统的推荐与搜索系统架构中,工程团队通常需要维护一套被戏称为「弗兰肯斯坦栈」的技术组合:向量数据库负责语义检索、特征存储系统承载实时上下文、数千行 Python 代码处理业务逻辑与排序规则。当产品经理提出「在下单概率高的商品中,排除用户已购买的类目,并保证结果多样性」这样的需求时,工程师需要在三个系统之间反复倒腾数据,调试成本呈指数级增长。ShapedQL 的核心设计目标,正是将这种碎片化的计算拓扑压缩为单一 SQL 语句,并在查询规划层实现向量检索与标量计算的深度融合。本文将从执行引擎的角度,剖析 ShapedQL 如何在查询编译阶段完成混合算子的统一调度与结果归并。

混合查询的语义分析阶段

当用户提交一条 ShapedQL 查询时,规划器的首要任务是对查询进行语义分类,识别其中涉及的向量操作与标量操作边界。以典型的推荐查询为例:

SELECT video_id, creator_name
FROM trending_videos(),
     following_network("$user_id")
WHERE NOT previously_watched("$user_id")
ORDER BY p_watch_time(user, item)
REORDER BY diversity(creator_name)

这条查询中同时包含了混合检索(trending_videos 与 following_network 的多源融合)、状态过滤(previously_watched 依赖用户历史上下文)、标量排序(p_watch_time 的 ML 评分)以及列表级重排(diversity 函数)。传统系统会将这些阶段拆分到独立服务,由应用层编排执行顺序,这不仅引入了序列化开销,也丧失了跨阶段优化的可能性。ShapedQL 的语义分析器会将上述查询分解为四类算子:向量检索算子负责从嵌入空间获取候选集;布尔过滤算子应用业务约束;评分算子调用实时 ML 模型进行逐项打分;重排算子在列表层面优化整体质量。关键的设计决策在于,规划器在语义分析阶段就会建立算子间的数据依赖图,而非简单地将各阶段串行连接。这种依赖导向的计划生成方式,为后续的算子融合与并行调度奠定了基础。

向量 - 标量混合算子的物理计划生成

传统数据库系统将向量搜索实现为关系引擎的插件层,ANN 索引的调用发生在查询执行的某一阶段,产生的中间结果需要物化后再传递到下一阶段。这种设计的问题在于,向量检索产生的候选集可能非常庞大(如返回 top-1000),而后续的过滤和评分操作又可能将大部分候选过滤掉,导致大量无效计算。ShapedQL 采用的策略是在物理计划生成阶段,将向量检索算子与后续的过滤、评分算子进行融合,生成统一的混合算子。

具体而言,规划器会在向量检索算子内部嵌入早期过滤逻辑。当 ANN 索引返回候选向量时,系统会立即应用标量谓词进行剪枝,而不是等到检索完成后统一过滤。这种「检索即过滤」的策略显著减少了传递到评分阶段的数据量。物理计划的生成过程遵循两个原则:其一是代价估算的跨阶段统一,规划器在评估不同执行策略时,会将向量检索的 I/O 成本、过滤的网络传输成本、ML 评次的计算成本统一纳入考量,而非为每个阶段独立优化;其二是算子接口的语义对齐,向量检索算子与标量算子共享相同的数据 Schema 定义,使得下游算子无需感知上游究竟是向量引擎还是传统表扫描。

在多源检索场景下(如同时从 trending_videos 和 following_network 获取候选),规划器需要处理多个向量检索算子的结果合并问题。ShapedQL 支持两种合并策略:Score Normalization 策略会在合并前对各源的相似度分数进行归一化处理,避免单一数据源的分数尺度主导最终排序;Cascade 策略则会先在各源内部完成完整的过滤 - 评分 - 重排流水线,再在最终阶段进行交叉源合并。规划器会根据候选集的规模、各源的分数分布特征以及查询的延迟约束,自动选择最优的合并策略。

运行时调度与算子融合执行

混合执行计划的实际执行依赖于 ShapedQL 的运行时调度器。与传统的 Volcano 模型(每处理一行数据就进行一次算子间切换)不同,ShapedQL 采用微批处理模式,每次处理一批候选向量后统一传递到下游算子。这种设计有两方面考量:一方面,现代 CPU 的 SIMD 指令在处理批量数据时效率更高,ML 模型的批推理也能充分利用 GPU 并行能力;另一方面,减少算子间的切换频率可以显著降低函数调用开销和内存分配压力。

运行时调度器还负责处理用户上下文数据的注入。在 ShapedQL 的模型中,用户特征并非简单地作为查询参数传入,而是在整个查询执行过程中持续可用。当执行 previously_watched 过滤时,系统会从特征存储中拉取用户的历史行为序列,并在过滤算子中完成模式匹配;当执行 p_watch_time 评分时,同一用户特征会被缓存并复用于所有候选的评分计算。调度器会在第一次上下文访问时触发异步预取,并在后续算子执行时确保上下文数据已就绪,从而隐藏网络延迟。

状态管理是运行时系统的另一个关键设计点。传统的搜索系统是「无状态」的,每个请求独立处理,不保留任何中间结果。而 ShapedQL 的执行计划中可能包含跨请求的状态依赖,例如 previously_watched 过滤需要查询用户的历史行为。调度器通过维护用户级别的状态缓存,并在 TTL 过期前主动刷新,确保状态依赖不会成为性能瓶颈。同时,调度器会监控状态缓存的命中率,当命中率持续低于阈值时,会动态调整缓存策略或触发后台预热流程。

结果归并策略与延迟控制

当查询包含 REORDER BY 阶段时,系统需要在完成所有候选的评分计算后,进行额外的列表级优化。diversity 这样的重排函数通常需要全局视角的信息(如已选结果的类目分布),无法在评分阶段并行处理。ShapedQL 的归并策略采用了两阶段处理模式:第一阶段完成所有候选的并行评分,生成带有类别标签的排序列表;第二阶段应用重排算法,在保持评分相对顺序的前提下,注入多样性约束。

延迟控制是生产环境中的核心约束。ShapedQL 规划器会在编译阶段为每个算子估算执行延迟,并在生成计划时进行端到端的延迟预算检查。如果发现某个执行计划的预估延迟超过 SLA 要求,规划器会自动启用降级策略,例如减少检索候选数量、降低 ML 模型的精度等级,或跳过 REORDER BY 阶段。这种编译时的延迟保证,相比运行时动态调整,能够提供更稳定的用户体验。

从实际部署效果来看,采用 ShapedQL 的团队通常可以将原有的 3000+ 行代码压缩到约 30 行声明式 SQL,迭代周期从周级别缩短到天级别。更重要的是,查询执行的可观测性大幅提升:当某个结果排序异常时,工程师可以直接查看执行计划,定位到具体是向量检索阶段还是评分阶段的参数配置问题,而非在多个服务之间大海捞针。

资料来源:Shaped 官方发布公告及产品文档、CHASE 混合查询引擎研究论文。

查看归档