段子手女装大佬 21 小时前发布
继上次搭建完框架得到了个粗糙的 demo 以后,我天真地以为我离真理的距离简直就只有一步之遥了。基本的图形组件试了个遍没什么。
想着我还有些模拟的地理数据没有做可视化,数据信息的内容放在名为 location 的属性之下,具体格式如:
- {
- "location":{
- "lat":12.345,
- "lon":56.789
- },
- "temperature":49.966,
- "more-props":"value"
- }
一个很自然而然想法萌生了 --- 用地图来展示相关信息。但!万万那没想到,一进地图的坑,卡了 10 天都没出坑。(部分原因是圣诞节让我懒惰 [写不出来就让圣诞节背锅哈哈哈哈],没有做功课)。
关于基于地图的信息可视化,Power BI 上的 Map 工具给我留下了用户友好简单易用的好印象。只要使用直接的经纬度数据对就能在地图上对位置定位并展示。逻辑惯性让我想当然了,天真地以为所有的地图插件都一样 "单纯"。
首先,在 Grafana 的标准可视化工具中是不包括地图相关的工具的, 但在插件库中官方发布了一款名为 World Map Pannal 基于地图可视化的工具,符合我的需求看起来效果也不错。
在简单地下载安装了这个插件后,我发现事情并没有想象简单。该工具和我的可视化框架最大的冲突是:
Worldmap Panel 并不支持通过经纬度数据对 e.g. (latitude, longtitude) 在地图上定位与可视化, 其支持的数据格式有且仅有两种:Country/State Code 或 geohash。
以下从官方文档中摘出的这句话很好地的解释了这两种数据类型。
There are currently two ways to connect data with points on a map. Either by matching a tag or series name to a country code/state code (e.g. SE for Sweden, TX for Texas) or by using geohashes to map against geographic coordinates。
Grafana 和 InfluxDB 的文档大概是我有生以来看到过写的最逻辑混乱的文档之一了,吐槽请见上篇博客。
在这新年之际,我要邀请大家继续欣赏出自 Grafana 官方 WorldMap Panel 的documentation。 说实话我一口气看了三遍后竟然比看第一遍时还要混乱。文档以 table data, time series data 和 json 为 data source 的介绍相关配置实在是非常地不明智之举。以我的构架为例:首先,使用 influxdb 得到的数据照理说应该是 time series data 吧?毕竟人家 influxdb 号称 time-series 数据库,以写入数据库时的时间戳作为表格的唯一索引。 然而最后使用的配置方法竟然归档在 table data 下 (influxdb: 我不要面子的哦);
其次 "time-series data" 这个称谓也许还能够直观地理解是以时间戳为索引的数据(更有甚者我这样的理解其实是错误的),那么 "table data" 该如何去理解呢?"time-series data" 难道不是以表格的形式组织排列储存的吗?至于 "json" 就更为模糊了,是以 json 为格式的数据?还是通过 json 的形式传递的数据? 那么 json 这种格式的数据就不能同时是 "time-series data" 或 "table data" 吗?这三种类型的数据不具备互斥性,由此可见这种分类方法是不科学的。
我个人主观认为正确的分类方法正如文档开头所说,我在本文的第一章节也引用了这句话:
There are currently two ways to connect data with points on a map. Either by matching a tag or series name to a country code/state code (e.g. SE for Sweden, TX for Texas) or by using geohashes to map against geographic coordinates.
注解:
对于 code: 可以使用 grafana 预先定义的 code, 也可以自定义一些 code 并用 json/jsonp 方式导入;
对于 geohash: 主要是为了支持 elasticsearch, 但是对于 influxdb, 可以人工添加 geohash 的 tag,并将数据看作是表格读取 geohash tag 中的内容;
"以 country code 和 geohash 为区分,详述在不同数据库下针对这两种数据源的配置方法"--- 如果用这样的方法组织文档,一目了然,结构清晰;读者按图索骥,效率大大提高,至少好过现在的文档。而全文档如此重要的一句话,竟然放在一个毫不起眼的角落。恕我实在无法理解撰写者的意图。
为了解决这个如鲠在喉的数据匹配问题,几种可能的解决方法一番折腾后初现原形:
最容易想到的方法。简单粗暴快捷!但是考虑到这样的方法并不能适配所有的 IoT 设备,且大部分的 GPS 产生的数据还是经纬度。排除排除!
可惜我并没有找到这样可以直接使用的 plug-in。转念想到可以自己开发 plug-in, 但是对我而言时间,学习成本太。高。(Golang 小白, geohash 算法不了解)。两个字:排除!
P.S: 有兴趣的朋友可以看看 telegraf 的文档,他们是欢迎各种形式的 plugin PR 的。暗中观察,这样的 plug-in 应该要归在 processor plug-in 一类中。而目前官方只在这类中给了个 printer。基本等于没什么卵用,就是在 cmd 里打印下数据流。亟待小伙伴填坑!
ref:https://github.com/influxdata...
Kapacitor 是 influxdata 四个开源核心产品之一(TICK stack, K--Kapacitor),可以对数据进行相应的分析处理,比如使用机器学习模型处理分析数据。具体其他功能不是特别清楚没做仔细调研,有兴趣的同学移架这里。
至于排除的原因和 2 类似,没有可用的脚本,开发成本太高。
看起来似乎是个物美价廉的正经解决方法。不过由于本文讨论的是实时 IoT 数据的可视化,可能每分钟就会向数据库内写入大量的数据,如果在数据存储后再对数据进行操作,则要频繁地调用数据库 I/O 进行读写操作, 将已经存入的数据记录逐条处理并写回,增加了数据库负担。因此排除。
ref: https://community.influxdata....
5. 使用 Node-Red 对数据流向管理,在数据存入数据库之前利用已有的集成块调用接口计算 geohash 以减轻对数据库的负担。Node-RED为一个开源的 IoT 设备数据流编辑器,主要用于可视化 IoT 数据的流向并且对数据流向进行管理和连接。 它依赖于活跃的 node.js 社区,拥有大量可用资源和强大的社区支持。 既能有效地将数据从源头历经的各个技术栈以流程图的形式表达出来,又能对数据流进行简单管理,支持 javascript 对数据流的处理,因此对前端工程师十分友好。
而吸引我使用 Red-Node 很重要的一个原因是: Node-RED 中有一个名为node-red-node-geohash的结点模块,在 Node-RED 项目中使用 npm 简单安装后,即可将数据中的经纬度数据对直接编码成 geohash 码,反之亦然。这样就避免了我投入大量时间成本和开发成本在 geohash 到经纬度的转码上;
其次,Node-RED 对数据流向进行管理和编辑处理的强大功能,允许在流向中插入自定义的 javascript 功能代码;这让数据流向设计的灵活度大大提高了,因此也能充分利用这种灵活度将我的数据在存入数据库之前将关于经纬度的数据转译成 geohash,这样一来就避免了方法 4 中对数据库资源的浪费和复写;
最后,Node-RED 的可视化编辑界面能有效将数据流向以一种简单直接的方式表达出来,是选择使用该工具的加分点。权衡性价比之后,决定采取最后一种方案。
tips: 使用 Node-RED 的前提条件是保证 node.js 已安装;
如果是和我一样使用 windows 系统的小伙伴们, 推荐一个插件叫做 chocolately, 从此 Windows 也拥有了软件包管理工具,命令行安装 package 不是梦!
打开 windows cmd 使用 chocolately 安装 node.js:
- choco install nodejs - lts
- C: \WINDOWS\system32 > npm install - g--unsafe- perm node - red
- 用户app路径\npm\node_modules\node - red > npm install node - red - node - geohash
- 用户app路径\npm\node_modules\node - red > node - red
Node-RED 的数据流向编辑器采用模块拖拽的形式,用户很容易理解和使用,因此上手不难,学习曲线平缓。
根据我的案例情况,在 Node-RED 上搭建的数据流向如下
从我机器上的 MQTT broker 上订阅从我的模拟器中发出的特定话题的数据后,利用 geohash 结点模块处理经纬度数据,生成 geohash,然后再一次利用 MQTT broker 发布一个新的话题,用于传递经过处理的数据, 这时只要数据库订阅这个新话题,就能利用 telegraf 顺利地将数据存入数据库中。
在这个流向中除了必备的 mqtt 和 geohash 节点,我还利用了两个 function 节点来自定义代码。它们分别用于处理流入 geohash 结点之前的数据,和 geohash 结点之后的数据。
根据官方文档中的描述,geohash 节点将会直接读取 msg.payload 中的 lat 和 lon 属性,如果规定了精确度即 msg.payload.precision 存在,那么会一并处理生成唯一的 geohash 码。具体描述如下:
A function that encodes lat,lon to and from a geohash.
If the msg.payload is an object with properties lat or latitude and lon or longitude - it will add a geohash property to the payload.
The precision can be set by msg.payload.precision from 1 to 9.
Note: If the msg contains a .location property it will operate on that in preference to the .payload.
在第一章中,我提到过,我的地理数据是被包裹在 location 属性中的,即 msg.payload.location。因此 geohash 无法直接得到经纬度信息。这时就借助了 location-preprocessor 的功能节点将 location 中的信息提取出来。注意在引用的文档叙述中的最后一句, 如果 msg 中包含了 location 属性,会直接处理 location 属性中的 lat,lon 属性,忽略 payload 中的信息。 借助这一点,我们则可以将 msg.payload.location 中的信息直接放入 msg.location 让其计算 geohash。
location-preprocessor 的代码:
- //The main purpose of this snippet is to extract the location info from msg.payload and then put it to msg.location to get the calculated geohash.
- var message = JSON.parse(msg.payload);
- if(message[0].location !==null){
- msg.location ={
- "lat": message[0].location.lat.toString(),
- "lon": message[0].location.lon.toString(),
- "precision":"8"
- };
- //msg.location=message;
- }
- return msg;
当得到有效的 geohash 码后,此时,只需将 msg.location.geohash 的值复制进入 msg.payload 中,此时数据中就拥有了 geohash 码了。接着只需新建一个 mqtt 话题,将处理的数据通过 mqtt broker 发布出去,则 Node-RED 的配置到这里就结束了。
location-afterprocessor 的代码:
- //The main purpose for this snippet is to put the geohash property into msg.payload which is then transferred by mqtt-broker via certain topic
- if(msg.location.geohash!==null)
- {
- var message=JSON.parse(msg.payload);
- message[0].geohash=msg.location.geohash;
- msg.payload=JSON.stringify(message);
- msg.topic="sensors/wrap_geohash";
- }
- return msg;
到这里,运行 telegraf 和 influxdb,数据应该安然无恙地被 telegraf 简单处理后存入数据库。这时对数据库进行简单的操作检查数据是否如自己预期地被写入了指定数据库。
既然到这里已经保证数据库里有了可用的数据,那么接下来开始设置 Worldmap Panel 工具吧!
欣喜伴随着绝望。又要开始研究文档 T.T。
瞅来瞅去,文章里关于配置最重要的一段话就是这里了:
An example of Table Data would using InfluxDB and then formatting the data returned from the metric query as Table.
Similar to the Elasticsearch query above, 3 fields are expected (2 of them are mandatory)
- field named metric
- geohash tag named geohash
- an optional location name (shown in the mouse over). This location name has to be specified in the Worldmap settings tab too.
我给大家用直白的话翻译一下这段话的意思: 老子 Worldmap Panel 只认两个兄弟,一个叫做 metric,还有一个就是 geohash!location name 的这个人可以考虑,但是可有可无。其他的都滚一边去!
geohash 就是个打手,Worldmap Panel 说让它去哪儿它就得去哪儿,该在那个地理位置就给定在哪里;
metric 是个师爷,在 geohash 的定位基础上,每个点要显示的值都靠 metric 去提供。但是师爷这种人聪明绝顶,行走江湖容易遭人暗算,所以 metric 是个化名,真正名字叫什么,主要看数据库给什么值了。总之在 Worldmap 上他就叫 metric。
这样一来我们就可以设置数据集按照 geohash 来定位,而在每个 geohash 的点上需要显示的值则由 metric 确定。比如从我的需求出发,需要显示我的每台设备在地图上的定位并能让用户看到每台机器的当前运行的温度情况,那么我就应该这样来设置我的 query。
同时,在 worldmap 一栏对 map data options 进行设置:
location data 一定要选择 table, 且一般 table field name 设置为 geohash;
到这里应该可以看到美腻的 demo 了!Worldmap panel 到这里终于可用了!
脸上笑嘻嘻,心里真是 mmp 啊!朋友们填坑不易,且填且珍惜哦!
也不知道自己还能坚持填坑多久,前路漫漫啊前路漫漫!
最后是不是要祝盆友们元旦快乐呢?虽然我知道看到最后的基本都是真爱,而真爱的概率和在这个现实世界一样基本为 0。
来源: https://segmentfault.com/a/1190000012674763