跳转到主要内容
Chinese, Simplified

在《时间序列数据和MongoDB:第1部分-简介》中,我们回顾了理解数据库的查询访问模式需要询问的关键问题。在《时间序列数据和MongoDB:第2部分-模式设计最佳实践》中,我们探索了时间序列数据的各种模式设计选项,以及它们如何影响MongoDB资源。在这篇博客文章中,我们将讨论如何查询、分析和呈现存储在MongoDB中的时间序列数据。了解客户端如何连接查询您的数据库将有助于指导您设计数据模型和最佳数据库配置。有多种方式可以查询MongoDB。您可以使用本地工具,如MongoDB Shell命令行和MongoDB Compass(基于gui的查询工具)。通过编程方式,MongoDB数据是通过一个广泛的MongoDB驱动程序列表访问的。几乎所有主要编程语言都有驱动程序,包括c#、Java、NodeJS、Go、R、Python、Ruby和许多其他语言

MongoDB还通过使用MongoDB BI连接器提供了第三方BI报告工具集成。流行的基于sql的报表工具,如Tableau、Microsoft PowerBI、QlikView和TIBCO Spotfire,可以直接利用MongoDB中的数据,而不需要将数据ETL到另一个平台进行查询。MongoDB图表,目前处于测试阶段,提供了可视化您的MongoDB数据的最快方法,不需要第三方产品或扁平化您的数据,以便它可以被sql -base BI工具读取。

在这个博客中,我们将介绍使用上述工具查询、分析和呈现时间序列数据。

使用聚合框架查询

MongoDB聚合框架允许开发人员表达执行数据准备、转换和分析的功能管道。这是通过使用一些阶段来完成的,这些阶段执行特定的操作,如分组、匹配、排序或调整数据。流经各个阶段及其相应处理的数据称为聚合管道。从概念上讲,它类似于通过Unix shell命令行管道的数据流。数据从前一阶段获得输入,工作被执行,该阶段的输出作为下一个处理阶段的输入,直到管道结束。图1显示了数据如何流经由匹配和分组阶段组成的管道。

图1:示例数据流经聚合管道

' $match '是这两个阶段管道中的第一个阶段。' $match '将把整个订单集合作为输入,并提供一个包含文档列表的过滤器作为输出,其中字段" status "包含" a "值。第二阶段将这些过滤后的文档作为输入,并对数据进行分组,以生成所需的查询结果作为输出。虽然这是一个简单的示例,但请记住,您可以构建非常复杂的处理管道,利用25个不同阶段类上的100多个运算符,允许您执行诸如转换、编校、排序、分组、匹配、分面搜索、图遍历和不同集合之间的联接等操作。您可以使用其他分布式数据库无法使用的方式处理数据。

对于时间序列数据,我们将使用MongoDB Compass发出一个特别查询,查找给定股票的当天最高价格。Compass是一种GUI工具,它允许您轻松地探索数据。一个有用的特性是能够可视化地构建一个聚合管道,方法是将阶段组装到画布上,然后将结果管道导出为代码,以便复制和粘贴到应用程序中。

为某只股票寻找日高点

在深入研究查询本身之前,回想一下在本博客系列的第2部分中描述的StockGen应用程序,它为我们想要跟踪的5只股票生成了一个月的股价数据。创建的两个集合之一称为“StockDocPerMinute”,它包含一个表示特定股票符号的一分钟数据的文档,如图2所示。

{
            "_id" : ObjectId("5b57a8fae303d36d6df69cd3"),
            "p" : {
                        "0" : 58.75,
                        "1" : 58.75,
                        "2" : 59.45,
…up to…
                        "58" : 58.57,
                        "59" : 59.01
            },
            "symbol" : "FB",
            "d" : ISODate("2018-07-14T00:00:00Z")
}

图2:StockDocPerMinute文档示例

考虑这样一个场景:应用程序为给定的股票行情请求当天最高的价格。如果没有聚合框架,这个查询必须通过检索所有数据返回到应用程序并使用客户端代码计算结果来完成,或者通过在Javascript中定义一个map-reduce函数来完成。从性能或开发人员生产力的角度来看,这两种选择都不是最佳的。

注意,示例文档有一个子文档,其中包含整个分钟间隔的数据。通过使用聚合框架,我们可以轻松地处理此子文档,方法是使用$objectToArray表达式将子文档转换为数组,计算最大值并投影所需的结果。

使用MongoDB指南针,我们可以构建查询使用聚合管道构建器如下:

 

图7:第五阶段是$sort阶段

我们可以看到,最后一个阶段的输出显示的是每天的最大值。使用聚合管道构建器,我们不需要编写任何代码。为了便于参考,上图中MongoDB Compass构建的完整查询如下图所示:


db.getCollection('StockDocPerMinute').aggregate([
{ $match: { "symbol" : "FB" }

},
{"$project": 

"year": {"$year": "$d"}, 
"month": {"$month": "$d"}, 
"dayOfMonth": {"$dayOfMonth": "$d"},
"p": {"$objectToArray": "$p"},
"Symbol":1
} },
    {"$addFields": {"tmax": {"$max": '$p.v'}}},
    {"$group": {
                            _id: {           
                                year: '$year',
                                month: '$month',
                                dayOfMonth: '$dayOfMonth'
                            },
                            "DayMax": {$max: "$tmax"},
                            }
                        },
   {$sort: {_id: -1}}
])

利用视图

MongoDB只读视图可以从现有的集合或其他视图创建。这些视图充当只读集合,并在读取操作期间按需计算。由于它们以另一个集合的形式出现,您可以通过限制对视图的底层集合的访问,并只给予客户端对视图的读访问权限,来添加一层安全性。如果你想了解更多关于视图访问控制的知识,请阅读博客文章“提供对MongoDB数据的最低权限访问”。

要查看视图是如何创建的,请考虑用户希望查询股票价格历史记录的场景。我们可以使用createView语法在StockDocPerMinute集合上创建一个视图,如下所示:

db.createView("ViewStock","StockDocPerMinute", 
[
{"$project": {"p": {"$objectToArray": "$p"}, "d":1, "symbol":1}},
{"$unwind": "$p"},
{"$project": {"_id": 0, "symbol":1,"Timestamp": {
   "$dateFromString": {"dateString":
                           {"$concat": [{"$dateToString":
                                             {"format": "%Y-%m-%dT%H:%M:",
                                              "date": "$d"}},
                                        {"$concat": ["$p.k", "Z"]}]}}}, 
                                        "price":"$p.v"}}
                                    ])

由于MongoDB只读视图是在运行时具体化的,所以每个查询都可以获得最新的结果。既然已经定义了视图,就可以像访问其他集合一样访问它了。例如,使用我们可以发出的视图查询“FB”股票的第一个价格条目:

db.ViewStock.find({ "symbol":"FB" } ) .sort({d:-1}).limit(1)

您还可以对视图使用聚合框架。下面是某个特定日期的所有“FB”股票行情数据的查询。

db.ViewStock.aggregate({ $match: { 
"symbol":"FB",
 "Timestamp" : { $gte: ISODate("2018-06-26"), $lt: ISODate("2018-06-27") }}},
 { $sort: { "Timestamp": -1 }
})

使用第三方BI报告工具查询时间序列数据

用户可能希望利用对第三方商业智能报告和分析工具的现有投资。要使这些讲sql的工具能够查询MongoDB中的数据,您可以使用称为MongoDB BI连接器的中间服务。

图8:使用BI连接器使用您喜欢的基于sql的报告工具查询MongoDB数据

BI Connector服务向客户机应用程序提供一个类似于MySQL服务器的端口,并接受发出SQL查询的客户机连接。BI连接器服务然后将这些查询转换为MongoDB查询语言(MQL),并将查询提交给MongoDB数据库。结果从MongoDB返回,并被扁平化为一个表格结构,然后发送回说SQL的客户端。该流的详细信息见图8。

为了演示MongoDB BI连接器的实际应用,让我们使用Tableau Desktop和MongoDB BI连接器来使用时间序列数据。Tableau Desktop有一个MongoDB的连接选项。使用该选项并连接到BI连接器中指定的端口,我们可以看到Tableau枚举了来自MongoDB数据库的表列表,如图9所示。

图9:Tableau中的数据源视图,显示从MongoDB BI连接器返回的信息

这些表实际上是我们在MongoDB中的集合。继续使用Tableau中的工作表视图,我们可以继续使用之前在本文档中创建的视图构建一个显示价格随时间变化的报告。

 

图10:显示价格随时间变化的示例表格工作表

MongoDB图表

在MongoDB中可视化数据的最快方法是使用MongoDB图表。目前测试版中,它为用户提供了一个网络控制台,用户可以直接从存储在MongoDB中的数据构建和运行报告。有了图表,就不需要运行特殊的服务来查询MongoDB。也不需要将数据移出或将其转换为要查询的不同格式。数据可以直接查询存储在MongoDB的富文档。与其他只读连接一样,您可以将图表连接到次要副本节点,从而将分析和报告查询与服务于操作时间序列应用程序的集群的其余部分隔离开来。要查看MongoDB图表如何表示来自StockGen工具的数据,请查看价格随时间变化曲线图,如图11所示。

图11:显示价格随时间变化的MongoDB图表

在撰写本文的时候,MongoDB图表还处于测试阶段,因此细节和屏幕截图可能与最终版本有所不同。

用MongoDB分析

除了发行高级分析与MongoDB查询聚合框架,MongoDB连接器为Apache火花暴露引发所有的库,包括Scala、Java、Python和r .这使您能够使用火花大数据分析引擎处理时间序列数据的扩展分析功能的MongoDB进一步进行实时分析和机器学习。连接器将MongoDB数据物化为数据数据库和数据集,以便通过机器学习、图表、流和SQL api进行分析。Spark连接器利用MongoDB的聚合管道和丰富的二级索引来提取、过滤和处理所需的数据范围!没有浪费时间提取和加载数据到另一个数据库,以查询您的MongoDB数据使用Spark!

Figure 12: Spark connector for MongoDB

MongoDB R驱动程序为开发人员和统计人员提供了使用惯用的、本地语言访问MongoDB、企业身份验证和对BSON数据类型的全面支持的一流体验。使用R可用的大量库,您可以查询MongoDB时间序列数据并确定局部加权回归,如图13所示。

图13:散点图,显示价格随时间的变化和每秒数据的平滑

MongoDB的R驱动程序可以通过CRAN R归档文件获得。一旦安装,你可以连接到你的MongoDB数据库,并返回可以在R计算中使用的数据。上面的图是用R Studio用以下代码生成的:

library(mongolite)
<p>ts=mongo(collection="StockDocPerSecond", db="Stock", url="mongodb://localhost:27020")</p>
<p>fbquery=ts$find('{ "symbol":"FB"}', fields='{"_id":0, "d":1, "p":1 }')</p>
<p>plot(fbquery$d,fbquery$p, xlab="Date", ylab="Price", main="Price over Time");</p>
<p>lines(lowess(fbquery$d,fbquery$p), col=2);

总结

虽然并非所有的数据在本质上都是时间序列,但越来越多的数据可以被归类为时间序列——这是由允许我们实时而不是批量利用数据流的技术所推动的。每个行业、每个公司都需要对时间序列数据进行查询、分析和报告。真正的业务价值来自于从数据中获得的分析和见解。MongoDB使您能够收集、分析和处理环境中的每个时间序列数据。在这个由三部分组成的系列文章中,我们讨论了一些与特定应用程序需求相关的发人深省的问题。在第二篇博客文章中,我们介绍了几种不同的时间序列模式设计及其对MongoDB性能的影响。最后,我们总结了如何使用MongoDB聚合框架和MongoDB Compass查询时间序列数据,以及使用BI连接器和分析语言(如R)等其他方法。

原型是一回事,但有效地处理TB级数据则是另一回事。使用MongoDB可以很容易地水平扩展时间序列工作负载。通过使用副本集,只读客户端可以连接到副本集辅助服务器来执行查询,而让主服务器专注于写操作。此外,读重工作负载和写重工作负载都可以通过分片进行水平伸缩。虽然对MongoDB架构的深入分析超出了这些博客文章的范围,但你可以在MongoDB架构白皮书中找到很多有用的信息。

物联网(IoT)用例生成过多的时间序列数据。更大的物联网解决方案包括支持用于数据摄入的各种硬件和软件设备,支持实时和历史分析、安全性、高可用性和大规模管理时间序列数据等。MongoDB正在为全球关键的物联网应用提供动力。如需更多关于物联网的信息,请访问物联网网站。

 

原文:https://www.mongodb.com/blog/post/time-series-data-and-mongodb-part-3--querying-analyzing-and-presenting-timeseries-data

本文:http://jiagoushi.pro/node/1341

讨论:请加入知识星球【首席架构师智库】或者小号【jiagoushi_pro】或者QQ群【11107777】

Tags
 
Article
知识星球
 
微信公众号
 
视频号