是否有一种方法可以使用KSQL将消息拆分为多条消息并发布到新主题。需要明确的是,我不是在寻找基于Java的侦听器并将其迭代/流式传输到一个新主题。相反,我正在寻找可以为我做的KSQL。
例如:
比方说,我需要将invoice
主题中的消息分成item_inventory_delta
条消息
键:saleschecknumber
消息示例:
{
"total": 12.33,
"salecounter": 1,
"items": [
{
"itemId": 123,
"quantity": 1
},
{
"itemId": 345,
"quantity": 5
}
]
}
键:saleschecknumber_itemID
消息示例
{
"itemId": 123,
"quantity": 1
}
2。
{
"itemId": 345,
"quantity": 5
}
答案 0 :(得分:2)
由于the addition中的EXPLODE
table function,从ksqlDB 0.6开始,您现在可以执行此操作。
根据您的示例给出一个带有JSON负载的主题invoice
,请首先使用PRINT
对该主题进行检查以转储其内容:
ksql> PRINT invoice FROM BEGINNING;
Format:JSON
{"ROWTIME":1575366231505,"ROWKEY":"null","total":12.33,"salecounter":1,"items":[{"itemId":123,"quantity":1},{"itemId":345,"quantity":5}]}
然后在该主题的主题上声明一个模式,这为我们提供了一个ksqlDB 流:
CREATE STREAM INVOICE (total DOUBLE,
salecounter INT,
items ARRAY<STRUCT<itemId INT,
quantity INT>>)
WITH (KAFKA_TOPIC='invoice',
VALUE_FORMAT='JSON');
这只是“注册”现有主题以与ksqlDB一起使用。直到下一步,才编写新的Kafka主题。
创建一个新的Kafka主题,从源流中收到的消息中不断填充该主题:
CREATE STREAM INVENTORY WITH (KAFKA_TOPIC='item_inventory_delta') AS
SELECT EXPLODE(ITEMS)->ITEMID AS ITEMID,
EXPLODE(ITEMS)->QUANTITY AS QUANTITY
FROM INVOICE;
已创建新主题:
ksql> SHOW TOPICS;
Kafka Topic | Partitions | Partition Replicas
-------------------------------------------------------------------
invoice | 1 | 1
item_inventory_delta | 1 | 1
主题具有请求的增量消息:)
ksql> PRINT item_inventory_delta;
Format:JSON
{"ROWTIME":1575366231505,"ROWKEY":"null","ITEMID":123,"QUANTITY":1}
{"ROWTIME":1575366231505,"ROWKEY":"null","ITEMID":345,"QUANTITY":5}
答案 1 :(得分:1)
有许多方法可以使我理解,这与我们如何处理传入消息而不汇总消息有关。使用Kafka流处理器API的简单方法,可让您自定义处理逻辑。
Processor API允许开发人员定义和连接自定义 处理器并与状态存储进行交互。使用Processor API, 您可以定义处理一个接收到的任意流处理器 一次记录,并将这些处理器与其关联的 状态存储以构成代表一个 定制处理逻辑
注意 :您尚未定义将输出值的内容,因此我只是发布键和值相同,但是您可以选择定义输出键,值
您可以如下定义Kafka Stream处理器API
Topology builder = new Topology();
builder.addSource("Source", "invoice")
.addProcessor("sourceProcessor", () -> new InvoiceProcessor(), "Source")
.addSink("sinkDeltaInvoice", "item_inventory_delta", Serdes.String().serializer(), Serdes.String().serializer(),
"sourceProcessor")
以下是自定义处理器方法,请注意其公正方法尚未完全实施
class InvoiceProcessor implements Processor<String, String> {
private Gson gson = new Gson();
//constructor
.......
private ProcessorContext context;
@Override
public void init(ProcessorContext context) {
this.context = context;
}
@Override
public void close() {
// Any code for clean up would go here. This processor instance will not be used
// again after this call.
}
@Override
public void process(String key, String value) {
try {
//Create custom inventory to map JSON object
//List[Item] items is member object of Inventory class
Inventory inventory = gson.fromJson(key, Inventory.class);
//itertae item of items List[Items]
for(Item item: inventory.getItems()){
context.forward(gson.toJson(item), gson.toJson(item), To.child("sinkDeltaInvoice"));
}
//
}
}
}
答案 2 :(得分:0)
对于KStream
应用程序,您可以使用flatMap
,该函数接受接受一条记录并返回零个或多个记录的可迭代项的功能:
case class Record(total: Double, salecounter: Int, items: List[Item])
case class Item(itemId: Int, quantity: Int)
// initialize the stream
val inputStream: KStream[String, Record] = ???
// split the message
inputStream.flatMap { case (key, record) =>
record.items.map(item => (key, item) )
}