InfluxDB:使用Flux中的数据透视功能重组数据

如果您在我用Rails和GraphQL实现Flux查询时一直遵循我的Flux旅程,那么您会知道在Flux中实现各种功能时我一直在使用火车数据。 为了使Rails项目中的GraphQL gem正常工作(它为每个属性调用一个对象上的方法),我需要为每个火车数据点创建一个Ruby对象,其中每个标签和字段都分开变成自己的属性,如下所示:

 班级火车 
attr_reader:时间,:测量,:驱动器,:位置,:火车,:户外温度,:速度,:轨道温度
  def initialize(火车) 
@time =火车[“ _time”]
@measurement =火车[“ _measurement”]
@driver =火车[“驾驶员”]
@location =火车[“位置”]
@train =火车[“ train”]
@outdoor_temp =火车[“ outdoor_temp”]
@speed =火车[“速度”]
@track_temp =火车[“ track_temp”]
结束
 结束 

如果没有正确的Flux函数,当我查询数据库以返回火车数据点时,我的标签将被分离到它们自己的列中,但是我的字段将被聚合到一个单独的列_field 。 我的数据将不会像我希望的那样通过基本查询来改变形状,如下面的查询所示,返回的结果如下:

 来自(存储桶:“火车”) 
|>范围(开始:-60d)
|>过滤器(fn:(r)=>
r._measurement ==“ train_speed”

|> group(列:[“ driver”])

我是否需要编写代码来重塑数据? 那似乎不对。 那么,如果我不能将字段提取到它们自己的列中以便更轻松地解析,该如何创建一个干净的Ruby对象呢? 枢轴功能使我能够做到这一点。

Flux提供了一种透视功能,使您可以将单列中的数据重塑为多列,从而确保以一种更易于使用的方式从查询引擎返回数据,而无需实际更改基础数据本身。 通常,您将被安排到一组预定的列和行,而pivot允许您指定数据的组织和显示方式,并使其更易于阅读和直接使用,而无需编写其他应用程序代码。 让我们看看它是如何工作的。 从文档:

输出构造如下:

  1. 将为rowKey参数输入中标识的每个唯一值创建一个新行。
  2. 新行的初始列集是与组键联合的行键,但不包括columnKey和valueColumn参数指示的列。
  3. 对于由columnKey参数在输入中标识的每个唯一值,将一组值列添加到行中。 标签是使用_作为分隔符的valueColumn字符串和columnKey值的串联。
  4. 对于每个行键+列键对,适当的值由valueColumn从输入表中确定。 如果未找到任何值,则将该值设置为null。

为了探究数据透视功能,我将InfluxDB v1.7与Flux技术预览版结合使用(但v2.0 Alpha版本的工作流程相同)。 首先,我使用写入端点为一个名为trains的存储桶播种,其中包含包含火车数据的数据点。 测量值为train_speed 。 标签是driverlocationtrain 。 字段是outdoor_tempspeedtrack_temp 。 我希望看到我所有的字段分解成自己的列,而不是汇总到单个列中,这样我就可以像上面提到的那样制作一个干净的Ruby对象。 提醒一下,这是我开始使用的数据形状的一个示例,按驱动程序分组,您可以在其中看到我的字段全部聚合到一个单独的列_field

使用以下查询实现了上述按驱动程序分组的表的可视化:

 来自(存储桶:“火车”) 
|>范围(开始:-60d)
|>过滤器(fn:(r)=>
r._measurement ==“ train_speed”

|> group(列:[“ driver”])

在此查询中,我从trains存储桶中获取数据,设置最近60天的range (在Flux中设置时间range是必需的),并要求使用尽可能广泛的filter (即测量值)。 然后,我按driver对数据进行group ,以查看与每个驱动程序关联的所有可用数据。 这与您可以创建的过滤器差不多,并且在大型数据集上使用它可能不明智,但是从更高层次上说明过滤的作用很有用。

该查询的结果是,我的测量值和标签都被_field到了自己的列中,但是我所有的字段都收集在同一_field列中。 我可以通过查看UI中的原始数据来确认这一点,这对于确认我是否获得所需的数据形状非常有用。 如果我想要一个表格,在那里我看到所有这些字段都分成各自的列怎么办? 我可以运行以下查询以实现数据透视功能:

 来自(存储桶:“火车”) 
|>范围(开始:-60d)
|>过滤器(fn:(r)=>
r._measurement ==“ train_speed”

|> group(列:[“ driver”])
|>枢轴(
rowKey:[“ _ time”],
columnKey:[“ _field”],
valueColumn:“ _ value”

该查询返回的结果如下所示:

您可以看到我的每个字段现在都有自己的列,但是我不再看到自己的度量或标签。 如果我想看到那些字段被分成自己的列,又仍然按驱动程序分组并保留测量和标签行,该怎么办? 除非这些原始列出现在group函数或rowKey ,否则它们将被删除。 因此,通过将其columnKey值设置为_field并将我的rowKey设置为不仅包含_time而且还包含locationtrain_measurement ,我可以实现数据透视功能以确保每个字段都有自己的列:

 来自(存储桶:“火车”) 
|>范围(开始:-60d)
|>过滤器(fn:(r)=>
r._measurement ==“ train_speed”

|> group(列:[“ driver”])
|>枢轴(
rowKey:[“ _ time”,“位置”,“火车”,“ _measurement”],
columnKey:[“ _field”],
valueColumn:“ _ value”

该查询返回的结果如下所示:

现在,我将字段分为自己的列,并且还保留了我的测量值和标签作为行键。 提醒一下,这是我开始的工作:

稍后,我们将看到当我们向columnKey数组添加其他值时会发生什么。

但是,如果我需要根据特定时间戳记中存在的值对数据进行排序怎么办? 您可以如下所示修改枢轴:

 来自(存储桶:“火车”) 
|>范围(开始:-60d)
|>过滤器(fn:(r)=>
r._measurement ==“ train_speed”

|> group(列:[“ driver”])
|>枢轴(
rowKey:[“ _ field”,“位置”,“火车”,“ _measurement”],
columnKey:[“ _time”],
valueColumn:“ _ value”

通过将_time我的columnKey ,并将_field作为rowKey ,我现在能够产生如下数据:

现在,我每个字段都有一行,每个时间戳都有一列。 向右滚动可让我查看所有时间戳及其各种行值。

另一个有用的枢轴使您可以使每个标签与字段一起出现在列名称中,通过允许您使用更特定的列名称来提高可读性。 如果特定标签有多个值,这可能会派上用场,但如果标签有很多可能的值,则应谨慎使用。 您可以运行以下查询:

 来自(存储桶:“火车”) 
|>范围(开始:-60d)
|>过滤器(fn:(r)=>
r._measurement ==“ train_speed”

|> group(列:[“ driver”])
|>枢轴(
rowKey:[“ _ time”,“位置”,“ _measurement”],
columnKey:[“ _field”,“ train”],
valueColumn:“ _ value”

该查询产生驾驶员Gupta已驾驶train atrain b 。 您将获得单独的列,列名称中包含所有可能的训练值(只有两个,因此此查询不会占用大量资源),并通过下划线与字段键分开:

现在,您已经了解了枢轴如何在Flux中工作。 这是一个有用的函数,用于以不同于默认约束规定的格式返回数据。 您可以通过多种不同方式来实现该功能,我发现尝试更改rowKeycolumnKey数组中的值以查看如何以不同的方式返回数据很有用。 我鼓励您这样做,并享受Flux提供的所有功能!