设计 FlatQL 的初衷是通过一种扁平化的查询语言,以可视化的方式构建复杂查询,从而使得数据分析过程中可以减少对数据工程师的依赖。在传统的数据分析中, SQL 通常通过模板语言的形式实现动态查询,即预先定义一个完整的 SQL 查询,并通过动态替换其中的部分内容来实现某种程度的灵活性 (例如:Superset 的模板化 SQL)。然而,这种模板化的方式仅能满足部分简单查询的动态需求。当动态投影或过滤条件对整个 SQL 结构产生影响时, 模板化语言便显得力不从心。例如:
在面对这些复杂场景时,模板化 SQL 无法提供足够的灵活性。常见的解决方案是通过预计算 构建多层数据模型,即在原始数据模型之上, 构建一系列针对每个分析主题的数据模型。这样,在实际分析时,只需面向单表进行查询,并通过模板语言生成动态查询。然而,这种方式会带来巨大的数据建模成本, 且当分析需求发生变化时,需要重构数据模型,不仅影响效率,还会导致大量重复开发的成本。
FlatQL 采用扁平化的语法结构,只包含投影、过滤、排序三大基本操作,剔除了传统 SQL 中冗杂的部分(包括:分组、多表连接、子查询等复杂逻辑), 所有 SQL 技术相关的处理均由 Agile Query SQL 编译器的算法计算自动生成。这样设计的优势在于,开发者只需关注查询的核心需求。 FlatQL 的完整语法定义如下(BNF 形式):
statement:
select
select:
SELECT expression [AS alias] [, expression [AS alias] ]* FROM schemaIdentifier
[WHERE booleanExpression [AND booleanExpression]* ]
[ORDER BY expression [ASC | DESC] [, expression [ASC | DESC]]* ]
[LIMIT integer]
expression:
column | functionCall | binaryExpression | caseWhenExpression | parenExpression
...
我们来看几个FlatQL 示例:
SELECT
customers.company_name AS "客户",
ROUND(SUM(order_details.quantity), 2) AS "销售量",
ROUND(SUM(order_details.quantity * order_details.unit_price), 2) AS "销售额"
FROM "329875"
SELECT
categories.category_name AS "品类",
SUM(order_details.quantity * order_details.unit_price) AS "销售额"
FROM "329875"
WHERE
GROWTH_OF(SUM(order_details.quantity * order_details.unit_price), orders.order_date) > 10
SELECT
categories.category_name AS "品类",
COUNT(customers.company_name) AS "客户数量",
COUNT_IF(
GROUP_COUNT(orders.order_id, customers.customer_id) > 1
AND GROUP_SUM(order_details.quantity * order_details.unit_price, customers.customer_id) > 100,
customers.customer_id
) AS "高级客户数量"
FROM "329875"
WHERE categories.category_name IN ('饮料', '食品') LIMIT 1000
SELECT
categories.category_name AS "品类",
COUNT_IF(GROUP_COUNT(orders.order_id, customers.customer_id, orders.order_date = LAST_YEARS(1)) > 1)
/ TO_FLOAT(COUNT(customers.customer_id)) * 100 AS "复购率"
FROM "329875"
ORDER BY SUM(order_details.quantity * order_details.unit_price) ASC LIMIT 1000
SELECT
categories.category_name AS "品类",
AVG(
GROUP_SUM(order_details.quantity * order_details.unit_price, TO_MONTH(orders.order_date))
) AS "月均销售额"
FROM "329875"
WHERE orders.order_date = LAST_YEAR(1) LIMIT 1000
从上述示例中可以看出,FlatQL 的主要特点:
示例中的查询语句中的元素(投影、过滤、排序等)彼此独立,每个动态部分均由独立的维度或指标组成(包括过滤表达式,也仅为指标或维度拼接形成的布尔表达式)。 这种设计使得查询可以完全通过可视化方式轻松构建。整个查询中无需关注 SQL 编程中的逻辑关系,只需要关注单个指标的定义。
除了标准的聚合函数,FlatQL 还提供了大量领域相关函数,例如:
可视化构建查询的前提是:1)查询语句中的各个元素相对独立,彼此之间不存在依赖关系;2)查询的逻辑结构简单,便于直观地进行可视化交互操作。 这样才能有效降低数据分析师的交互成本,无论查询的复杂度如何,交互形式不发生变化。Agile Query 的技术实现如下:
将维度和度量值转换为关键词:通过将数据库中的列或指标定义映射为关键词,在进行数据分析时,用户只需关注这些关键词,并可以灵活地进行组合。 这样的交互方式接近与使用自然语言进行数据分析,唯一不同的地方是 Agile Query 是精确的数据分析,而 NLP 形式的数据分析属于动态理解并构建查询。
可视化过滤和排序配置:由于 Agile Query 中的最小单元为列和指标定义,在前端可视化交互时,很容易将这个表达式定义组合成过滤表达式, 例如:拼接比较运算符
技术的发展主要体现在提高生产效率,释放更多生产力,从而投入到更复杂的工作中。Agile Query 释放的是数据工程的的开发工作量, 提升的是数据分析师获取数据的效率,从而提升企业整体的决策效率。Agile Query 还提供了丰富的可视化交互工具,让数据分析师能够自助构建查询, 让数据工程师可以专注于数据治理相关工作,不再因数据分析需求的变化而分心。