大模型与数据分析:探索Text-to-SQL(上):https://developer.aliyun.com/article/1480726
DIN-SQL
2022年底,ChatGPT爆火,凭借LLM强大的逻辑推理、上下文学习、情景联系等特点,按理说LLM应该可以超过seq2seq、BERT等系列的模型,但是使用少样本、零样本提示方法用LLM解决NL2SQL问题效果却比不上之前的模型。今天分享的这篇来自NLP顶级会议的论文解决了这个问题:如何改进Prompt让LLM超越之前的方法,并让LLM在Spider数据集上霸榜。
论文原文链接:DIN-SQL: Decomposed In-Context Learning of Text-to-SQL with Self-Correction(地址:https://arxiv.org/abs/2304.11015)
摘要:我们研究将复杂的文本到 SQL 任务分解为更小的子任务的问题,以及这种分解如何显着提高大型语言模型 (LLM) 在推理过程中的性能。目前,在具有挑战性的文本到 SQL 数据集(例如 Spider)上,微调模型的性能与使用 LLM 的提示方法之间存在显着差距。我们证明 SQL 查询的生成可以分解为子问题,并且这些子问题的解决方案可以输入到 LLM 中以显着提高其性能。我们对三个 LLM 进行的实验表明,这种方法持续将其简单的小样本性能提高了大约 10%,将 LLM 的准确性推向 SOTA 或超越它。在 Spider 的 Holdout 测试集上,执行准确度方面的 SOTA 为 79.9,使用我们方法的新 SOTA 为 85.3。我们的情境学习方法比许多经过严格调整的模型至少高出 5%。
该论文提出了一种基于少样本提示Few-shot Prompt的新颖方法,将Text-to-SQL的任务分解为多个步骤。
编写SQL查询的思维过程可以分解为:
- 检测与查询相关的数据库表和列
- 识别更复杂查询的一般查询结构(例如分组、嵌套、多重联接、集合运算等)
- 制定任何可以识别的过程子组件
- 根据子问题的解决方案编写最终查询。
基于这个思维过程,将文本到SQL任务的方法分解为4个模块:
- 模式链接
- 查询分类和分解
- SQL生成
- 自我修正
如果问题被简单地分解到正确的粒度级别,LLM就有能解决所有的这些问题。
▐ Schema Linking Module
模式链接负责识别自然语言查询中对数据库模式和条件值的引用。它被证明有助于跨领域的通用性和复杂查询的综合(Lei 等人,2020),使其成为几乎所有现有文本到 SQL 方法的关键初步步骤。在我们的案例中,这也是LLM失败次数最多的一个类别(图 2)。我们设计了一个基于提示的模式链接模块。提示包括从 Spider 数据集的训练集中随机选择的 10 个样本按照思路链模板(Wei 等人,2022b),提示以“让我们一步一步思考”开头,正如 Kojima 等人(2022)建议的那样。对于问题中每次提到的列名,都会从给定的数据库模式中选择相应的列及其表。还从问题中提取可能的实体和单元格值。如下图显示模式链接模块的输入和输出的示例。
▐ Classification & Decomposition Module
对于每个连接,都有可能未检测到正确的表或连接条件。随着查询中联接数量的增加,至少一个联接无法正确生成的可能性也会增加。缓解该问题的一种方法是引入一个模块来检测要连接的表。此外,一些查询具有过程组件,例如不相关的子查询,它们可以独立生成并与主查询合并。
为了解决这些问题,我们引入了查询分类和分解模块。该模块将每个查询分为三类之一:简单、非嵌套复杂和嵌套复杂。easy 类包括无需连接或嵌套即可回答的单表查询。非嵌套类包括需要连接但没有子查询的查询,而嵌套类中的查询可以需要连接、子查询和集合操作。类标签对于我们的查询生成模块很重要,该模块对每个查询类使用不同的提示。除了类标签之外,查询分类和分解还检测要为非嵌套和嵌套查询以及可能为嵌套查询检测到的任何子查询连接的表集。如下图显示分类和分解模块的输入和输出的示例:
▐ SQL Generation Module
随着查询变得更加复杂,必须合并额外的中间步骤来弥合自然语言问题和 SQL 语句之间的差距。这种差距在文献中被称为不匹配问题(Guo et al, 2019),对 SQL 生成提出了重大挑战,这是因为 SQL 主要是为查询关系数据库而设计的,而不是表示自然语言中的含义。
虽然更复杂的查询可以从思路链式提示中列出中间步骤中受益,但此类列表可能会降低更简单任务的性能(Wei 等人,2022b)。在相同的基础上,我们的查询生成由三个模块组成,每个模块针对不同的类别。
对于我们划分的简单类别中的问题,没有中间步骤的简单的少量提示就足够了。此类示例 Ej 的演示遵循格式 ,其中 Qj 和 Aj 分别给出英语和 SQL 的查询文本,Sj 表示模式链接。
我们的非嵌套复杂类包括需要连接的查询。我们的错误分析(第3节)表明,在简单的几次提示下,找到正确的列和外键来连接两个表对于法学硕士来说可能具有挑战性,特别是当查询需要连接多个表时。为了解决这个问题,我们采用中间表示来弥合查询和 SQL 语句之间的差距。文献中已经介绍了各种中间表示。特别是,SemQL(Guo et al, 2019)删除了在自然语言查询中没有明确对应项的运算符 JOIN ON、FROM 和 GROUP BY,并合并了 HAVING 和 WHERE 子句。NatSQL(Gan 等人,2021)基于 SemQL 构建并删除了集合运算符。作为我们的中间表示,我们使用 NatSQL,它与其他模型结合使用时显示出最先进的性能 (Li et al, 2023a)。非嵌套复杂类的示例 Ej 的演示遵循格式 ,其中 Sj 和 Ij 分别表示第 j 个示例的模式链接和中间表示。
最后,嵌套复杂类是最复杂的类型,在生成最终答案之前需要几个中间步骤。此类可以包含不仅需要使用嵌套和集合操作(例如 EXCEPT、UNION 和 INTERSECT)的子查询,而且还需要多个表连接的查询,与上一个类相同。为了将问题进一步分解为多个步骤,我们对此类的提示的设计方式是LLM应首先解决子查询,然后使用它们生成最终答案。此类提示遵循格式 , Ij, Aj>,其中k表示子问题的数量,Qji和Aji分别表示第i个问题-第一个子问题和第i个子查询。和之前一样,Qj 和 Aj 分别表示英语和 SQL 的查询,Sj 给出模式链接,Ij 是 NatSQL 中间表示。
▐ Self-correction Module
生成的 SQL 查询有时可能会缺少或冗余关键字,例如 DESC、DISTINCT 和聚合函数。我们对多个 LLM 的经验表明,这些问题在较大的 LLM 中不太常见(例如,GPT-4 生成的查询比 CodeX 生成的查询具有更少的错误),但仍然存在。为了解决这个问题,我们提出了一个自我纠正模块,指示模型纠正这些小错误。
这是在零样本设置中实现的,其中仅向模型提供有错误的代码,并要求模型修复错误。我们为自我纠正模块提出了两种不同的提示:通用和温和。通过通用提示,我们要求模型识别并纠正“BUGGY SQL”中的错误。另一方面,温和提示并不假设 SQL 查询有错误,而是要求模型检查任何潜在问题,并提供有关要检查的子句的一些提示。我们的评估表明,通用提示可以在 CodeX 模型中产生更好的结果,而温和的提示对于 GPT-4 模型更有效。除非另有明确说明,否则 DINSQL 中的默认自我更正提示对于 GPT-4 设置为“温和”,对于 CodeX 设置为“通用”。
▐ 效果对比
spider的测试集上的执行精度(EX)和逻辑匹配精度(EM),使用GTP-4实现了最高的执行精度,使用CodeX Davinci实现了第三高的执行精度。
指标体系
▐ 什么是指标体系
我们在讨论一个人是否健康的时候,常常会说出一些名词:体温、血压、体脂率等。当一份体检报告出具时,上面会罗列数十项体检指标,而将这些指标综合起来考量,大概就能了解一个人的健康状况。若其中一向指标飘红,那就说明身体的某项机能出了问题。
同样,判断一家公司的经营情况,可以通过指标对业务进行监控,可往往一个指标没办法解决复杂的业务问题,这就需要使用多个指标从不同维度来评估业务,也就是使用指标体系。
指标体系(Indication System)就是从不同维度梳理业务,把指标有系统地组织起来,形成的一个整体。
▐ 指标的理解
理解指标必须明确两个重要的概念【度量】和【维度】,一个正确的指标必须包括度量和维度。“性别”是维度,“男性数量”,“女性数量”,“男性占比”,“女性占比”是度量;“城市”是维度,“一线城市占比”,“省会城市数量”,“GDP 大于 1 万亿的城市数量”是包含了维度和度量的指标。
指标都是汇总计算出来的,有聚合过程。例如单笔订单的金额不能是一个指标,统计一天的订单金额才是指标。指标需要维度进行多方面的描述分析,维度可以根据需要可以无限扩展,例如,月汽车销量,可以增加城市维度、品牌维度、是否贷款维度等等,就可以变成:城市月汽车销量,大众汽车城市月销量、有贷款的大众汽车城市月销量。
- 通过表格理解指标
一维表格
不存在单维表格,单一的值不能是指标,例如:
成交金额 |
2000 |
因为上面的表格没有描述是谁的成交金额,单独的一个值,无法描述这个值代表的什么事务、动作,以及在什么时间周期范围内产生的这个聚合度量。
二维表格 时间周期
任何指标统计都离不开时间周期,可以说所有的指标都会涉及时间。对在一个时间段内发生的业务进行统计。例如过去 24 小时,一个自然日、自然周,这一年,从月初到现在,往前推 30 天等等,都是时间周期。如果在表格中描述指标,则一定且必须最少是一个二维表格(至少有两列),在表格中加入时间周期,就得到了这样的结果:
时间 |
成交金额 |
day1 |
2000 |
最近7天 |
5000 |
业务范围
如果确定了业务范围,例如业务范围=【短视频】,度量是播放次数,并且把播放VV这个度量的时间范围确定在天这个范围内:
时间周期 |
业务 |
播放次数 |
day1 |
短视频 |
xxxx |
day2 | 短视频 | xxxx |
day2 | 短视频 | xxxx |
dayn | 短视频 | xxxx |
业务这一列用于描述这个度量的业务范围,一般称它为业务修饰词,但通常在表格中,不会这么存放,第二列造成了冗余,一般都简化掉这一列,收敛成两列的形式,把业务范围和度量合并:
时间周期 |
短视频播放次数 |
day1 | xxxx |
day2 | xxxx |
day3 | xxxx |
dayn... | xxxx |
业务范围和维度的区别
业务范围也是维度,只不过在指标计算的过程中,会从最宏观的一面开始,习惯性的会定义一个范围,要统计哪个业务的数据?你有 4 家水果店,别人要问你,你的日销售额是什么?那你可能会问,是哪家门店?或者是我所有的门店?(相当于我自己的生意范围)它本身就是一个维度(视角)来统计的。但把它抽离出来,是方便于对指标的管理与认知。公司大了,有很多分支业务的时候,你问 DAU 是多少,肯定会带上业务前缀的。
多维表格
如果二维表格是最小集,那么加入更多的维度和度量,这个表格就变成多维表格,例如,修饰词=【短视频】,加入维度=【终端】和【是否会员】则多维表格是这样的:
时间周期 |
终端 |
是否会员 |
短视频播放vv |
day1 | ios | 是 | xxxx |
day1 | 安卓 |
是 | xxxx |
day1 | ios | 否 |
xxxx |
day1 | 安卓 |
否 |
xxxx |
day1 | all |
all | xxxx |
day2 | ios | 是 |
xxxx |
day2 | 安卓 | 是 |
xxxx |
也可以在此基础之上,增加度量,例如增加度量【播放时长】:
时间周期 |
终端 |
是否会员 |
短视频播放vv |
短视频播放时长 |
day1 | ios | 是 |
xxxx | xxxx |
day1 | 安卓 |
是 |
xxxx | xxxx |
day1 | ios | 否 |
xxxx | xxxx |
day1 | 安卓 |
否 |
xxxx | xxxx |
day1 | all |
all |
xxxx | xxxx |
多维表格的表头样式就是这样的:【维度 1】【维度 2】【维度 3】【维度 n…】【度量 1】【度量 2】【度量 3】【度量 n…】。
每一行的维度+单一度量都是一个指标
这里有一个很重要的思想统一,上面的多维表中每一行都是一个指标,每一行形成了指标的基本要求【维度】+【度量】。经常会有一种情况,用户在相互沟通指标时,没有按照每一行是一个独立指标来看待。例如,会员在 ios 端的播放 vv 和会员在安卓端播放的 vv 是两个不同的指标,很多人会认为指标是播放 vv,会员、终端都是描述指标的维度。这样理解没问题。因为视角不同。”指标是播放 vv,会员、终端都是描述指标的维度“是典型的管理视角。一行一个指标是应用视角,在描述指标的时候,就是确定在这一行的这个数字上,如果按照管理视角来看,那么指标就会有很多行。如果多个人有多个理解方式,就一定会产生沟通成本。
条件限定
上面的多维表是正确表达指标的一种理想状态,认为每一行都是一个可以解释的指标。但实际使用情况不单单是用【维度】+【时间周期】+【度量】就可以完成指标的描述的。
用户会随着业务的需求,有很多临时分析需要,随时对指标进行条件的设定。例如上面的表中,指标【短视频播放时长】,需要对用户做分类,就会有一定的条件限制:播放时长大于1小时的用户,非会员且播放时长大于 1 小时的用户。这个例子中,把指标【短视频播放时长】以及维度【是否会员】做了条件限制,用于描述指标【短视频用户数】。
时间周期 |
终端 |
条件限定 |
短视频用户数 |
day1 |
ios |
【播放时长】>1 小时 | xxxx |
day1 |
安卓 |
【播放时长】>1 小时&非会员 | xxxx |
这种情况非常常见,例如大于 18 岁的用户,本科及以上学历,用户登录次数大于 3 等等。度量、维度值,都可以当做条件作用于其他指标。
以上情况我们统称为条件限定,条件限定扩大了指标的灵活性,可以基于实际的业务需要对指标进行数据剪裁。条件限定和维度值的区别:例如像 IOS 端,是一个维度值,单独来看 IOS 端的短视频用户数,IOS 端可以表达维度,也可以用于条件限定,但是维度值是确定且单一的,它不能组合。条件限定是灵活的,它可以用度量来限制、也可以组合各种维度值,例如渠道包括:1,系统直播 2,线下门店 3,淘宝 4、外部直播 5、分销商,每一个数值都代表一个维度值,他是确定的观察视角。条件限定可以是他们中任何数字的组合,比如 1 和 2,2 和 3,1 或者 2,2 或者 3,不是 1 和 2 等等,它是灵活多变的。
总结
- 单独存在的度量、维度都不是指标
- 用表格描述指标的最小集是二维表,单独一列没有任何意义,不具备可读性
- 绝大多数指标都是多维表的形态:【维度 1】【维度 2】【维度 3】【维度 n…】【度量 1】【度量 2】【度量 3】【度量 n…】
时间周期 | 维度1 | 维度2 | 维度n | 度量1 | 度量2 |
日期 | 城市 | 品类 | 渠道 | 成交金额 | 成交订单数 |
- 业务范围帮助缩小和明确了处理数据和理解指标的范围
- 如果维度不断增多,那么数据表就是一个很宽的表。也就是常说的“大宽表”
- 条件限定的加入,产生了更灵活的指标形式
▐ 指标模型
- 原子指标
原子指标是指数据分析中最小的可度量单元,通常是一个数值或一个计数。原子指标是数据分析的基础,它们可以用来描述某个特定的事件、行为或状态,如销售额、访问量、转化率等。原子指标通常是不可再分的,因为它们已经是最小的可度量单元了。
按照上面的例子来说,原子指标可以理解为是度量,例如【销售金额】【播放时长】【访问次数】等等,这些度量是不可拆解的。
原子指标用于明确业务的统计口径及计算逻辑。具备以下特性:
- 原子指标是对指标统计口径算法的一个抽象,等于业务过程(原子的业务动作)+ 统计方式。例如,支付(事件)金额(度量),曝光(事件)次数(度量)
- 原子指标不会独立存在,一定是结合业务范围,维度进行组合才有意义
- 原子指标加维度可以理解为一个度量在不同视角下的变化
原子指标通常是其他指标的基础,可以通过对原子指标的分析来得出更高级别的指标。理解原子指标是整个指标管理模型中非常重要的一环。
- 派生指标
派生指标在业务限定的范围内,由原子指标、时间周期、维度三大要素构成,用于统计目标指标在具体时间、维度、业务条件下的数值表现,反映某一业务活动的业务状况。
例如上面讲到的多维表中的每一行都是一个派生指标,也就是说,业务中用到的指标都是派生指标。
不同的派生指标可能具有相同的原子指标,这样派生指标就定义了一种等价关系,而属于相同的原子指标就构成了一个对指标体系的划分。在每一个划分中,存在一个可以派生出其他指标的最小派生指标,即最细粒度。
大模型与数据分析:探索Text-to-SQL(下):https://developer.aliyun.com/article/1480723