我有一个Kafka主题,其中包含Json中的数据:
{"id": "A", "country": "France"}
{"id": "B", "currency": "£"}
我想用“引用表”之类的内容来规范化内容:
country ( "France" ) -> "FR"
currency ( "£" ) -> "GBP"
为了输出:
{"id": "A", "country": "FR"}
{"id": "B", "currency": "GBP"}
我认为这是使用KTable
存储参考数据的典型用例。但是我对实现有些坚持。
当前状态
提取参考数据
在Kafka上创建的专用主题:poc-mapping-in
Json数据示例提供了主题:
{"mapping":"ccy", "from":"£", "to":"GBP"}
{"mapping":"country", "from":"France", "to":"FR"}
对键和值进行重新处理后,在KTable
中提取的数据:
KStream<String, String> mappingStream = builder
.stream("poc-mapping-in",consumed)
.map(
(key, value) -> KeyValue.pair(
value.get("mapping")+"#"+value.get("from"),
value.get("to").asText())
);
KGroupedStream<String, String> mappingGroupedStream = mappingStream.groupByKey(
Serialized.with(Serdes.String(),Serdes.String() ));
KTable<String,String> mappingTable = mappingGroupedStream.aggregate(
() -> "", //initializer
(aggKey, newValue, aggValue) -> newValue, // adder
Materialized.<String, String, KeyValueStore<Bytes, byte[]>>as("ReferenceStore")
.withValueSerde(Serdes.String())
.withKeySerde(Serdes.String())
);
// Testing
mappingTable.toStream().to("poc-mapping-in-content",
Produced.with(Serdes.String(), Serdes.String()));
在主题poc-mapping-in-content
中,我得到了以下几行:
"currency"#"£" GBP
"country"#"France" FR
这看起来像我期望的那样。双引号很奇怪,但这并不能阻止我进一步前进。
数据已经/应该存储在名为ReferenceStore
的本地存储中。
摄取业务流
在Kafka上创建的主题:poc-raw-events
Json数据示例提供了主题:
{"id": "A", "country": "France"}
{"id": "B", "currency": "£"}
提取到KStream
中的数据:
final Consumed<String, JsonNode> consumed = Consumed.with(Serdes.String(), jsonSerde);
KStream<String, JsonNode> businessData = builder.stream("poc-raw-events", consumed);
从这里我不知道该怎么办。从技术上讲,我知道如何更新JsonNode中的属性。因此,我尝试通过以下方式在KStream
和foreach
之间循环:
businessData.foreach(new ForeachAction<String, JsonNode>() {
public void apply(String k, JsonNode v) {
System.out.println(k+ " : " +v);
if (v==null) {System.out.println("NULL detected"); return;}
Iterator<Entry<String, JsonNode>> fields = v.fields();
int i=0;
while (fields.hasNext()) {
i++;
Entry<String, JsonNode> next = fields.next();
System.out.println(k+ " field #"+i+" : " +next.getKey() + " -- " + next.getValue());
String key = next.getKey() + "#" + next.getValue());
// ((ObjectNode) v).put(next.getKey(), " WHAT HERE ??? ");
}
}
});
我的想法是用参考KTable中存在的数据替换最后一行中的" WHAT HERE ??? "
。但是如何???
.findByKey()
的东西。ReferenceStore
本地存储,因为访问它的方式类似于myKafkaStream.store(...)
,目前myKafkaStream
尚未启动,也没有启动甚至建成。我想到的另一种方法是使用KStream leftJoin KTable功能。但是我读过某个地方(我没有收藏……),为此,我们应该在两个KTables中使用相同的键。但就我而言,在Json方面,我不是在联接键上工作,而是在一个简单的属性上工作。
您将如何实施?
答案 0 :(得分:4)
由于您使用的是参考数据,因此我认为您要考虑使用的是GlobalKTable
。如上所述,每个GlobalKTable
实例都完全复制了一个KafkaStreams
,并被显式创建以保存用例的参考数据。
KStream-GlobalKTable连接的独特之处在于您可以使用流的KeyValue
来映射到GlobalKTable
的键。因此,只要您可以将属性从JsonNode
中拉出,就应该能够与GlobalKTable.
答案 1 :(得分:0)
如果referenceKTable具有与data.getAltKey()匹配的键
streamToMap.selectKey((originalKey, data) -> data.getAltKey()).leftJoin(referenceKTable, valueJoiner)
可以做到。 valueJoiner(或lambda)的实现必须结合两个输入。