Flux 数据模型
Flux采用了一个基于基本数据类型的基本数据模型。 数据模型由表、记录、列和流组成。
记录
一个 记录 是一个命名值的元组,并使用记录类型表示。
列
一个 列 有一个标签和数据类型。
列的可用数据类型有:
| 数据类型 | 描述 |
|---|---|
| bool | 布尔值,真或假。 |
| uint | 一个无符号的64位整数。 |
| int | 一个有符号的64位整数。 |
| float | 一个 IEEE-754 64 位浮点数。 |
| string | 一串unicode字符。 |
| 字节 | 一系列字节值。 |
| 时间 | 具有纳秒精度的时间瞬间。 |
| duration | 纳秒精度的时间持续时间。 |
表格
一个 表 是一组具有共同列和分组键的记录。
组键是一个列的列表。 表的组键表示整个数据集中分配给该表的子集。 表中的所有记录将在组键的每一列上具有相同的值。 这些公共值称为“组键值”,可以表示为一组键值对。
表的模式由其组键及其列的标签和类型组成。
表的流
A stream 代表一个潜在的无限集合的表。 A stream 被使用各自的组键分组为单独的表。 在一个 stream 内部,每个表都有一个唯一的组键值。
流的表示使用流类型 stream[A] where A: Record。
在Flux类型系统中,组键并没有被明确建模。
缺失值(null)
null 是一个预先声明的标识符,表示缺失或未知的值。null 是唯一包含 null type 的值。任何在基本类型上操作的非布尔运算符,当至少有一个操作数是 null 时返回 null。
将null视为一个未知值。 下表解释了null值在表达式中的行为:
| 表达式 | 结果为 | 因为 |
|---|---|---|
null + 5 | null | 将5添加到一个未知值仍然是未知的 |
null * 5 | null | 将一个未知值乘以5仍然是未知的 |
null == 5 | null | 我们不知道一个未知值是否等于 5 |
null < 5 | null | 我们不知道一个未知值是否小于5 |
null == null | null | 我们不知道某个未知的事物是否等于另一个同样未知的事物 |
对未知事物进行操作产生的结果仍然是未知的。 唯一例外的地方是布尔逻辑。 由于布尔类型是可空的,Flux 实现了三元逻辑作为处理带有 null 操作数的布尔运算符的方法。 通过将 null 操作数解释为未知值,我们有以下定义:
- 不是 null = null
- 空 或假 = 空
- null 或 true = true
- null 或 null = null
- null 和 false = false
- null 和 true = null
- 空 和 空 = 空
因为记录是使用记录类型表示的,尝试访问值未知或缺失的列也会返回 null.
根据上述定义,无法使用==和!=运算符检查一个表达式是否为null。如果其任何操作数为null,这些运算符将返回null。为了进行这样的检查,Flux提供了一个内置的exists运算符:
exists x如果x是 null 则返回 falseexists x如果x不为 null 则返回 true
变换
转换定义了对流的更改。 转换可能消耗输入流,并始终生成新的输出流。 输出流组键的输出顺序基于输入流是稳定的。 特定的排序可能在不同版本之间改变,但不被视为破坏性更改。
大多数转换为从输入流接收到的每个表输出一个表。 修改分组键或值的转换会在输出流中重新分组表格。 当由产生副作用的函数构造时,转换会产生副作用。
变换通过函数类型表示。
匹配参数名称
一些转换(例如,map 和 filter)是通过高阶函数(接受其他函数的函数)来表示的。传递给函数的每个参数必须与为该函数定义的参数名称相匹配。
例如, filter 接受 fn,它接收一个名为 r 的参数:
from(bucket: "db")
|> filter(fn: (r) => ...)
如果参数从 r 重命名为 v,脚本会失败:
from(bucket: "db")
|> filter(fn: (v) => ...)
// FAILS!: 'v' != 'r'.
因为 Flux 不支持位置参数,参数名称很重要。转换(在这个例子中,filter)必须知道 r 是参数名称才能成功调用该函数。