Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Google cloud dataflow apachebeam有状态DoFn定期输出所有K/V对_Google Cloud Dataflow_Apache Beam_Spotify Scio - Fatal编程技术网

Google cloud dataflow apachebeam有状态DoFn定期输出所有K/V对

Google cloud dataflow apachebeam有状态DoFn定期输出所有K/V对,google-cloud-dataflow,apache-beam,spotify-scio,Google Cloud Dataflow,Apache Beam,Spotify Scio,我正在尝试使用有状态DoFn(使用@ProcessElement和@StateIdValueState元素)在Apache Beam中聚合(每个键)流数据源(通过Scio)。我认为这将是最适合我试图解决的问题。这些要求是: 对于一个给定的键,记录在任何时候都是聚合的(基本上是求和的)——我不关心以前计算的聚合,只关心最近的聚合 根据我控制的某些条件,键可能会从状态(state.clear())中退出 每5分钟,无论是否看到任何新密钥,都应输出尚未从状态中移出的所有密钥 考虑到这是一个流式管道

我正在尝试使用有状态DoFn(使用
@ProcessElement
@StateId
ValueState
元素)在Apache Beam中聚合(每个键)流数据源(通过Scio)。我认为这将是最适合我试图解决的问题。这些要求是:

  • 对于一个给定的键,记录在任何时候都是聚合的(基本上是求和的)——我不关心以前计算的聚合,只关心最近的聚合
  • 根据我控制的某些条件,键可能会从状态(
    state.clear()
    )中退出
  • 每5分钟,无论是否看到任何新密钥,都应输出尚未从状态中移出的所有密钥
考虑到这是一个流式管道,并且将无限期地运行,在一个全局窗口上使用
combinePerKey
,累积激发的窗格似乎会随着时间的推移继续增加其内存占用和需要运行的数据量,因此我希望避免这种情况。此外,在测试时,(可能如预期的那样),它只是将新计算的聚合与历史输入一起附加到输出,而不是使用每个键的最新值

我的想法是,使用StatefulDoFn只允许我输出到现在为止的所有全局状态(),但这似乎不是一个简单的解决方案。我已经看到了使用计时器人为执行回调的暗示,以及可能使用缓慢增长的side-input-map()并以某种方式刷新该映射的暗示,但这实际上需要迭代映射中的所有值,而不是加入映射


我觉得我可能忽略了一些简单的事情来让它工作。我对Beam中的窗口和计时器的许多概念都比较陌生,我想知道如何解决这个问题。谢谢

你说得对,有状态的DoFn应该在这里帮助你。这是你能做什么的基本草图。请注意,这只输出不带键的和。这可能不是你想要的,但它应该能帮助你前进

类组合emittingfn扩展DoFn{
@TimerId(“发射器”)
专用最终TimerSpec emitterSpec=TimerSpec.timer(时域处理时间);
@StateId(“完成”)
private final StateSpec donstate=StateSpecs.value();
@StateId(“agg”)
私人最终国家规范
aggSpec=StateSpecs.com(
积分之和().getAccumeratorCoder(null,VarIntCoder.of()),积分之和();
@过程元素
public void processElement(ProcessContext c,
@StateId(“agg”)组合STATE aggState,
@StateId(“完成”)价值State doneState,
@TimerId(“发射器”)计时器(emitterTimer)引发异常{
如果(某些条件){
countValueState.clear();
doneState.write(true);
}否则{
countValueState.addAccum(c.element().getValue());
emitterTimer.align(Duration.standardMinutes(5)).setRelative();
}
}
}
@OnTimer(“发射器”)
公开无效(
OnTimerContext上下文,
@StateId(“agg”)组合STATE aggState,
@StateId(“完成”)价值State doneState,
@TimerId(“发射器”)计时器(发射器计时器){
布尔isDone=doneState.read();
if(isDone!=null&&isDone){
返回;
}否则{
context.output(aggState.getAccum());
//将计时器设置为再次发出
emitterTimer.align(Duration.standardMinutes(5)).setRelative();
}
}
}
}

很高兴与您一起讨论一些有用的东西。

@Pablo确实正确,StatefulDoFn和计时器在这个场景中很有用。这是我能够使用的代码

有状态的做Fn

//DomainState是我正在使用的自定义案例类
类型DoFnT=DoFn[KV[字符串,域状态],KV[字符串,域状态]]
类StatefulDoFn扩展了DoFnT{
@StateId(“键”)
private val keySpec=StateSpecs.value[String]()
@StateId(“域状态”)
private val domainStateSpec=StateSpecs.value[DomainState]()
@TimerId(“循环计时器”)
private val loopingTimer:TimerSpec=TimerSpecs.timer(TimeDomain.EVENT\u TIME)
@过程元素
def过程(
上下文:DoFnT#ProcessContext,
@StateId(“key”)stateKey:ValueState[String],
@StateId(“domainState”)stateValue:ValueState[domainState],
@TimerId(“loopingTimer”)loopingTimer:Timer):单位={
…从可能为空的值创建键/值的逻辑
如果(保留状态(值)){
loopingTimer.align(Duration.standardMinutes(5)).setRelative()
stateKey.write(键)
stateValue.write(值)
if(刷新状态(值)){
上下文输出(千伏(键、值))
}
}否则{
stateValue.clear()
}
}
@OnTimer(“循环计时器”)
def onLoopingTimer(
上下文:DoFnT#OnTimerContext,
@StateId(“key”)stateKey:ValueState[String],
@StateId(“domainState”)stateValue:ValueState[domainState],
@TimerId(“loopingTimer”)loopingTimer:Timer):单位={
…用于为空值创建键/值检查的逻辑
如果(保留状态(值)){
loopingTimer.align(Duration.standardMinutes(5)).setRelative()
if(刷新状态(值)){
上下文输出(千伏(键、值))
}
}
}
}
带管道

sc
.PubSubscription(…)
.keyBy(…)
.withGlobalWindow()
.applyPerKeyDoFn(新状态fuldofn())
.带固定窗户(
持续时间=持续时间。标准分钟(5),
选项=窗口选项(
累加模式=丢弃已触发的窗格,
触发器=AfterWatermark.pastEndOfWindow(),
allowedLateness=持续时间.0,
//在窗口打开期间,仅对每个关键点使用最新的
timestampCombiner=timestampCombiner.END\u窗口的\u
))
.reduceByKey(mostRecentEvent())
.saveAsCustomOutput(TextIO.write()…)

明天之前,我会尽力帮你找到答案!我怀疑窗口/触发选项可能是b