65.9K
CodeProject 正在变化。 阅读更多。
Home

Gurux 数据精炼器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (6投票s)

2010年4月22日

GPL3

11分钟阅读

viewsIcon

32514

downloadIcon

635

从物理设备检索数据,处理它,并可视化结果

引言

refineryscreenshot.jpg  

Gurux 数据精炼器是一款用于收集、处理和可视化数据的应用程序。虽然也有其他应用程序可以执行相同的操作,但数据精炼器提供了一个一体化的解决方案,可以通过同一个用户界面完成所有这些操作。

GXDataCollector,数据精炼器中的一个数据收集组件,从选定的源检索数据,并将其保存在数据表中。源可以是任何类型的物理设备,例如 Web 服务器、生产机械或计量设备。GXDataCollector 将数据存储在一个表中,该表的第一列(第 0 列)始终是时间,因此收集的所有数据都带有时间戳。Gurux 数据精炼器需要 .NET Framework 3.5(或更高版本)的配合。

当需要从远程物理设备收集数据时,主要问题通常是缺乏一个包含所有可能选项的总体标准。这就是为什么市场上大多数应用程序只能适用于特定制造商、特定用途和特定使用方式的设备。如果您有一个设备,需要收集其参数值,但找不到合适的应用程序,甚至找不到一个足够灵活的应用程序供您自定义,那么本文将非常有用。本文中的示例将允许您自己确定数据收集器组件所需的属性。

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 表中。

处理器 用于将收集的数据精炼以用于不同的用途。处理组件的类型可以是滤波器、一系列计算,或者对数据进行的任何操作。您可以设置多个操作按顺序执行。

使用 **可视化器**,您可以按照自己的选择方式显示收集和/或处理后的数据;例如,数字表格(所谓的原始数据)、曲线图、图表等。

repositorytree.png  

结构

在数据精炼器存储库树(左图所示)中显示的存储库集合,可以被看作一个银行保险库,里面有单独的保险箱。

每个保险箱(= 存储库)都包含内容(= 项目),并且可以单独使用或一起使用这些单独保险箱中的内容,作为组合资产。

存储库中的项目数量没有限制,因此您可以根据需要将项目分组。同一存储库中的项目(图中存储库 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”*文件中。

  1. 在 Visual Studio 中打开 Gurux DataRefinery 解决方案(*“GuruxDataRefinery.sln”*)。
  2. 在 *Collectors* 目录中创建一个 ClassLibrary 项目。

    createcoll1.png

    注意: 在 *Collectors* 目录中创建 ClassLibrary 项目至关重要,如果创建在其他地方,则后期生成事件(请参阅下一步)将无法正常工作。

  3. 复制现有 GXCollector(Gurux Drupal Collector 或 Gurux SourceForge.net Collector)的后期生成事件,并将其粘贴到新收集器的后期生成事件中。这将在生成项目后,将新收集器的动态链接库(*.dll* 文件)复制到相关目录(例如:*bin\debug\collectors*)。

    createcoll2.png

  4. Gurux.DataRefineryAddIn 项目添加为引用。

    createcoll3.png

  5. 让类继承 GXDataCollector,并实现它。
    namespace Gurux.FileCollectorSample
        {
            public class GXFileCollectorSample : GXDataCollector
            {
                public override ShownValues DefaultValueType
    	    {
    	        get
    	            {
    		        return ShownValues.None;
    		    }
    	    }
            }
        }
  6. 然后,实现新收集器的基本属性
    • TypeName
    • 描述
    • DisplayUnit
  7. 实现 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));
        }
  8. 添加必需的 public 属性,以便最终用户可以编辑收集器的选项。
    例如,IPAddressFilePath
    public string FilePath
        {
            get;
            set;
        }
  9. 最后,实现实际收集带时间戳数据的代码;*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);
            }
        }
  10. 生成您的项目。

故障排除

如果您创建的 GXCollector 未出现在 DataRefinery 收集器设置对话框的可用收集器列表中

collectorlist.png

  • 则可能是其动态链接库已移位,或者
  • 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”*文件中。

  1. 在 Visual Studio 中打开 Gurux DataRefinery 解决方案(*“GuruxDataRefinery.sln”*)。
  2. 在 *Processors* 目录中创建一个 ClassLibrary 项目。

    createproc1.png

    注意: 在 *Processors* 目录中创建 ClassLibrary 项目至关重要,如果创建在其他地方,则后期生成事件(请参阅下一步)将无法正常工作。

  3. 复制现有 GXProcessor(Gurux Gaussian Filter Processor 或 Gurux Data Joiner Processor)的后期生成事件,并将其粘贴到新处理器的后期生成事件中。这将在生成项目后,将新处理器的动态链接库(*.dll* 文件)复制到相关目录(例如:*bin\debug\processors*)。

    createproc2.png

  4. Gurux.DataRefineryAddIn 项目添加为引用。

    createproc3.png

  5. 让类继承 GXDataProcessor 并实现它。另外,重置最大值。
    namespace GuruxAlertProcessorSample
    {
        public class GXAlertProcessorSample : GXDataProcessor
        {
            double m_Maximum = 0;
        }
    }
  6. 实现 Maximum,即数据表的值将与之进行比较的值。
    当用户更改最大值时,所有数据都将更新,并调用 ForceUpdate 方法。
    public double Maximum
        {
            get
            {
                return m_Maximum;
            }
            set
            {
                bool change = m_Maximum != value;
                m_Maximum = value;
                if (change)
                {
                    ForceUpdate();
                }
            }
        }
    }
  7. 然后,实现新处理器的基本属性
    • TypeName
    • 描述
  8. 接下来,实现实际检查数据表每个单元格的代码,如果超过最大值,则报告错误。
     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);
                                }
                            }
                        }
                    }
                }
            }
  9. 生成您的项目。

故障排除

如果您创建的 GXProcessor 未出现在 DataRefinery 处理器设置对话框的可用处理器列表中

processorlist.png

  • 则可能是其动态链接库已移位,或者
  • 则可能是 GXDataProcessor 未正确继承。

要使 GXProcessor 生效:

  • 确保处理器的 *.dll* 文件存在于数据精炼器的 *Processors* 目录中。
  • 确保 GXDataProcessor 已继承到该类并正确实现,如上面示例的第 5 步所示。

改进和补充

本文最初发布于 2010 年 4 月 22 日。当时,它包含了一个创建您自己的数据收集器的示例。

五月初,我们收到一封电子邮件,报告了源代码中的一个错误:收集器可以正常检索数据,但更新到处理器时不起作用。该错误已修复,并于 5 月 5 日发布了新的源代码。

我们收到了许多关于 Gurux DataRefinery 的积极反馈,因此我们修订了本文,并添加了“第二部分”。第二部分提供了创建您自己的数据处理器的示例代码和说明。修订后的文章以及源代码目录的又一个更新版本(包含必要的示例代码)于 2010 年 5 月 11 日发布。

© . All rights reserved.