首页 > 解决方案 > Process Historian 的 MongoDB 时间序列:通过 _id 字段的不同字节进行查询

问题描述

我想将时间序列数据存储在 mongodb 中。我知道,我知道,网上有很多关于这个的文章,但没有一篇能完全解决我的问题,其中许多是指旧的 mmap 存储引擎,我使用 WiredTiger,其中许多处理等距时间序列。目的是在读取和写入吞吐量之间实现最佳折衷,同时确保最大的可扩展性(甚至是 TB 的时间序列数据)和最小的磁盘存储大小/内存消耗。这也意味着最少数量的索引。历史学家需要能够导入过去的数据,这就是为什么新数据并不总是随着时间戳的增加而添加。我已经开发了一个简约的模式:

{
    "_id": "f061e95ae4dc281aea4df2f8",
    "Values": [
        {
            "Time": "2018-05-02T07:56:40.545Z",
            "Value": "529"
        },
        {
            "Time": "2018-05-02T07:56:51.119Z",
            "Value": "254"
        },
...
    ]
}

该文档表示属于一个信号和一个一小时时间的一大块数据(数据的特征是最小但不等距的采样时间约为 1 秒)。该集合仅包含像这样的文档,并且只有一个索引(当然在 _id 上)。文档的 _id 是根据该信号的唯一标识符的哈希和数据桶所属的 UTC 小时的开始生成的。

如您所见,为了查询数据,我根据给定的时间范围和信号标识符计算了一组 id。_id 的前 4 个字节编码 UTC 小时,后 8 个字节编码信号标识符的散列。因此,查询一个信号的一天数据将导致查询尝试检索 24 个 id。问题是:对于较大的时间范围(例如从纪元开始到现在),我必须查询很多 ID(例如 400000),这似乎使查询变得很慢。(缩短的)mongodb db 查询(在 C# 中):

FilterDefinition<DBTimeSeries> f = Builders<DBTimeSeries>.Filter.Empty;
var filterbuilder = Builders<DBTimeSeries>.Filter;
IEnumerable ids = Helpers.GetIDs(start, end, tagname);
var f = Builders<DBTimeSeries>.Filter.Empty;
f = f & filterbuilder.In(x => x.ID, ids);
var chunks = await collection.FindAsync<DBTimeSeries>(f);

即使数据库中有少量数据,此查询也需要一分钟才能执行。ID 属性是来自 mongodb C# 驱动程序的“ObjectId”类型。

我知道这是可能的

f = f & filterbuilder.Where(x => x.ID > new ObjectId(DateTime.Now.AddDays(-1), 0, 0, 0) && x.ID < new ObjectId(DateTime.Now, 0, 0, 0))

这意味着我可以对 ID 进行时间范围查询,但这并不能让我在不向上述文档添加额外字段的情况下查询数据以获取一个特定信号。我什至不得不索引这个字段以获得更好的性能。

因此,我的问题是:最好能够通过如下查询来查询 _id:“给我 _id 字段的前 4 个字节表示 x 和 y 之间的 uint32 并且 _id 字段的最后 8 个字节的文档是等于给定的unit64"。查询应该专门使用索引,这应该是可能的,因为所有信息都存储在 _id 字段中。我知道 $bitsAllSet 选项(https://docs.mongodb.com/manual/reference/operator/query/bitsAllSet/#op._S_bitsAllSet),但我只能在 C# 驱动程序中传递很长的时间并且查询似乎不是能够为查询的 $bitsAllSet 部分使用索引...

有人有想法吗?谢谢大家。

标签: mongodbtime-series

解决方案


推荐阅读