我有一个 KTable ,其数据看起来像这样(key => value),其中键是客户ID,值是包含一些客户数据的小JSON对象:
1 => { "name" : "John", "age_group": "25-30"}
2 => { "name" : "Alice", "age_group": "18-24"}
3 => { "name" : "Susie", "age_group": "18-24" }
4 => { "name" : "Jerry", "age_group": "18-24" }
我想对此 KTable 进行一些聚合,并且基本上保留每个age_group
的记录数。所需的 KTable 数据如下所示:
"18-24" => 3
"25-30" => 1
让我们说Alice
群组中的18-24
生日有一个生日,让她进入新的年龄段。支持第一个 KTable 的州商店现在应该如下所示:
1 => { "name" : "John", "age_group": "25-30"}
2 => { "name" : "Alice", "age_group": "25-30"} # Happy Cake Day
3 => { "name" : "Susie", "age_group": "18-24" }
4 => { "name" : "Jerry", "age_group": "18-24" }
我希望得到的汇总 KTable 结果能够反映这一点。 e.g。
"18-24" => 2
"25-30" => 2
我可能过度概括了here所描述的问题:
在Kafka Streams中没有最终聚合......根据您的使用案例,手动重复数据删除将是解决问题的一种方法“
但到目前为止,我只能算出一个跑步总数,例如爱丽丝的生日将被解释为:
"18-24" => 3 # Old Alice record still gets counted here
"25-30" => 2 # New Alice record gets counted here as well
编辑:这是我注意到的一些额外行为,似乎出乎意料。
我正在使用的拓扑如下:
dataKTable = builder.table("compacted-topic-1", "users-json")
.groupBy((key, value) -> KeyValue.pair(getAgeRange(value), key))
.count("age-range-counts")
现在,从最初的空状态开始,一切看起来都像这样:
compacted-topic-1
(empty)
dataKTable
(empty)
// groupBy()
Repartition topic: $APP_ID-age-range-counts-repartition
(empty)
// count()
age-range-counts state store
(empty)
现在,让我们向compacted-topic-1
发送一条消息,该消息将上传为
compacted-topic-1
3 => { "name" : "Susie", "age_group": "18-24" }
4 => { "name" : "Jerry", "age_group": "18-24" }
dataKTable
3 => { "name" : "Susie", "age_group": "18-24" }
4 => { "name" : "Jerry", "age_group": "18-24" }
// groupBy()
// why does this generate 4 events???
Repartition topic: $APP_ID-age-range-counts-repartition
18-24 => 3
18-24 => 3
18-24 => 4
18-24 => 4
// count()
age-range-counts state store
18-24 => 0
所以我想知道:
groupBy
和count
,但是我可能需要使用类似reduce
的内容吗? add
减速器和subtract
减速器被调用的情况时遇到了一些麻烦,所以任何关于这些点的澄清都将非常感激。< / LI>
答案 0 :(得分:7)
如果您的原始KTable
包含id -> Json
数据(让我们称之为dataKTable
),您应该可以通过
KTable countKTablePerRange
= dataKTable.groupBy(/* map your age-range to be the key*/)
.count("someStoreName");
这适用于所有版本的Kafka的Streams API。
<强>更新强>
关于重新分区主题中的4个值:这是正确的。每次更新&#34;基地KTable
&#34;为它写一个记录&#34;旧值&#34;它的新价值&#34;。这是正确更新下游KTable
所必需的。必须从一个计数中删除旧值,并且必须将新值添加到另一个计数中。因为您的(计数)KTable
可能是分布式的(即,在多个并行运行的应用程序实例上共享),所以两个记录(旧的和新的)可能最终都在不同的实例,因为它们可能具有不同的密钥,因此必须发送它们作为两个独立的记录。 (记录格式应该比你在问题中显示的更复杂。)
这也解释了为什么你需要一个减法器和一个加法器。减法器从聚合结果中删除旧记录,而加法器将新记录添加到聚合结果中。
仍然不确定为什么你没有在结果中看到正确的计数。你运行了多少个实例?也许可以通过在KTable
中设置cache.max.bytes.buffering=0
来尝试停用StreamsConfig
缓存。