Grafana支持各种不同的数据源,每个数据源都有自己的数据模型。为了使这成为可能,Grafana将每个数据源的查询结果整合到一个称为数据框架的统一数据结构中。
数据框架结构是一个从R编程语言和熊猫等数据分析工具中借鉴的概念。
笔记 数据帧在Grafana 7.0+中可用,并用更通用的数据结构取代了时间序列和表结构,可以支持更广泛的数据类型。
本文概述了数据框架结构,以及Grafana内部如何处理数据。
数据帧字段
数据帧是字段的集合,其中每个字段对应于一列。反过来,每个字段都由值和元数据的集合组成,例如这些值的数据类型。
export interface Field<T = any, V = Vector<T>> {
/**
* Name of the field (column)
*/
name: string;
/**
* Field value type (string, number, and so on)
*/
type: FieldType;
/**
* Meta info about how field and how to display it
*/
config: FieldConfig;
/**
* The raw field values
* In Grafana 10, this accepts both simple arrays and the Vector interface
* In Grafana 11, the Vector interface will be removed
*/
values: V | T[];
/**
* When type === FieldType.Time, this can optionally store
* the nanosecond-precison fractions as integers between
* 0 and 999999.
*/
nanos?: number[];
labels?: Labels;
/**
* Cached values with appropriate display and id values
*/
state?: FieldState | null;
/**
* Convert a value for display
*/
display?: DisplayProcessor;
/**
* Get value data links with variables interpolated
*/
getLinks?: (config: ValueLinkConfig) => Array<LinkModel<Field>>;
}
让我们看一个例子。下表展示了一个包含时间和温度两个字段的数据帧:
| 时间 | 温度 |
|---|---|
| 2020-01-02 03:04:00 | 45.0 |
| 2020年1月2日 03:05:00 | 47.0 |
| 2020年1月2日 03:06:00 | 48.0 |
每个字段有三个值,字段中的每个值必须共享相同的类型。在这种情况下,time字段中的所有值都是时间戳,temperature字段中的所有值都是数字。
虽然时间字段表示时间戳,但值的类型应该是Number(TypeScript)或time.Time(Golang)。
对日期帧中时间字段的另一个限制涉及转换数字。在插件前端代码中,可以使用@grafana/data包中的ensureTimeField函数将其他格式转换为Number。此函数将遵循ISO 8601格式(例如,2017-07-19 00:00:00.000)的字符串、Javascript DateTime和具有相对时间(例如,now-10s)的字符串转换为Numbers。
对数据帧的一个限制是,帧中的所有字段必须具有相同的长度才能成为有效的数据帧。
现场配置
数据帧中的每个字段都包含有关字段中值的可选信息,例如单位、缩放等。
通过向数据帧添加字段配置,Grafana可以自动配置可视化。例如,您可以配置Grafana以自动设置数据源提供的单元。
数据转换
我们已经看到了字段配置如何包含类型信息;此外,数据帧字段在Grafana中启用数据转换。
数据转换是接受数据帧作为输入,并返回另一个数据帧作为输出的任何函数。通过在插件中使用数据帧,您可以免费获得一系列转换。
要了解有关Grafana中数据转换的更多信息,请参阅转换数据。
数据帧作为时间序列
至少有一个时间字段的数据帧被认为是时间序列。
有关时间序列的更多信息,请参阅我们的时间序列简介。
宽格式
当时间序列集合共享相同的时间索引时——每个时间序列中的时间字段是相同的——它们可以以宽格式存储在一起。通过重用时间字段,发送到浏览器的数据会减少。
在本例中,每个主机的cpu使用情况共享时间索引,因此我们可以将它们存储在相同的数据帧中:
Name: Wide
Dimensions: 3 fields by 2 rows
+---------------------+-----------------+-----------------+
| Name: time | Name: cpu | Name: cpu |
| Labels: | Labels: host=a | Labels: host=b |
| Type: []time.Time | Type: []float64 | Type: []float64 |
+---------------------+-----------------+-----------------+
| 2020-01-02 03:04:00 | 3 | 4 |
| 2020-01-02 03:05:00 | 6 | 7 |
+---------------------+-----------------+-----------------+
然而,如果两个时间序列不共享相同的时间值,它们将表示为两个不同的数据帧:
Name: cpu
Dimensions: 2 fields by 2 rows
+---------------------+-----------------+
| Name: time | Name: cpu |
| Labels: | Labels: host=a |
| Type: []time.Time | Type: []float64 |
+---------------------+-----------------+
| 2020-01-02 03:04:00 | 3 |
| 2020-01-02 03:05:00 | 6 |
+---------------------+-----------------+
Name: cpu
Dimensions: 2 fields by 2 rows
+---------------------+-----------------+
| Name: time | Name: cpu |
| Labels: | Labels: host=b |
| Type: []time.Time | Type: []float64 |
+---------------------+-----------------+
| 2020-01-02 03:04:01 | 4 |
| 2020-01-02 03:05:01 | 7 |
+---------------------+-----------------+
宽格式的典型用途是同一过程收集多个时间序列。在这种情况下,每次测量都是在相同的间隔内进行的,因此共享相同的时间值。
长格式
一些数据源以长格式(也称为窄格式)返回数据。这是SQL数据库等返回的常见格式。
在长格式中,字符串值表示为单独的字段,而不是标签。因此,长格式的数据形式可能具有重复的时间值。
Grafana可以检测长格式的数据帧并将其转换为宽格式。
例如,以下数据帧以长格式显示:
Name: Long
Dimensions: 4 fields by 4 rows
+---------------------+-----------------+-----------------+----------------+
| Name: time | Name: aMetric | Name: bMetric | Name: host |
| Labels: | Labels: | Labels: | Labels: |
| Type: []time.Time | Type: []float64 | Type: []float64 | Type: []string |
+---------------------+-----------------+-----------------+----------------+
| 2020-01-02 03:04:00 | 2 | 10 | foo |
| 2020-01-02 03:04:00 | 5 | 15 | bar |
| 2020-01-02 03:05:00 | 3 | 11 | foo |
| 2020-01-02 03:05:00 | 6 | 16 | bar |
+---------------------+-----------------+-----------------+----------------+
上表可以像这样转换为宽格式的数据帧:
Name: Wide
Dimensions: 5 fields by 2 rows
+---------------------+------------------+------------------+------------------+------------------+
| Name: time | Name: aMetric | Name: bMetric | Name: aMetric | Name: bMetric |
| Labels: | Labels: host=foo | Labels: host=foo | Labels: host=bar | Labels: host=bar |
| Type: []time.Time | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 |
+---------------------+------------------+------------------+------------------+------------------+
| 2020-01-02 03:04:00 | 2 | 10 | 5 | 15 |
| 2020-01-02 03:05:00 | 3 | 11 | 6 | 16 |
+---------------------+------------------+------------------+------------------+------------------+
笔记
并非所有面板都支持宽时间序列数据帧格式。为了保持完全的向后兼容性,Grafana引入了一种转换,您可以使用该转换来从宽格式转换为长格式。有关使用信息,请参阅准备时间序列转换。
技术参考
Grafana中数据框架的概念借鉴了R编程语言和Pandas等数据分析工具。其他技术参考如下。
Apache Arrow
数据框架结构的灵感来自并使用Apache arrow项目。Javascript数据帧使用箭头表作为底层结构,后端Go代码在箭头表中序列化其帧以进行传输。
JavaScript
数据帧的Javascript实现在@grafana/data包的/src/dataframe文件夹和/src/types/dataframe.ts中。
GO
有关数据帧Go实现的文档,请参阅github.com/grafana/gra…。
了解更多
有关使用数据帧的插件开发指南,请参阅使用数据帧。