让我们说我有一个非常大的数据集(数十亿条记录),一个数据集无法容纳在一台机器上,并且我想进行多个未知查询(它是一项服务,用户可以选择该数据集的某个子集,而我需要返回该子集的最大值。
对于计算本身,我正在考虑使用Spark或类似工具,问题是Im将具有大量IO /网络活动,因为Spark必须不断从磁盘读取数据集并将其分发到这些工人,而不是例如在集群启动时让Spark在工人之间分配数据,然后只是要求每个工人对某些记录进行工作(例如,按其编号)。
那么,对于这里的大数据人员来说,您通常会做什么?只是让Spark重做每个请求的读取和分发吗? 如果我想做我上面说的话,我别无选择,只能写我自己的东西吗?
答案 0 :(得分:0)
如果查询已知,但子集未知,则可以为许多较小的数据窗口/切片预先计算最大值(或其他运算符)。这为您提供了一个小的且易于查询的排序索引,这可能使您可以计算任意子集的最大值。如果子集不能像切片那样整齐地开始和结束,则只需处理“最外面的”部分切片即可得到结果。
如果查询未知,则可能要根据具体情况考虑将数据存储在MPP数据库中或使用OLAP多维数据集(Kylin,Druid?);或者您可以将数据以Parquet等列格式存储,以进行有效的查询。
答案 1 :(得分:0)
这是一个基于OP对我的其他答案的评论中的问题描述的预先计算的解决方案:
上百万个条目,每个条目具有3k个名称->数字对。给定一百万个条目的子集和名称的子集,您需要该子集中所有条目的每个名称的平均值。因此,一百万个条目的每个可能子集(每个可能的大小)太多了,无法计算和保留。
首先,我们将数据分成较小的“窗口”(碎片,页面,分区)。
假设每个窗口包含约1万行,每行约有20k个不同的名称,每行中有3k(名称,值)对(选择窗口大小可能会影响性能,使用较小的窗口可能会更好)。
假设每个名称的〜24个字节和2个字节的值,则每个窗口包含10k * 3k *(24 + 2字节)= 780 MB的数据以及一些我们可以忽略的开销。
对于每个窗口,我们都会预先计算每个名称的出现次数,以及该名称的值之和。使用这两个值,我们可以在任何一组窗口上计算名称的平均值,如下所示:
Average for name N = (sum of sums for N)/(sum of counts for N)
这是一个数据量少的小例子:
Window 1
{'aaa':20,'abcd':25,'bb':10,'caca':25,'ddddd':50,'bada':30}
{'aaa':12,'abcd':31,'bb':15,'caca':24,'ddddd':48,'bada':43}
Window 2
{'abcd':34,'bb':8,'caca':22,'ddddd':67,'bada':9,'rara':36}
{'aaa':21,'bb':11,'caca':25,'ddddd':56,'bada':17,'rara':22}
Window 3
{'caca':20,'ddddd':66,'bada':23,'rara':29,'tutu':4}
{'aaa':10,'abcd':30,'bb':8,'caca':42,'ddddd':38,'bada':19,'tutu':6}
带有总和和计数的预先计算的窗口1“索引”:
{'aaa':[32,2],'abcd':[56,2],'bb':[25,2],'caca':[49,2],'ddddd':[98,2],'bada':[73,2]}
此“索引”将包含大约20k个不同的名称和每个名称两个值,或20k *(24 + 2 + 2字节)= 560 KB的数据。这比数据本身少一千倍。
现在让我们付诸行动:假设输入跨越100万行,您将需要加载(1M / 10k)= 100索引或56 MB,这很容易装入单台计算机的内存中(哎呀,放入智能手机的内存中。
但是,由于您正在汇总结果,因此您可以做得更好;您甚至不需要一次加载所有索引,您可以一次加载一个索引,对值进行过滤和求和,然后在加载下一个索引之前将其丢弃。这样,您仅需几兆字节的内存就可以做到这一点。
更重要的是,任何一组窗口和名称的计算时间都不应超过几秒钟。如果名称按字母顺序排序(另一项值得进行的优化),则可获得最佳性能,但即使使用未排序的列表,其运行速度也应足够快。
剩下的唯一一件事情就是处理输入范围与预定窗口不完全对齐的情况。对于输入范围的两个“末端”,这需要一点逻辑,但是可以轻松地将其内置到您的代码中。
说每个窗口从星期一到星期日恰好包含一周的数据,但是您输入的内容指定了一个从星期三开始的时间段。在这种情况下,您将必须加载第一周的星期三至星期日的实际原始数据(如上所述,几百兆字节),以首先计算每个名称的(计数,总和)元组,然后将索引用于输入范围的其余部分。
这确实增加了一些处理时间,但是上限为2 * 780MB,仍然非常适合在一台计算机上。
至少我会那样做。