跳到主要内容

数据帧

Grafana 支持各种不同的数据源,每个数据源都有自己的数据模型。为了实现这一点,Grafana 将来自每个数据源的查询结果整合到一个统一的数据结构中,称为数据帧

数据帧结构的概念借鉴自数据分析工具,如 R 编程语言Pandas

注意

数据帧在 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 has been 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:0045.0
2020-01-02 03:05:0047.0
2020-01-02 03:06:0048.0

每个字段都有三个值,并且字段中的每个值必须共享相同的类型。在本例中,时间字段中的所有值都是时间戳,而 温度字段中的所有值都是数字。

虽然时间字段表示时间戳,但值的类型应为 Number (TypeScript) 或 time.Time (Golang)。

日期帧中时间字段的另一个限制与数字转换有关。在插件前端代码中,可以使用 ensureTimeField 函数从 @grafana/data 包中将其他格式转换为 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 插件 SDK for Go,插件可以检测并将长格式的数据帧转换为宽格式。

有关检测和转换数据帧的信息,请参阅此示例

		tsSchema := frame.TimeSeriesSchema()
if tsSchema.Type == data.TimeSeriesTypeLong {
wideFrame, err := data.LongToWide(frame, nil)
if err == nil {
// handle error
}
// return wideFrame
}

这是另一个例子。以下数据帧以长格式显示

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 数据帧使用 Arrow Tables 作为底层结构,后端 Go 代码在 Arrow Tables 中序列化其帧以进行传输。

Javascript

数据帧的 Javascript 实现位于 /src/dataframe 文件夹/src/types/dataframe.ts,它们都位于 @grafana/data中。

Go

有关 Go 数据帧实现的文档,请参阅 github.com/grafana/grafana-plugin-sdk-go/data 包

了解更多

有关使用数据帧进行插件开发的指南,请参阅以下主题