在App Engin中查询随时间变化的百分比

2024-04-25 20:39:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我的网站索引来自一个不断更新的提要的时间序列数据。网站用户应该能够配置警报,当数据中特定属性的值在特定时间段内发生一定百分比的变化时,会触发警报。在

例如:假设我们正在跟踪一个用户的twitter关注者的数量。以下是(简化)数据馈送的外观:

日期,关注者

  • 10: 00,1
  • 10: 01,2
  • 10: 02,2
  • 10: 03、15年
  • 。。。在

警报:

  • 如果“关注者”在过去1小时内增加了15%,请通知我。在
  • 如果“关注者”在过去40分钟内减少了10%,请通知我。在

只有一个简单的数据馈送。将(希望)定义数千个警报。这些警报中有许多可能是相似的,但很难估计会有多少独特的警报。在

编辑:之前忘记提到这一点,但追随者的数量经常变化(每分钟)。在

使用数据存储和其他appengine工具实现这种机制的最优雅的方式是什么?警报应该相对实时地触发(+/-几分钟)。在

谢谢!在


Tags: 数据用户编辑数量属性定义网站时间
3条回答

有时,当你需要保持一个变量的移动平均值时,你能做的最好的事情就是回到这个要求的来源,看看是否可以用指数衰减的加权平均值来代替它(阅读解释它的wikipedia article)。它不像移动平均线那么容易理解,但是维护和存储起来要简单得多,尤其是如果你想在线实时计算它的话。在

假设,例如,不要查看您提供的系列的移动平均值,而是查看半衰期为一分钟的衰减权重的平均值。在

  • 10: 00,1(平均值为1)
  • 10: 01,2(旧平均值为1,权重为0.5,新数据为2,新加权平均值为(1*0.5+2*1)/(0.5+1)=1.667
  • 10: 02,2(旧平均值为1.667,权重为0.75,新数据为2,新加权平均值为(1.667*0.75+2*1)/(0.75+1)=1.85
  • 10: 03、15(旧平均值为1.85,权重为0.875,新数据为15,新加权平均值为(1.85*0.875+15*1)/(0.875+1)=8.8667
  • 。。。在

它看起来可能很复杂,但实际上很简单。当然,你需要调整你的半衰期以适应你的需要(这和选择移动平均线的窗口有点不同)。在

与移动平均相比,使用衰减加权平均有两大优点:

  1. 您不需要记录离散值来计算平均值;您只需要存储当前值和采样时间。在
  2. 您只需要在数据发生变化时重新计算平均值。当它不变时,你所拥有的平均值的权重会衰减,但它的价值仍然存在。因此,您可以在收到新数据时计算它,而不是在运行在cron或类似的单独任务中。在

另外,稍微研究一下这些方程,你可以找到一些更有用的东西,比如为你可以索引的值存储e^X,因为它保持了你所监视的度量值的不同值之间的顺序关系。在

重写put意味着每次写入都要进行计算,这可能效率低下。如果您允许用户设置这些警报,那么您可能会得到表示警报的数据存储对象,这意味着每次评估警报时都会有GET或查询。在

一种选择是任务:当数据源发生变化时,启动一个任务来评估警报。至少,这将使初始数据馈送写入请求更快地完成。但是,如果数据馈送变化很快,那么您可能有许多任务,并且由于最近的数据更改,大多数任务都变得不必要。在

也许最好的选择是一个cron任务,每隔几分钟运行一次。如果需要,您可以根据负载更改cron作业的时间,并且如果您有许多用户/警报,则以高度并行的方式进行处理更为可行。在

我将尝试去规范化你的模型,在性能和冗余之间找到一个平衡,写操作和读操作。在

例如:

  1. 由于该服务关注实时更改,因此每个特定属性的倍增数据可以存储在一个数据存储中。例如,一个大型实体在五天内存储同一用户的所有更改。因此,随着时间的变化不需要额外的查询来计算。 这也是google在appengine上托管代码堵塞的方式。可以在数据存储中应用树结构来提供一些额外的特性。

  2. 对于警报,一种常见的方法是直接在数据模型本身上写下谁在观察数据变化。

由于反规范化确实需要澄清用例是什么,所以这个设计只是基于我的假设。在

class Watcher(ndb.Model):
    # define the rule such as "Notify me if 'followers' has increased by 15% in the past 1 hour."
    pass


class Attribute(ndb.Model):
    name = ndb.StringProperty() # the name of this attribute such as "twitter_user_1:followers"
    data = ndb.PickleProperty() # a tree store all changes of the specify attribute

    watch_list = ndb.LocalStructureProperty(repeated=True, kind=Watcher) # who want to received the notification

因此,服务可以在一个地方收集所有必要的信息。在

相关问题 更多 >

    热门问题