我试图想出一个算法来解决我遇到的这个问题。这不是硬件问题,而是我正在进行的一个副项目。
表格A 大约有10 ^ 5行的顺序,并且每天以10 ^ 2的顺序添加新的行。
表B 大约有10 ^ 6行,每天新增10 ^ 3。从A到B有一对多关系(A中某些行有很多B行)。
我想知道如何为这种数据进行连续聚合。我希望每隔约10分钟运行一次这样的工作并执行此操作:对于A中的每一行,查找在最后一天,一周和一个月中创建的B中与其相关的每一行(然后按计数排序)并保存他们在不同的数据库中或缓存它们。
如果这令人困惑,这里有一个实际的例子:Say表A有亚马逊产品,表B有产品评论。我们希望在过去4小时,每天,每周等显示最高评价的产品排序列表。新产品和评论会快速添加,我们希望上述列表能够达到最佳状态 - 尽可能的日期。
我当前的实现只是一个for循环(伪代码):
result = []
for product in db_products:
reviews = db_reviews(product_id=product.id, create>=some_time)
reviews_count = len(reviews)
result[product]['reviews'] = reviews
result[product]['reviews_count'] = reviews_count
sort(result, by=reviews_count)
return result
我每小时都这样做,并将结果保存在json文件中以供服务。问题是,这并不能很好地扩展,并且需要很长时间才能进行计算。
那么,我在哪里可以解决这个问题呢?
更新
感谢您的回答。但我最终学习并使用Apache Storm。
答案 0 :(得分:1)
在数据库中有两个较大的表,您需要定期为过去的时间段(小时,天,周等)创建一些聚合,并将结果存储在另一个数据库中。
我将假设,一旦过去一段时间,相关记录就没有变化,换句话说,过去一段时间的汇总总是有相同的结果。
Luigi是管道相关任务的框架,其中一个典型用途是计算过去时期的聚合。
概念如下:
简而言之:如果目标存在,任务就完成了。
这适用于多种类型的目标,例如本地文件系统,hadoop,AWS S3以及数据库中的文件。
为了防止半成品结果,目标实现会处理原子性,例如,文件首先在临时位置创建,并在完成后立即移动到最终目的地。
在数据库中有一些结构可以表示某些数据库导入已完成。
您可以自由创建自己的目标实现(它必须创建一些东西并提供方法exists
来检查,结果存在。
对于您描述的任务,您可能会找到您需要的所有内容。只有一些提示:
类luigi.postgres.CopyToTable允许将记录存储到Postgres数据库中。目标将自动创建所谓的“标记表”,它将标记所有已完成的任务。
其他类型的数据库也有类似的类,其中一个使用SqlAlchemy,它可能涵盖您使用的数据库,请参阅类luigi.contrib.sqla.CopyToTable
在Luigi,doc是importing data into sqlite database
的例子在StackOverflow答案中,完整的实现超出了扩展的可行性,但我相信,您将体验到以下内容:
我已经使用Luigi处理了大量的XML文件,并且还完成了一些任务,将聚合数据导入数据库并且可以推荐它(我不是Luigi的作者,我只是很高兴的用户)。
如果您的任务执行数据库查询的执行时间过长,则几乎没有选项:
count
的SQL查询,并直接返回所需的数字。使用group by
,您甚至可以在一次运行中获得所有产品的摘要信息。可能会发生这种情况,即使不使用Luigi,通过优化的SQL查询,您也可以获得有效的解决方案。
答案 1 :(得分:1)
数据仓库?汇总表是正确的方法。
数据是否发生变化(一旦写入)?如果是这样,那么逐步更新摘要表就成了一个挑战。大多数DW应用程序都没有这个问题
在插入原始数据表时更新汇总表(日期+维度+次数+次数+总和)。由于每分钟只获得一次插入,INSERT INTO SummaryTable ... ON DUPLICATE KEY UPDATE ...
将足够,并且比每10分钟运行一次脚本更简单。
从汇总表中进行任何报告,而不是原始数据(Fact表)。它会更快很多。
My Blog on Summary Tables讨论了详细信息。 (它针对更大的DW应用程序,但应该是有用的阅读。)
答案 2 :(得分:0)
我同意Rick,汇总表对你来说最有意义。每10分钟更新一次汇总表,只需从中提取数据,作为用户的请求摘要。
此外,请确保您的数据库已正确编制索引以提高性能。我确定db_products.id设置为唯一索引。但是,还要确保db_products.create被定义为DATE或DATETIME,并且因为您在WHERE语句中使用它而编制索引。