12

我们有一个庞大且不断增长的实验数据数据集,该数据集取自大约 30,000 名受试者。对于每个主题,都有多个数据记录。在每个记录中,收集了几个时间序列的生理数据,每个时间序列长约 90 秒,采样频率为 250Hz。我应该注意,时间序列的任何给定实例都不会扩展,只会将其他记录添加到数据集中。这些录音的长度也不相同。目前,每个记录的数据都包含在其自己的平面文件中。这些文件被组织在一个目录结构中,该目录结构按整个实验的版本、实验位置、日期和实验终端(按该分层顺序)分层分解。

我们的大部分分析都是在 MATLAB 中完成的,我们计划继续广泛使用 MATLAB 进行进一步分析。当所有研究人员都在同一地点时,目前的情况是可行的(如果不需要的话)。我们现在遍布全球,我正在研究使所有这些数据从远程位置可用的最佳解决方案。我精通 MySQL 和 SQL Server,并且可以很容易地想出一种在这种范式中构建这些数据的方法。然而,我对这种方法的效率持怀疑态度。我会重视任何可能为我指明正确方向的建议。我应该考虑不同的东西吗?时间序列数据库(尽管在我看来,这些数据库似乎已针对扩展现有时间序列进行了调整)?还有什么?

分析不需要在线完成,但这样做的可能性会是一个加分项。目前,我们的典型用例是查询特定的记录子集并拉下相关的时间序列以进行本地分析。我很感激你的任何建议!

更新:

在我的研究中,我发现了这篇论文,他们在其中存储和分析了非常相似的信号。他们选择 MongoDB 的原因如下:

  • 发展速度
  • 向现有文档中添加字段的便利性(从信号中提取的特征等)
  • 通过 MongoDB API 本身轻松使用 MapReduce

这些对我来说都是有吸引力的优势。开发看起来非常简单,使用分析结果轻松扩充现有文档的能力显然很有帮助(尽管我知道这在我已经熟悉的系统中并不难做到。

需要明确的是,我知道我可以将数据存储在平面文件中,并且我知道我可以简单地安排通过网络通过 MATLAB 对这些平面文件进行安全访问。我想将这些数据存储在数据库中的原因有很多。例如:

  • 除了上述的层次结构之外,现在平面文件几乎没有结构。例如,如果不提取特定日期每个终端的所有单个文件,就不可能提取特定日期的所有数据。
  • 无法查询与特定记录关联的元数据。例如,我不禁想到我需要跳过以提取女性受试者的所有数据的箍。

总而言之,我想将这些数据存储在数据库中,原因有很多(空间、效率和易于访问的考虑等)。

更新 2

我似乎没有充分描述这些数据的性质,所以我将尝试澄清。这些记录当然是时间序列数据,但不是很多人认为的时间序列数据。我不会持续捕获要附加到现有时间序列的数据。我确实在制作多个录音,所有录音都带有不同的元数据,但三个信号相同。这些信号可以被认为是一个数字向量,这些向量的长度因记录而异。在传统的 RDBMS 中,我可能会创建一个记录类型 A 的表,一个记录 B 类型的表,等等,并将每一行视为时间序列中的一个数据点。但是,这不起作用,因为录音的长度不同。相反,我更希望有一个代表一个人的实体,并让该实体与从该人那里获取的多个录音相关联。

潜在的 MongoDB 结构

例如,这是我为一个主题绘制的潜在 MongoDB BSON 结构:

{
    "songs": 
    {
        "order": 
        [
            "R008",
            "R017",
            "T015"
        ],
        "times": [
            { 
                "start": "2012-07-02T17:38:56.000Z",
                "finish": "2012-07-02T17:40:56.000Z",
                "duration": 119188.445
            },
            { 
                "start": "2012-07-02T17:42:22.000Z",
                "finish": "2012-07-02T17:43:41.000Z",
                "duration": 79593.648
            },
            { 
                "start": "2012-07-02T17:44:37.000Z",
                "finish": "2012-07-02T17:46:19.000Z",
                "duration": 102450.695
            }
        ] 
    },
    "self_report":
    {
        "music_styles":
        {
                "none": false,
                "world": true
        },
        "songs":
        [
            {
                "engagement": 4,
                "positivity": 4,
                "activity": 3,
                "power": 4,
                "chills": 4,
                "like": 4,
                "familiarity": 4
            },
            {
                "engagement": 4,
                "positivity": 4,
                "activity": 3,
                "power": 4,
                "chills": 4,
                "like": 4,
                "familiarity": 3
            },
            {
                "engagement": 2,
                "positivity": 1,
                "activity": 2,
                "power": 2,
                "chills": 4,
                "like": 1,
                "familiarity": 1
            }
        ],
        "most_engaged": 1,
        "most_enjoyed": 1,
        "emotion_indices":
        [
            0.729994,
            0.471576,
            28.9082
        ]
    },
    "signals":
    {
        "test":
        {
            "timestamps":
            [
                0.010, 0.010, 0.021, ...
            ],
            "eda":
            [
                149.200, 149.200, 149.200, ...
            ],
            "pox":
            [
                86.957, 86.957, 86.957, ...
            ]
        },
        "songs":
        [
            {
                "timestamps":
                [
                    0.010, 0.010, 0.021, ...
                ],
                "eda":
                [
                    149.200, 149.200, 149.200, ...
                ],
                "pox":
                [
                    86.957, 86.957, 86.957, ...
                ]
            },
            {
                "timestamps":
                [
                    0.010, 0.010, 0.021, ...
                ],
                "eda":
                [
                    149.200, 149.200, 149.200, ...
                ],
                "pox":
                [
                    86.957, 86.957, 86.957, ...
                ]
            },
            {
                "timestamps":
                [
                    0.010, 0.010, 0.021, ...
                ],
                "eda":
                [
                    149.200, 149.200, 149.200, ...
                ],
                "pox":
                [
                    86.957, 86.957, 86.957, ...
                ]
            }
        ]
    },
    "demographics":
    {
        "gender": "female",
        "dob": 1980,
        "nationality": "rest of the world",
        "musical_background": false,
        "musical_expertise": 1,
        "impairments":
        {
            "hearing": false,
            "visual": false
        }
    },
    "timestamps":
    {
        "start": "2012-07-02T17:37:47.000Z",
        "test": "2012-07-02T17:38:16.000Z",
        "end": "2012-07-02T17:46:56.000Z"
    }
}

那些signals 是时间序列。

4

3 回答 3

1

很多时候,当人们来到 NoSQL 数据库时,他们会听到没有模式和生活都是美好的。但是,恕我直言,这是一个非常错误的概念。

在处理 NoSQL 时,您必须考虑“聚合”。通常,聚合是可以作为单个单元操作的实体。在您的情况下,一种可能(但不是那么有效)的方法是将用户和他/她的数据建模为单个聚合。这将确保您的用户聚合可以与数据中心/分片无关。但是,如果数据要增长 - 加载用户也会加载所有相关数据并且会占用内存。(这样的Mongo对内存有点贪心)

另一种选择是将记录存储为聚合并“链接”回具有 id 的用户 - 这可以是您可以像 GUID 一样创建的合成密钥。尽管这表面上看起来像是一个连接,但它只是“按属性查找”——因为这里没有真正的参照完整性。如果要不断添加文件,这可能是我将采用的方法。

MongoDb 发光的地方是您可以通过文档中的属性进行临时查询的部分(如果您不想在以后失去头发,您将为该属性创建一个索引。)。在 Mongo 中选择时间序列数据存储不会出错。例如,您可以在日期范围内提取与 id 匹配的数据,而无需进行任何重大特技。

请确保无论您采用哪种方法都拥有副本集,并在早期努力选择您的分片方法 - 稍后分片并不好玩。

于 2013-07-30T05:42:06.817 回答
0

您应该真正研究 LDAP 及其数据模型。您的数据显然具有很强的层次结构特征,并且 LDAP 已经普遍用于存储有关人员的属性。它是一种成熟的标准化网络协议,因此您可以从各种实现中进行选择,而不是被锁定在某个特定的 NoSQL 风格的当月选择中。LDAP 专为分布式访问而设计,为身份验证(以及授权/访问控制)提供安全模型,并且非常高效。比这些基于 HTTP 的协议中的任何一个都重要。

于 2014-08-12T02:38:59.630 回答
0

我觉得这可能无法回答正确的问题,但我可能会这样做(使用 SQL 服务器):

用户(表)

  • 用户身份
  • 性别
  • 专业知识
  • ETC...

样品(表)

  • 样品编号
  • 用户身份
  • 开始时间
  • 期间
  • 命令
  • ETC...

系列(表)

  • 样品编号
  • SecondNumber(约 1-90)
  • 值(带值的字符串)

我认为这应该给你相当灵活的访问,以及合理的内存效率。由于这些值以字符串格式存储,因此您无法对 sql 中的时间序列进行分析(需要先对其进行解析),但我认为这应该不是问题。当然你也可以使用MeasurementNumberand Value,那么你就有了完全的自由。

当然,这并不像您的 MongoDB 设置那样完整,但是应该很容易填补空白。

于 2013-07-30T09:48:29.310 回答