我有2个名为“alarm”和“干预”的流,其中包含JSON。如果连接了警报和干预,那么它们将具有相同的密钥。我想联系他们以检测24小时前没有干预的所有警报
但是这个程序不起作用,结果所有的警报就像24小时前没有干预一样。
我重新检查了我的数据集5次,并且有警报在警报日期前不到24小时完成干预。
这张图解释了情况:
enter image description here
所以我需要知道在发出警报之前是否有干预措施
该计划的代码:
final KStream<String, JsonNode> alarm = ...;
final KStream<String, JsonNode> intervention = ...;
final JoinWindows jw = JoinWindows.of(TimeUnit.HOURS.toMillis(24)).before(TimeUnit.HOURS.toMillis(24)).after(0);
final KStream<String, JsonNode> joinedAI = alarm.filter((String key, JsonNode value) -> {
return value != null;
}).leftJoin(intervention, (JsonNode leftValue, JsonNode rightValue) -> {
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = null;
if (rightValue == null) {//No intervention before
try {
actualObj = mapper.readTree("{\"date\":\"" + leftValue.get("date").asText() + "\","
+ "\"alarm\":" + leftValue.toString()
+ "}");
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return actualObj;
} else {
return null;
}
}, jw, Joined.with(Serdes.String(), jsonSerde, jsonSerde));
final KStream<String, JsonNode> fraude = joinedAI.filter((String key, JsonNode value) -> {
return value != null;
});
fraude.foreach((key, value) -> {
rl.println("Fraude=" + key + " => " + value);
System.out.println("Fraude=" + key + " => " + value);
});
final KafkaStreams streams = new KafkaStreams(builder.build(), streamingConfig);
streams.cleanUp();
streams.start();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
streams.close();
rl.close();
el.close();
nfl.close();
}
}));
总之,我想检测红色矩形enter image description here
中的模式P.S:我确保干预记录在警报记录之前发送
答案 0 :(得分:0)
M.Djx,
我现在不认为Kafka Streams的这个用例是一个完美的解决方案,但我有一些想法让你更接近。我准备提交KIP,以便在不久的将来准确处理此类用例。
一点:与KTable不同,KStreams不是更改日志,因此较新的事件不会使用相同的密钥覆盖旧事件;他们只是在同一个流中共存。我认为这就是为什么你的foreach
让所有警报都没有干预的原因;你在干预之前看到了中间加入事件。
例如:
LEFT RIGHT JOIN
a:1 a:(1,null)
a:X a:(1,X)
将在两个联接结果上调用 foreach
,使其看起来像缺少正确的值,当它实际上只是有点迟了。
如果您在结果流上应用时间窗口,将获取更改日志 - 较新的值将覆盖旧版本。类似的东西:
joinedAI
.groupByKey()
.windowedBy(
TimeWindows
.of(1000 * 60 * 60 * 24) // the window will be 24 hours in size
.until(1000 * 60 * 60 * 48) // and we'll keep it in the state store for at least 48 hours
).reduce(
new Reducer<JsonNode>() {
@Override
public Long apply(final JsonNode value1, final JsonNode value2) {
return value2;
}
},
Materialized.<String, JsonNode, WindowStore<Bytes, byte[]>>as("alerts-without-interventions")
);
糟糕的是,这将产生具有正确语义的更改日志流,但您仍然会看到中间值,因此您不希望直接从此流触发任何操作(如foreach
)。
您可以做的一件事是每天安排一次工作,从{em>昨天扫描"alerts-without-interventions"
窗口。从窗口存储中获得的任何结果都将是该密钥的最新值。
我准备的KIP将提出一种方法,让您过滤掉窗口中的中间结果,这样您就可以将foreach附加到更改日志中,并仅在窗口的最终结果上触发它。
或者,如果您的应用的数据不是太大,并且如果您不太担心边缘情况,则可以考虑实施&#34;窗口最终事件&#34;使用LinkedHashMap或Guava缓存自己进行语义化。
我希望这会有所帮助。