MongoDB作为时间序列数据库

时间:2011-09-10 00:21:51

标签: mongodb time-series

我正在尝试将mongodb用于时间序列数据库,并且想知道是否有人可以建议如何最好地为该场景设置它。

时间序列数据与股票价格历史非常相似。我收集了来自不同机器的各种传感器的数据集。有十亿个时间戳的值,我想问下面的问题(最好是从数据库而不是应用程序级别):

  1. 对于给定的一组传感器和时间间隔,我希望按时间顺序排列在该时间间隔内的所有时间戳和传感器值。假设所有传感器共享相同的时间戳(它们都是同时采样的)。

  2. 对于给定的一组传感器和时间间隔,我希望按时间顺序排列在给定间隔内的每个第k项(时间戳和相应的传感器值)。

  3. 有关如何最好地设置并实现查询的任何建议吗?

    感谢您的建议。

3 个答案:

答案 0 :(得分:17)

显然这是一个老问题,但是当我研究MongoDB的时间序列数据时,我遇到了它。我认为可能值得分享以下方法来提前分配完整文档并执行更新操作,而不是新的插入操作。请注意,此方法已记录在herehere

想象一下,您每分钟都在存储数据。请考虑以下文档结构:

{
  timestamp: ISODate("2013-10-10T23:06:37.000Z"),
  type: ”spot_EURUSD”,
  value: 1.2345
},
{
  timestamp: ISODate("2013-10-10T23:06:38.000Z"),
  type: ”spot_EURUSD”,
  value: 1.2346
}

这与标准关系方法相当。在这种情况下,您为每个记录的值生成一个文档,这会导致大量的插入操作。我们可以做得更好。请考虑以下事项:

{
  timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"),
  type: “spot_EURUSD”,
  values: {
    0: 1.2345,
    …  
    37: 1.2346,
    38: 1.2347,
    … 
    59: 1.2343
  }
}

现在,我们可以编写一个文档,并执行59次更新。这样做要好得多,因为更新是原子的,单个写入更小,并且还有其他性能和并发优势。但是,如果我们想在一个文档中存储整天,而不仅仅是整个小时,那该怎么办呢?这将要求我们沿着1440个条目走,以获得最后一个值。为了改进这一点,我们可以进一步扩展到以下内容:

{
  timestamp_hour: ISODate("2013-10-10T23:00:00.000Z"),
  type: “spot_EURUSD”,
  values: {
    0: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343},
    1: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343},
    …,
    22: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343},
    23: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343}
  }
}

使用这种嵌套方法,我们现在只需步行,最多24 + 60即可获得当天的最后一个值。

如果我们使用预先填充的所有值构建文档,我们可以确保文档不会更改大小,因此不会移动。

答案 1 :(得分:13)

如果您不需要永久保存数据(即您不介意它'老化'),您可能需要考虑“上限集合”。上限系列有许多限制,反过来提供一些有趣的好处,听起来很符合你想要的。

基本上,上限集合具有指定的大小,文档以插入顺序写入它,直到它填满为止,此时它会回绕并开始用最新的文档覆盖最旧的文档。您可以对上限集合中的文档执行的更新略有限制 - 即。您无法执行将更改文档大小的更新(因为这意味着需要在磁盘上移动以查找额外空间)。我不明白这是你所描述的问题。

结果是,您可以保证您的上限集合中的数据将按插入顺序写入并保留在磁盘上,这样可以非常快速地查询插入顺序。

顺便说一句,传感器及其产生的数据有何不同?如果它们相对相似,我建议将它们全部存放在同一个集合中以方便使用 - 否则将它们分开。

假设您使用单个集合,那么您的查询听起来都非常可行。要记住的一件事是,要获得上限集合的好处,您需要根据集合的“自然”顺序进行查询,因此通过时间戳键查询将不会那么快。如果读数是定期进行的(因此您知道在给定的时间间隔内将采取多少读数),我建议查询1的内容如下:

db.myCollection.find().limit(100000).sort({ $natural : -1 })

假设,例如,您每秒存储100个读数,上面将返回最后100秒的数据。如果您想要前100秒,则可以添加.skip(100000)

对于你的第二个查询,听起来像你需要MapReduce,但听起来并不是特别困难。您可以通过与上述类似的查询选择您感兴趣的文档范围,然后使用map函数选择您感兴趣的区间文档。

以下是关于上限集合的Mongo文档:http://www.mongodb.org/display/DOCS/Capped+Collections

希望这有帮助!

答案 2 :(得分:0)

我知道这是一个老问题,但我发现这些博客对我帮助很大: