Apache kafka 带有KafkaStreams的窗外连接端

Apache kafka 带有KafkaStreams的窗外连接端,apache-kafka,outer-join,apache-kafka-streams,Apache Kafka,Outer Join,Apache Kafka Streams,我有一个卡夫卡主题,我期望消息具有两种不同的键类型:旧键和新键。 i、 e.“1-新”,“1-旧”,“2-新”,“2-旧”。键是唯一的,但可能缺少一些键 现在,使用Kotlin和KafkaStreams API,我可以使用新旧密钥id相同的密钥记录这些消息 val windows = JoinWindows.of(Duration.of(2, MINUTES).toMillis()) val newStream = stream.filter({ key, _ -> is

我有一个卡夫卡主题,我期望消息具有两种不同的键类型:旧键和新键。 i、 e.
“1-新”
“1-旧”
“2-新”
“2-旧”
。键是唯一的,但可能缺少一些键

现在,使用Kotlin和KafkaStreams API,我可以使用新旧密钥id相同的密钥记录这些消息

    val windows = JoinWindows.of(Duration.of(2, MINUTES).toMillis())

    val newStream = stream.filter({ key, _ -> isNew(key) })
            .map({key, value ->  KeyValue(key.replace(NEW_PREFIX, ""), value) })

    val oldStream = stream.filter({ key, _ -> isOld(key) })
            .map({key, value ->  KeyValue(key.replace(OLD_PREFIX, ""), value) })

    val joined = newStream.join(oldStream,
            { value1, value2 -> "$value1&$value2" }, windows)

    joined.foreach({ key, value ->
        log.info { "JOINED $key : $value" }
    })
现在我想知道由于某种原因,时间窗口中缺少的新/旧键。是否可以使用KafkaStreams API实现


在我的情况下,当收到钥匙
“1-old”
,并且
“1-new”
不在2分钟内时,仅在这种情况下,我想将id
1
报告为可疑

如果我正确理解了您的问题,您只想在2分钟的窗口内有一个“旧”而没有相应的“新”时,将id报告为可疑

如果是这种情况,则需要使用左联接:

val leftJoined = oldStream.leftJoin(newStream,...).filter(condition where value expected from "new" stream is null);

HTH

DSL可能无法满足您的需求。但是,您可以使用处理器API。说到这里,
leftJoin
实际上可以用来做“繁重的工作”。因此,在
leftJoin
之后,可以使用带有附加状态的
.transform(…)
进一步“清理”数据

对于收到的每个
旧记录和空记录,将其放入存储区。如果您收到以后的
旧版和新版
,您可以将其从商店中删除。此外,您注册了一个标点符号,在每次标点符号调用时,您都会扫描存储区中“足够旧”的条目,以确保以后不会生成
old&new
join结果。对于这些条目,您将发出
old&null
,并将其从存储中删除

另一种选择是,您也可以省略连接,并使用state在单个
transform()
中执行所有操作。为此,您需要
KStream#merge()
新旧流,并在合并流上调用
transform()


注意:除了注册标点符号,您还可以将“扫描逻辑”放入转换中,并在每次处理记录时执行它。

看起来就像您正在查找的一样

消除了kafka streams框架中缺少类似sql的左连接语义。只有在连接窗口持续时间间隔内未发生完全连接事件时,此实现才会生成左连接事件


你关于可疑身份证的假设是正确的。但是,如果我将一个旧流左键连接到那些匹配ID的新流,我将获得流中相同键的
old&null
,然后
old&new
值。(我假设旧的键值总是首先到达)。如果我通过contains(“&null”)过滤值,我会得到可疑的所有ID。为什么我应该选择这种方法而不是groupby和后续窗口化的reduce?有多个原因:(1)连接使用滑动窗口,而聚合使用跳转窗口(所以语义不同)(2)reduce()也会连续计算,因此,您可能会遇到一些问题,需要使用suppress()加上一个计算实际联接的下游运算符。(3) 结合第(2)点,您需要将所有原始数据作为
reduce
的结果(即,使用
aggregate
并返回原始记录列表)。这会增大消息大小,并且可能不适用于较大的窗口。通过
计算实际联接的下游运算符
您的意思是将leftJoin作为单独的步骤来执行?我们想先做leftJoin,然后做groupby+reduce加上窗口长度限制。在windows方面,我想我们也可以使用SessionWindow。据我所知,使用SessionWindow可以解决这个问题。这种方法有意义吗?我明白了——你仍然有一个问题,那就是你可能会在窗口中创建潜在的大消息——我也不确定,如果你能正确区分结果记录:假设你有
(时间戳、键、值)
对,连接窗口大小
5ms
:左输入
(9,a,a)
->输出
(9,a,)
,左输入
(10,A,A)
->输出
(10,A,)
,右输入
(15,A,x)
->输出
(15,A,)
,您怎么知道这会替换第二条记录而不是第一条记录?还要注意的是,如果右输入的ts=14,则会在连接上发出两条记录。因此,我怀疑它是否有效。