Skip to content

衡石 HQL

衡石系统中自定义的计算过程描述语言为 Hengshi SENSE Query Language (HQL) ,用于衡石系统的前后端交互、API 数据请求中。

语法规定

使用统一的 JSON 来描述各个计算过程. HQL 由多层调用的 HE (Hengshi Expression) 组成。下面是单个 HE 的语法结构。

HE 节点名类型是否必须描述
uidSTRING本节点的全局唯一标识符
kindSTRING节点类型,见HE状态说明
opOBJECT不同的 HE 类型,对应不同的节点定义,见HE状态说明
argsHE 数组当 kind 为 functions的时候,此项为必须的
typeSTRING本节点输出的数据类型,可以是 string, number, integer, date, time, json, bool 中的一种
datasetOBJECT本节点所在的数据集 id, 一般在 kind 为 field 的时候会指定字段所属的数据集
directionSTRING可选值为 asc 或者 desc,本节点用户排序的时候可以指定该字段,不指定的话,默认为 asc
windowOBJECT指定本节点计算的窗口,只有 kind 为 function 时,该字段的值才有效,见HEWindow窗口说明
filterHE 数组计算的过滤条件,一般用户聚合计算的过滤

HE 节点类型说明

节点类型节点描述类型对应的 op
field描述字段字段名
function描述函数函数名
reference描述引用字段,一般用户图表的定义中引用的名字
constant描述常量常量的值
formula描述自定义的 HE 表达式表达式的定义
array描述数组数组
attr描述用户属性用户属性的名字
param描述应用参数应用参数的名字
dataset描述数据集数据集的 id

HE Window 窗口说明

窗口关键字类型描述
partitionHE 数组计算过程的划分依据,对应 sql 中的 partition by 关键字
orderHE 数组计算过程的排序依据,对应 sql 中的 order by 关键字

示例1:描述字段

kind 的值是 field, op 的值是字段名, dataset 的值是字段所在的数据集 id。下面的例子描述的是来自数据集 1 的 "test" 字段

json
{
   "kind": "field",
   "op": "test",
   "dataset": 1
}

示例2:描述常量

kind 的值是 constant, op 的值是常量值, type 的值是常量的类型。type 为非必需的。 下面的例子描述的是字符串类型常量值 'test'

json
{
   "kind": "constant",
   "op": "'test'"
}

下面的例子描述的是时间类型的常量值 '2000-01-01'

json
{
   "kind": "constant",
   "op": "'2000-01-01'",
   "type": "date"
}

示例3:描述函数

kind 的值是 function, op 的值是函数名或者操作符, args 是函数参数数组。 下面的例子是描述一个加法操作,数据集 2 的字段 salesNum + 2000。

json
{
   "kind": "function",
   "op": "+",
   "args": [
        {
             "kind": "field",
             "op": "salesNum",
             "dataset": 2
        },
        {
             "kind": "constant",
             "op": 2000
        }
   ]
}

下面的例子是描述聚合函数 sum 的使用,计算 数据集 2 的 salesNum 字段列的求和。

json
{
   "kind": "function",
   "op": "sum",
   "args": [
        {
             "kind": "field",
             "op": "salesNum",
             "dataset": 2
        }
   ]
}

下面的例子是描述窗口函数 avg 的使用,以 数据集 2 的 location 字段为分组,计算 数据集 2 的 salesNum 字段列的平均值。

json
{
   "kind": "function",
   "op": "avg",
   "args": [
        {
             "kind": "field",
             "op": "salesNum",
             "dataset": 2
        }
   ],
   "window": {
        "partition": [
             {
                 "kind": "field",
                 "op": "location",
                 "dataset": 2
             }
        ]
   }
}

下面的例子是描述窗口函数 rank 的使用,根据数据集 2 的 saleNum 字段求和的降序对数据集 2 的 location 字段排名。

json
{
   "kind": "function",
   "op": "avg",
   "args": [
        {
             "kind": "field",
             "op": "location",
             "dataset": 2
        }
   ],
   "window": {
        "order": [
             {
                 "kind": "function",
                 "op": "sum",
                 "args": [{
                     "kind": "field",
                     "op": "saleNum",
                     "dataset": 2
                  }],
                 "direction": "desc"
             }
        ]
   }
}

下面的例子是描述带 filter 条件的聚合函数 sum 的使用,计算所有 location 为"北京"或者"上海"的条件下, 数据集 2 的 salesNum 字段列的求和。

json
{
   "kind": "function",
   "op": "sum",
   "args": [
        {
             "kind": "field",
             "op": "salesNum",
             "dataset": 2
        }
   ],
   "filter": [
        {
             "kind": "function",
             "op": "in",
             "args":[
                {
                     "kind": "field",
                     "op": "location",
                     "dataset": 2
                },
                {
                     "kind": "constant",
                     "op": ["北京", "上海"]
                }
             ]
        }
   ]
}

示例4:描述表达式

kind 的值是 formula, op 的值是表达式。函数表达式的使用请参照函数文档。 HE 函数的描述都可以转成HE 表达式,例子中也对应了上面函数描述的例子。下面是HE 以及对应 表达式表述的定义。

用途HE表达式
字段{“kind”: “field”, “op”:”字段名”}{字段名}
数据集的字段{“kind”: “field”, “op”:”字段名”, "dataset":"数据集id"}{{数据集}}.{字段名}
用户属性{“kind”: “attr”, “op”:”用户属性名”}{{$用户属性}}
应用参数{“kind”: “param”, “op”:”应用参数名”}{{%应用参数}}
函数{“kind”: “function”, “op”:”函数名”, "args":["arg1", "arg2"]}函数名(arg1, arg2)
窗口函数{“kind”: “function”, “op”:”函数名”, "args":["arg1", "arg2"],"window":{"partition":["分组"],"order":["排序"]}}函数名(arg1, arg2) over(partition by "分组" order by "排序")
带过滤函数{“kind”: “function”, “op”:”函数名”, "args":["arg1", "arg2"],"filter":["filter1","filter2"]}函数名(arg1, arg2) filter(where "filter1" and "filter2")

下面的例子描述的是连接数据集 1 的 firstname 列 和 数据集 1 的 lastname 列。

json
{
   "kind": "formula",
   "op": "concat({{1}}.{firtname}, {{1}}.{lastname})"
}

下面的例子描述的是比较 数据集 1 的 salesNum 字段 和 应用参数的基准值。

json
{
   "kind": "formula",
   "op": "{{1}}.{salesNum} > {{%基准值}}"
}

下面的例子是描述窗口函数 avg 的使用,以 数据集 2 的 location 字段为分组,计算 数据集 2 的 salesNum 字段列的平均值。

json
{
   "kind": "formula",
   "op": "avg({{2}}.{salesNum}) over(partition by {{2}}.{location})"
}

下面的例子是描述窗口函数 rank 的使用,根据数据集 2 的 saleNum 字段求和的降序对数据集 2 的 location 字段排名。

json
{
   "kind": "formula",
   "op": "rank({{2}}.{location}) over(order by sum({{2}}.{salesNum}) desc)"
}

下面的例子是描述带 filter 条件的聚合函数 sum 的使用,计算所有 location 为"北京"或者"上海"的条件下, 数据集 2 的 salesNum 字段列的求和。

json
{
   "kind": "formula",
   "op": "sum({{2}}.{salesNum}) filter(where in({{2}}.{location}, ['北京','上海']))"
}

使用场景1: 图表的定义

在衡石系统中,定义一个图表由两部分组成,一部分是 HE 的定义,用于获取数据;另一部分是格式的定义,用于展示。这里我们只关注用于获取数据的 HE 部分。 下面是一个简单的图表示例,HE 的计算组合在一起,描述了业务:以 region_name 分组,计算组内 region_id 的求和,结果按照 region_name 的升序展示。

json
{
    "options": {
        "axes": [
            {
                "args": [
                    {
                        "op": "region_name",
                        "kind": "field",
                        "dataset": 7
                    }
                ],
                "op": "group",
                "uid": "u_edbee8adba68e26a_2",
                "kind": "function"
            },
            {
                "op": "sum",
                "kind": "function",
                "args": [
                    {
                        "op": "region_id",
                        "kind": "field",
                        "dataset": 7
                    }
                ],
                "uid": "u_9f886f9cb7bdf1d2_2"
            }
        ],
        "sort": [
            {
                "op": "u_edbee8adba68e26a_2",
                "kind": "reference",
                "direction": "asc"
            }
        ],
        "limit": 1000
    }
}

使用场景2: url 过滤

访问衡石系统的共享链接时,可以在共享链接后面添加 url 过滤条件,用于数据的权限控制。这个过滤条件也是由 HE 组成的。 下面这个过滤表示过滤 location 为北京的数据,它会作用于所有的图表上。

text
where=[{"kind":"formula","op":"{location}='北京"}]

下面这个过滤表示过滤数据集 1 的 location 字段为北京的数据,它会作用于所有与数据集1 由关联的图表上。

text
where=[{"kind":"formula","op":"{1}.{location}='北京"}]

使用场景3: 数据集的新增字段和指标

在衡石系统的数据集里新建字段、新建指标都是通过写 HE 表达式实现的。

HENGSHI SENSE API 使用手册