InfluxDB介绍(一)

1、时序数据库介绍

时序数据库全称为时间序列数据库。时间序列数据库指主要用于处理带时间标签(按照时间的顺序变化,即时间序列化)的数据,带时间标签的数据也称为时间序列数据。——引自百度词条。详情见 时序数据库百度词条

2、时序数据库关键概念

Metric(度量):类似于关系型数据库中的表,在InfluxDB里面是measurement,代表了一系列同类时序数据的集合。例如为空气质量传感器建立一个表,里面存储所有传感器的检测数据。

Tag(标签):Tag用来描述数据源特征,表明了数据的归属,例如某某地点的某某传感器产生的数据,这个某某地点和某某传感器就是两个Tag,表示采集的数据,属于某个地点的,属于某个传感器的。数据库内部会自动为Tag建立索引,支持根据Tag来进行多维度查询,Tag由Key和value组成,都是String类型。

Timestamp(时间戳):代表数据产生的时间点,可以写入时指定,也可由系统自动生成。

Field(量测值):描述了数据源的量测指标,也就是真实采集到的数据,通常随时间不断变化,例如传感器的采集到的温度、湿度等等数值,一般是数字型,比如int、long、double、float等等。

Point(数据点):数据源在某一个时间点产生的某个量测指标的值,比如一号传感器在2023年1月3日11点49分30秒采集到的温度是10.5摄氏度,这个10.5就是一个数据点。数据库查询和写入时都是按数据点来作为统计指标的。

Time Series(时间线):数据源的某个指标随时间变化形成时间线,Metric+Tags+Field组合确定一条线,如当前传感器采集的温度随时间变化的所有数据;针对时序数据的计算,例如聚合(sum、count、max、min等)都是基于时间线维度进行的。

device region timestamp temperature humidity
D-001 sourth-cn 2023-01-03T11:10:00Z 12.6 40
D-001 sourth-cn 2023-01-03T11:11:00Z 12.8 45
D-001 sourth-cn 2023-01-03T11:12:00Z 12.3 42
...... ...... ...... ...... ......
D-099 north-cn 2023-01-03T11:10:00Z 5.6 32
D-099 north-cn 2023-01-03T11:11:00Z 5.0 35
Tags  数据产生的时间 field,表示实际的数据内容

例如第一行数据中,temperature为12.6是一个point,12.8是一个point,12.3是一个point,那么区域是sourth-cn的设备D-001,在2023-01-03T11:10:00Z~2023-01-03T11:12:00Z时间范围内产生的温度数据12.6、12.8、12.3为一个时间线,产生的湿度数据又是一个时间线。

3、数据存储逻辑(相较于关系型数据库)

用上面的表格记录的数据简单举例:

在关系型数据库里面,表格的一行就是数据库的一行,拿第一条举例,表示区域为sourth-cn的D-001设备,在2023-01-03T11:10:00Z时刻记录的温度是12.6摄氏度,湿度是40。

但是在时序数据库里面不是如此,上面的数据有两个字段,分别是温度和湿度,表示两个Field(量测值),时序数据的存储是按Field分开存储的,所以其实是两条,如下:

_measurement _field _value _time  device  region
table_name temperature 12.8 2023-01-03T11:10:00Z D-001 sourth-cn
table_name humidity 45 2023-01-03T11:10:00Z D-001 sourth-cn

4、InfluxDB

官网介绍翻译:时间序列数据平台,开发人员在此构建物联网、分析和云应用程序。官方文档

目前最新版本是2.6,分为单机版和集群版,单机版本是免费的,集群版是收费的。

5、查询语法(2.X版本)

2.X和1.X的语法有很大的区别,1.X采用的是sql的方式,但是2.X版本采用的是JavaScript,下面给出部分语法示例和综合的例子。

5.1、from指定bucket(数据库)

from(bucket: "db_name")
    |> range(start: -5m, stop: -1m)

其中db_name表示想要查询的数据库名称,from表示从指定的bucket中查询数据。 

5.2、|>管道连接符

将数据从数据源管道传输到指定地方,如range()。

5.3、range指定起始时间段(查询的时间范围)

from(bucket: "db_name")
    |> range(start: -5m, stop: -1m)
    |> filter(fn: (r) => r["_measurement"] == "table_name")

range有两个字段,分别是start和stop,表示查询范围的开始时间和结束时间,如果只指定开始时间,则结束时间为当前最新时间,比如:

|> range(start: -5m)

上面的例子表示查询前5分钟到前1分钟的数据,其中的是时间格式如下:

1ns // 1 nanosecond
1us // 1 microsecond
1ms // 1 millisecond
1s  // 1 second
1m  // 1 minute
1h  // 1 hour
1d  // 1 day
1w  // 1 week
1mo // 1 calendar month
1y  // 1 calendar year

3d12h4m25s // 3 days, 12 hours, 4 minutes, and 25 seconds

5.4、filter过滤

filter用于过滤数据,主要有三种,1、指定measurement(表名),2、过滤指定Tag的数据,3、过滤指定field的数据

from(bucket: "db_name")
    |> range(start: -5m, stop: -1m)
    |> filter(fn: (r) => r["_measurement"] == "table_name")
    |> filter(fn: (r) => r["device"] == "D-001")
    |> filter(fn: (r) => r["_field"] == "temperature")

上面的例子中,我们查询的就是名称为table_name的表,过滤tag为D-001的数据,并且只查询_field为temperature的数据。

原始数据

_measurement _field _value _time  device  region
table_name temperature 12.8 2023-01-03T11:10:00Z D-001 sourth-cn
table_name humidity 45 2023-01-03T11:10:00Z D-001 sourth-cn

以原始数据为例,我们查询出来的就只有第一条数据,如果不指定_field的过滤条件,默认查询出归属于D-001下的所有数据,也就是表格中的两条,但是我们只需要查询其中的某几个参数,不需要所有的数据,此时可以通过or的方式过滤,如下:

from(bucket: "db_name")
    |> range(start: -5m, stop: -1m)
    |> filter(fn: (r) => r["_measurement"] == "table_name")
    |> filter(fn: (r) => r["device"] == "D-001")
    |> filter(fn: (r) => r["_field"] == "temperature" or r["_field"] == "humidity")

5.5、group分组

支持对数据进行分组,但并不是所有的字段都可以分组,除了实际数据_value和时间戳无法分组外,_measurement、Tags和_field都可以进行分组,下面的例子就是按Tag和_filed进行分组,一般和一些数学函数一起搭配使用,比如求和cumulativeSum()等等。

注:多个字段进行分组时,需要考虑分组本身的意义,是否需要先过滤再进行分组,因为分组后只会返回分组字段和_value,按上面的传感器举例,我们按device进行分组,分组完后返回的数据是不同设备下,很多参数(温度、湿度)的值混在一起的数据,在当前场景下其实并没有什么实际意义。比如我们可以过滤出温度的数据再进行分组,此时反映的就是不同设备采集的温度数据。

    |> group(columns: ["device", "_field"])

5.6、sort&limit排序和分页

sort的columns针对所有的字段都可以,下面的例子就是对两个Tag和参数值进行排序,不指定参数时,则对_value升序排列。

    |> sort(columns: ["_value"])

默认是对_value的升序排列,要显示指定降序,如下:

   |> sort(columns: ["region", "device", "_value"],desc: true)

注:对tag等字符串进行排序,好像没起作用,只能对_value进行排序,这个后续研究。

limit一般和排序搭配只用,排序完后对数据进行截取,完整的基本语法如下,offset可以不写,不写则默认是0,不跳过任何数据。

    |> limit(n: 3, offset: 2)

5.7、完整的例子

from(bucket: "db_name")
    |> range(start: -1h, stop: -1m)
    |> filter(fn: (r) => r["_measurement"] == "table_name")
    |> filter(fn: (r) => r["device"] == "D-001")
    |> filter(fn: (r) => r["_field"] == "temperature"  or r["_field"] == "humidity")
    |> sort(columns: ["_value"],desc: true)
    |> limit(n: 10, offset: 5)

更加详细查询使用说明,参见官方文档-查询数据

posted @ 2023-01-03 16:06  浪迹天涯的派大星  阅读(644)  评论(0编辑  收藏  举报