NxN 数据聚合的数据存储设计

Data Store Design for NxN Data Aggregation

我正在尝试为数据聚合和存储的 NxN 问题提出一个理论解决方案。例如,我有大量数据通过流传入。流以点为单位发送数据。每个点有 5 个维度:

  1. Location
  2. Date
  3. Time
  4. Name
  5. Statistics

然后需要聚合和存储此数据,以允许另一个用户来查询位置和时间数据。用户应该能够像下面这样查询(伪代码):

Show me aggregated statistics for Location 1,2,3,4,....N between Dates 01/01/2011 and 01/03/2011 between times 11am and 4pm

不幸的是,由于数据的规模,不可能从动态点聚合所有这些数据,因此需要在此之前进行聚合。正如您所看到的,尽管可以在多个维度上聚合数据。

他们可以查询任意天数或地点,因此找到所有组合需要大量的预聚合:

  • Record for Locations 1 Today
  • Record for Locations 1,2 Today
  • Record for Locations 1,3 Today
  • Record for Locations 1,2,3 Today
  • etc... up to N

在查询之前对所有这些组合进行预处理可能会导致不可行的处理量。如果我们有 200 个不同的位置,那么我们就有 2^200 种组合,这几乎不可能在任何合理的时间内预先计算。

我确实考虑过在 1 维上创建记录,然后可以在请求时即时进行合并,但这也需要大量时间。

问题:

  1. 考虑到用户可能会查询所有维度,我应该如何选择正确的维度 and/or 维度组合?
  2. 有没有我可以参考的案例研究、我可以阅读的书籍或您能想到的任何其他有用的东西?

感谢您的宝贵时间。

编辑 1

当我说将数据聚合在一起时,我的意思是将其他维度的统计数据和名称(维度 4 和 5)结合起来。因此,例如,如果我请求位置 1、2、3、4..N 的数据,那么在将其提供给用户之前,我必须将这 N 个位置的统计信息和名称计数合并在一起。

同样,如果我请求日期为 01/01/2015 - 01/12/2015 的数据,那么我必须汇总这些时间段之间的所有数据(通过相加求和 name/statistics)。

最后,如果我要求在日期 01/01/2015 - 01/12/2015 之间获取位置 1、2、3、4..N 的数据,那么我必须汇总这些日期之间所有这些位置的所有数据。

为了这个例子,让我们假设通过统计需要某种嵌套循环并且不能很好地扩展,尤其是在运行中。

你有很多数据。由于您要解析的数据量很大,所有方法都将花费大量时间。 我有两种方法可以给。 第一个是残酷的,你可能想不通了:

id | location | date | time | name | statistics
0  | blablabl | blab | blbl | blab | blablablab
1  | blablabl | blab | blbl | blab | blablablab
ect.

有了这个,你可以轻松解析和获取元素,它们都在同一个table,但解析时间长,table巨大

我觉得第二个更好:

Multiple tables:
id | location
0  | blablabl

id | date
0  | blab

id | time
0  | blab

id | name
0  | blab

id | statistics
0  | blablablab

有了这个,您可以更快地解析(很多),获取 ID,然后获取所有需要的信息。 它还允许您准备所有数据: 您可以让位置按位置排序,时间按时间排序,名称按字母排序,等等,因为我们不关心 ID 的混合方式: 如果 id 是 1 2 3 或 1 3 2,没有人真正关心,如果您的数据已经在它们各自的 tables 中被解析,那么您的解析速度会快得多。

所以,如果你用我给的第二种方法:在你收到一个数据点的那一刻,给他的每一列都赋予一个ID:

You receive:
London 12/12/12 02:23:32 donut verygoodstatsblablabla
You add the ID to each part of this and go parse them in their respective columns:
42 | London ==> goes with London location in the location table
42 | 12/12/12 ==> goes with 12/12/12 dates in the date table
42 | ...

有了这个,你想获得伦敦的所有数据,它们都是并排的,你只需要获取所有的 id,并获得其他数据。如果你想获取 11/11/11 和 12/12/12 之间的所有数据,它们都是并排的,你只需要获取 ids ect..

希望我有所帮助,抱歉我的英语不好。

试试时间序列数据库!

根据您的描述,您的数据似乎是一个时间序列数据集。 用户在查询时似乎最关心时间,选择时间范围后,用户会通过附加条件细化结果。

考虑到这一点,我建议您尝试 时间序列数据库,例如 InfluxDB or OpenTSD。 例如,Influx 提供了一种能够处理如下查询的查询语言,这与您要实现的目标非常接近:

SELECT count(location) FROM events
WHERE time > '2013-08-12 22:32:01.232' AND time < '2013-08-13'
GROUP BY time(10m);

我不确定你所说的 scale 是什么意思,但是时间序列数据库被设计成可以快速处理大量数据点。 我建议在推出您自己的解决方案之前一定要试一试!

您应该查看 Apache Flume 和 Hadoop http://hortonworks.com/hadoop/flume/#tutorials

flume 代理可用于捕获数据并将其聚合到 HDFS 中,您可以根据需要对其进行扩展。一旦它在 HDFS 中,就有许多选项可以可视化,甚至可以使用 map reduce 或弹性搜索来查看您在提供的示例中查找的数据集。

我曾使用过包含十万种产品和一万家商店的销售点数据库(通常是周级汇总销售额,但也包括用于购物篮分析、交叉销售等的收据级资料)。我建议你看看这些:

  • Amazon Redshift,可扩展性强,上手相对简单,性价比高
  • Microsoft Columnstore Indexes,压缩数据并具有熟悉的 SQL 界面,相当昂贵(AWS 的 1 年预留实例 r3.2xlarge 约为 37.000 美元),没有关于如何在集群内扩展的经验
  • ElasticSearch is my personal favourite, highly scalable, very efficient searches via inverted indexes, nice aggregation framework,无许可费用,有自己的查询语言但简单的查询很容易表达

在我的实验中,ElasticSearch 在相同硬件上比 Microsoft 的列存储或聚簇索引表快 20 - 50% 用于中小型查询。要获得快速响应时间,您必须有足够的 RAM 以在内存中加载必要的数据结构。

我知道我错过了许多其他数据库引擎和平台,但我最熟悉这些。我也使用过 Apache Spark,但不是在数据聚合环境中,而是用于分布式数学模型训练。

非规范化是一种解决关系数据库性能或可扩展性的方法。
IMO 有一些新表来保存汇总数据并使用它们进行报告将对您有所帮助。

I have a huge amount of data that comes in via a stream. The stream sends the data in points.

案例中会有多种方式实现反规范化:

  • 为流式传输中的数据聚合功能添加新的并行端点 等级
  • 正在安排作业以在 DBMS 级别聚合数据。
  • 使用DBMS触发机制(效率较低)

在理想情况下,当一条消息达到流级别时,将有两份包含 location, date, time, name, statistics 维度的数据消息副本被分派进行处理,一份用于 OLTP(current application logic) second will goes for an OLAP(BI) 处理。
BI 流程将为报告创建非规范化聚合结构。
我会建议按位置、日期组汇总数据记录。

因此最终用户将查询不需要大量重新计算的预处理数据,有一些可以接受的不准确性。

How should I go about choosing the right dimension and/or combination of dimensions given that the user is as likely to query on all dimensions?

这取决于您的应用程序逻辑。如果可能,限制用户使用可由用户分配值的预定义查询(例如日期从 01/01/2015 到 01/12/2015)。在更复杂的系统中,可以选择在 BI 仓库之上使用报告生成器。
我推荐 Kimball's The Data Warehouse ETL Toolkit

是否真的有一种方法可以在不以某种方式强制执行的情况下做到这一点?

我只熟悉关系数据库,而且我认为解决这个问题的唯一真正方法是按照之前的建议使用平面 table,即将所有数据点作为单个 [=38= 中的字段].我想您只需要决定如何执行此操作以及如何对其进行优化。

除非你要保持100%到单条记录的准确率,那我觉得这个问题真的需要,我们能扔掉什么。

我认为我的方法是:

  1. 算出最小的时间片段是什么,并在其上量化时域。例如每条可分析记录的时长为 15 分钟。
  2. 将原始记录一起收集到原始 table 中,但随着量化 window 通过,将行汇总到分析中 table(15 分钟 window).
  3. 可以通过对时间不太敏感的例程来删除旧的原始记录。
  4. Location 看起来像一个限制集,所以使用 table 将它们转换为整数。
  5. 索引摘要中的所有列 table。
  6. 运行 查询。

显然我敢打赌,以这种方式量化时域是可以接受的table。您也可以通过按时域查询原始数据来提供交互式向下钻取,但这仍然很慢。

希望对您有所帮助。

马克

您至少可以将日期和时间减少到一个维度,并根据您的最小粒度预先聚合您的数据,例如1 秒或 1 分钟分辨率。为相同的分辨率缓存和分块您的传入流可能很有用,例如每秒将总计附加到数据存储,而不是更新每个点。

名称和位置域更改的规模和可能性是多少?它们之间有什么关系吗?您说位置可能多达 200 个。我在想,如果 name 是一个非常小的集合并且不太可能更改,您可以在单个记录中的每个名称列中保存名称计数,从而减少 table 到每单位时间每个位置 1 行。