每N分钟运行一次,或者如果项目与平均值不同

时间:2018-07-20 13:34:43

标签: akka akka-stream akka.net

我有一个演员,他接收WeatherConditions并将其(通过使用OfferAsync推送到source。目前,它已设置为针对收到的每个项目运行(将其存储到db)。

public class StoreConditionsActor : ReceiveActor
{
    public StoreConditionsActor(ITemperatureDataProvider temperatureDataProvider)
    {
        var materializer = Context.Materializer();
        var source = Source.Queue<WeatherConditions>(10, OverflowStrategy.DropTail);

        var graph = source
            .To(Sink.ForEach<WeatherConditions>(conditions => temperatureDataProvider.Store(conditions)))
            .Run(materializer);

        Receive<WeatherConditions>(i =>
        {
            graph.OfferAsync(i);
        });
    }
}

我想要实现的是:

  1. 每N分钟仅运行一次,并存储在此N分钟时间窗口内收到的所有项目的平均值WeatherConditions
  2. 如果收到的商品符合特定条件(即商品温度比前一件商品的温度高30%),则运行该商品,尽管它在时间窗口中被“隐藏”。

我一直在尝试ConflateWithSeedBufferThrottle,但似乎都没有用(我是Akka / Akka Streams的新手,所以我可能缺少一些基本的知识)< / p>

1 个答案:

答案 0 :(得分:3)

此答案使用Akka Streams和Scala,但也许会启发您的Akka.NET解决方案。

groupedWithin方法可以满足您的第一个要求:

val queue =
  Source.queue[Int](10, OverflowStrategy.dropTail)
    .groupedWithin(10, 1 second)
    .map(group => group.sum / group.size)
    .toMat(Sink.foreach(println))(Keep.left)
    .run()

Source(1 to 10000)
  .throttle(10, 1 second)
  .mapAsync(1)(queue.offer(_))
  .runWith(Sink.ignore)

在上面的示例中,SourceQueue每秒最多提供10个整数,sliding将进入的元素分成一束,然后计算每个束的平均值。

关于第二个要求,您可以使用val source: Source[Int, _] = ??? source .sliding(2, 1) .collect { case Seq(a, b) if b >= 1.3 * a => b } .runForeach(println) 将一个元素与上一个元素进行比较。下面的示例仅在元素比上一个元素大至少30%的情况下将元素传递到下游:

{{1}}