Gurux 数据精炼器
从物理设备检索数据,处理它,并可视化结果
引言
![]() |
Gurux 数据精炼器是一款用于收集、处理和可视化数据的应用程序。虽然也有其他应用程序可以执行相同的操作,但数据精炼器提供了一个一体化的解决方案,可以通过同一个用户界面完成所有这些操作。
当需要从远程物理设备收集数据时,主要问题通常是缺乏一个包含所有可能选项的总体标准。这就是为什么市场上大多数应用程序只能适用于特定制造商、特定用途和特定使用方式的设备。如果您有一个设备,需要收集其参数值,但找不到合适的应用程序,甚至找不到一个足够灵活的应用程序供您自定义,那么本文将非常有用。本文中的示例将允许您自己确定数据收集器组件所需的属性。 |
Gurux 数据精炼器作为一个开源项目托管在 SourceForge.net 上,包括所有发布的版本以及集成应用程序手册。
该项目的最新源代码和文档可在 http://gurux.svn.sourceforge.net/svnroot/gurux/GuruxDataRefinery/ 获取。
背景
与大多数好主意一样,这个主意也是为了解决现有问题而诞生的。当 Gurux Ltd 于 2009 年秋季转为开源,并且我们正在建立一个开源社区时,我们需要获取一些关于我们网站流量和 SourceForge.net 上项目下载量的具体信息。我们想了解受众对我们贡献(新产品版本、电子邮件营销等)的响应程度,并获取有关这类关系的有价值信息。尽管 Drupal、Sourceforge 和 Google 提供的统计数据已经很好,但它们并没有完全满足我们的需求,因为我们希望 **将来自不同来源的数据合并到一个显示中**,以了解全局情况。
我们的开发人员编写了用于
- 检索数据(Drupal Collector 和 Sourceforge.net Collector)
- 精炼检索到的数据(高斯滤波器和数据连接器处理器)
- 可视化结果(原始数据视图、拼贴视图和数据图表可视化器)的组件
应用程序的第一个版本,以及我们最初为自己使用的组件,被发布为开源,以便为使用 Drupal 网站和/或 Sourceforge.net 作为源代码托管的其他社区提供相同的可能性。在第一个版本发布后不久,就产生了创建用户完全可定制的数据收集器的想法。本文是开发该想法的结果。
数据精炼器的主要组件
存储库 是数据精炼器中的基本单元。它可以被看作一个容器,用于存储从设备收集的数据表,并包含收集器、处理器和事件。您可以在您的存储库集合中控制一个或多个存储库。
收集器 能够从任何物理设备直接收集大量数据,无论是生产系统、网站服务器、湿度测量设备、能源表、温度计,还是任何类型的设备。收集器将数据收集到所谓的 RawData
表中。
处理器 用于将收集的数据精炼以用于不同的用途。处理组件的类型可以是滤波器、一系列计算,或者对数据进行的任何操作。您可以设置多个操作按顺序执行。
使用 **可视化器**,您可以按照自己的选择方式显示收集和/或处理后的数据;例如,数字表格(所谓的原始数据)、曲线图、图表等。
![]() |
结构在数据精炼器存储库树(左图所示)中显示的存储库集合,可以被看作一个银行保险库,里面有单独的保险箱。 每个保险箱(= 存储库)都包含内容(= 项目),并且可以单独使用或一起使用这些单独保险箱中的内容,作为组合资产。 存储库中的项目数量没有限制,因此您可以根据需要将项目分组。同一存储库中的项目(图中存储库 01 中的收集器 01 和 02)不必有任何共同点,但如果为存储库设置了可视化器,它们可以共享一个可视化器。 |
存储库
每个存储库可以包含一个或多个 GXDataCollectors
**和/或** GXDataProcessors
。每个 Collector
包含一个 RawDataTable
,该表可以有一个或多个行和一个或多个列。在 DataRefinery
中收集、处理和可视化的所有数据都带有时间戳。在所有 DataRefinery
项目中,时间是主要变量,所有数据都与之进行比较。因此,DataRefinery
中所有数据表的第一列始终是时间。
一个 Repository
甚至可以只包含处理器,并使用另一个 Repository
中收集器的数据。例如,图中的存储库 02 包含处理器 02,该处理器连接存储库 01 中收集器 01 和 02 的数据。这个处理器 02 有一个子处理器;处理器 03,它随后过滤连接后的数据。
收集器
虽然收集器可以从任何物理设备收集数据,但我们只编写并发布了用于收集
- Sourceforge.net 的*下载量*
- 我们基于 Drupal 的 Gurux 网站的*流量*
此外,我们在本文后面还提供了创建您自己的收集器的说明和代码示例。
处理器
收集器的数据可以由多个处理器处理。在多处理器的情况下,第一个要执行的操作需要在父处理器中指定。然后,第二个操作设置在第一个处理器的子处理器中,它又将父处理器用于第三个操作,依此类推。在多处理器的情况下,结构实际上不是分层的,而是简单地显示处理操作的执行顺序。
- 高斯滤波器 处理器可以“平滑”曲线的峰谷,从而更容易看到进展趋势。
- 数据连接器 处理器将来自不同来源的数据连接起来,以便在同一可视化图中显示。您可以从四种选项中选择
- 组合 将曲线一起显示,但各自独立。
- 总和 将每个日期/时间来自选定源的所有值相加,并将总和显示为曲线。
- 增量总和 类似于总和,但它还以层状显示来自不同源的份额。
- 总计 将每个日期/时间来自所有源的所有值相加,并将总计显示为曲线。
此外,我们在本文后面还提供了创建您自己的处理器的说明和代码示例。
可视化器
在数据精炼器中谈到可视化时,我们指的是数据的图形化表示。数据精炼器中的每个项目,每个存储库、收集器和处理器,都可以设置自己的可视化器。
- 原始数据视图 是最简单的可视化器,它将数据显示为数字数据表。
- 拼贴视图 允许您在一个视图中显示多种类型的数据表示。
- 数据图表 可视化器允许您选择
- 曲线是填充的(从零到数量)还是单线
- 图表类型:线性、对数、序数或指数
- 单位是否显示或隐藏
- 数据是以曲线、水平/垂直条形图、水平/垂直堆积条形图还是饼图形式呈现
- 是否在曲线上显示一个符号来标记日期,以及使用哪种符号(正方形、菱形、向上/向下三角形、圆形、X 交叉、加号、星形、水平/垂直短线,或用户定义的图案)
如果项目没有自己的可视化器,则可视化将从父项目继承。
创建您自己的收集器
由于数据源差异很大,我们提供了一个图文并茂的教程,说明如何使用 Visual Studio 创建您自己的数据收集器。
以下说明提供了一个简单的示例,演示如何创建一个收集器来收集带时间戳的温度数据。该示例保持简单,以便于应用,您可以创建任何类型的数据收集器。在示例的末尾,您可以在“*故障排除*”标题下找到最常见的问题及解决方法。
使用 Gurux DataRefinery 源代码
本文附带的是应用程序源代码的当前版本(2010 年 5 月)。将来,请在 http://gurux.svn.sourceforge.net/viewvc/gurux/GuruxDataRefinery/ 查看最新版本。
以下示例包含在本文的源代码目录中,位于*“\Development\Collectors\GuruxFileCollectorSample”*目录下的*“GXFileCollectorSample.cs”*文件中。
- 在 Visual Studio 中打开 Gurux
DataRefinery
解决方案(*“GuruxDataRefinery.sln”*)。 - 在 *Collectors* 目录中创建一个
ClassLibrary
项目。注意: 在 *Collectors* 目录中创建
ClassLibrary
项目至关重要,如果创建在其他地方,则后期生成事件(请参阅下一步)将无法正常工作。 - 复制现有
GXCollector
(Gurux Drupal Collector 或 Gurux SourceForge.net Collector)的后期生成事件,并将其粘贴到新收集器的后期生成事件中。这将在生成项目后,将新收集器的动态链接库(*.dll* 文件)复制到相关目录(例如:*bin\debug\collectors*)。 - 将 Gurux.DataRefineryAddIn 项目添加为引用。
- 让类继承 GXDataCollector,并实现它。
namespace Gurux.FileCollectorSample { public class GXFileCollectorSample : GXDataCollector { public override ShownValues DefaultValueType { get { return ShownValues.None; } } } }
- 然后,实现新收集器的基本属性
TypeName
描述
DisplayUnit
- 实现
InitializeDefault()
- 在
DataSet
Data 中创建一个GXDataTable
- 创建列
public override void InitializeDefault() { GXDataTable table = new GXDataTable(); this.Data.Tables.Add(table); table.Columns.Add(new GXDataColumn("TimeStamp", typeof(DateTime))); table.Columns.Add(new GXDataColumn ("Temperature", typeof(double), Color.Red)); }
- 在
- 添加必需的
public
属性,以便最终用户可以编辑收集器的选项。
例如,IPAddress
或FilePath
。public string FilePath { get; set; }
- 最后,实现实际收集带时间戳数据的代码;*CollectData(bool force)*。
注释
- 收集到的数据将追加到
DataSet
成员 Data 中。 - 抛出的异常将被处理,并在用户界面上显示。
public override void CollectData(bool force) { if (!File.Exists(FilePath)) { throw new Exception("The specified file could not be found."); } try { string fileContent = File.ReadAllText(FilePath); List
valuePairs = new List (); valuePairs.AddRange(fileContent.Split (Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); foreach (string pair in valuePairs) { DateTime timeStamp = DateTime.Parse(pair.Split(',')[0], CultureInfo.InvariantCulture); double temperature = Double.Parse(pair.Split(',')[1], CultureInfo.InvariantCulture); Data.Tables[0].Rows.Add(new object[] { timeStamp, temperature }); } } catch (Exception ex) { throw new Exception("Possible file format error: " + ex.Message); } } - 收集到的数据将追加到
- 生成您的项目。
故障排除
如果您创建的 GXCollector
未出现在 DataRefinery
收集器设置对话框的可用收集器列表中
- 则可能是其动态链接库已移位,或者
GXDataCollector
可能未正确继承。
要使 GXCollector 生效:
- 确保收集器的 *.dll* 文件存在于数据精炼器的 *Collectors* 目录中。
- 确保
GXDataCollector
已继承到该类并正确实现,如上面示例的第 5 步所示。
第二部分
创建您自己的处理器
如果您觉得我们的处理器不够用,想创建自己的处理器,我们也提供使用 Visual Studio 创建处理器的说明和示例代码。
以下说明提供了一个简单的示例,演示如何创建一个处理器,该处理器检查数据表中的每个值,并在超过预设的最大值时发出警报。该示例保持简单,以便于应用,您可以创建任何类型的数据处理器。在示例的末尾,您可以在“*故障排除*”标题下找到最常见的问题及解决方法。
使用 Gurux DataRefinery 源代码
本文附带的是应用程序源代码的当前更新版本(2010 年 5 月)。将来,请在 http://gurux.svn.sourceforge.net/viewvc/gurux/GuruxDataRefinery/ 查看最新版本。
以下示例包含在本文的源代码目录中,位于*“\Development\Processors\GuruxAlertProcessorSample”*目录下的*“GXAlertProcessorSample.cs”*文件中。
- 在 Visual Studio 中打开 Gurux DataRefinery 解决方案(*“GuruxDataRefinery.sln”*)。
- 在 *Processors* 目录中创建一个
ClassLibrary
项目。注意: 在 *Processors* 目录中创建
ClassLibrary
项目至关重要,如果创建在其他地方,则后期生成事件(请参阅下一步)将无法正常工作。 - 复制现有
GXProcessor
(Gurux Gaussian Filter Processor 或 Gurux Data Joiner Processor)的后期生成事件,并将其粘贴到新处理器的后期生成事件中。这将在生成项目后,将新处理器的动态链接库(*.dll* 文件)复制到相关目录(例如:*bin\debug\processors*)。 - 将
Gurux.DataRefineryAddIn
项目添加为引用。 - 让类继承
GXDataProcessor
并实现它。另外,重置最大值。namespace GuruxAlertProcessorSample { public class GXAlertProcessorSample : GXDataProcessor { double m_Maximum = 0; } }
- 实现
Maximum
,即数据表的值将与之进行比较的值。
当用户更改最大值时,所有数据都将更新,并调用ForceUpdate
方法。public double Maximum { get { return m_Maximum; } set { bool change = m_Maximum != value; m_Maximum = value; if (change) { ForceUpdate(); } } } }
- 然后,实现新处理器的基本属性
TypeName
描述
- 接下来,实现实际检查数据表每个单元格的代码,如果超过最大值,则报告错误。
public override void ProcessData(object sender, GXDataSet changedItems) { foreach (GXDataTable table in changedItems.Tables) { GXDataTable newTable = this.Data.Tables.Find(table.TableName); //Add table columns and primary keys, but not rows. if (newTable == null) { newTable = table.Clone(false); this.Data.Tables.Add(newTable); } for (int column = 0; column < table.Columns.Count; ++column) { if (IsNumeric(table.Columns[column].DataType)) { foreach (DataRow row in table.Rows) { try { double val = Convert.ToDouble(row[column]); //Report an error if value is exceeded. if (val > Maximum) { throw new Exception("Value is out of limits."); } DataRow dr = newTable.NewRow(); dr.ItemArray = row.ItemArray; newTable.Rows.Add(dr); } //Exception is handled and notified here, //because the checking is wanted to continue, //even if an exceeding value is found. catch (Exception Ex) { NotifyError(this, Ex); } } } } } }
- 生成您的项目。
故障排除
如果您创建的 GXProcessor
未出现在 DataRefinery
处理器设置对话框的可用处理器列表中
- 则可能是其动态链接库已移位,或者
- 则可能是
GXDataProcessor
未正确继承。
要使 GXProcessor 生效:
- 确保处理器的 *.dll* 文件存在于数据精炼器的 *Processors* 目录中。
- 确保
GXDataProcessor
已继承到该类并正确实现,如上面示例的第 5 步所示。
改进和补充
本文最初发布于 2010 年 4 月 22 日。当时,它包含了一个创建您自己的数据收集器的示例。
五月初,我们收到一封电子邮件,报告了源代码中的一个错误:收集器可以正常检索数据,但更新到处理器时不起作用。该错误已修复,并于 5 月 5 日发布了新的源代码。
我们收到了许多关于 Gurux DataRefinery
的积极反馈,因此我们修订了本文,并添加了“第二部分”。第二部分提供了创建您自己的数据处理器的示例代码和说明。修订后的文章以及源代码目录的又一个更新版本(包含必要的示例代码)于 2010 年 5 月 11 日发布。