Unfortunately KTable
s don't support KeyValueMapper
s: KStream
/KTable
joins are performed strictly by comparing keys. GlobalKTable
s support this, making the whole process of joining much easier (see my other answer).
To get this to work then, you need to rekey the customers
topic KStream
to use the product ID, so that you can perform the join with the products
topic KTable
.
Once you've obtained the product name, you can rekey the resulting joined stream back to the customer ID. For example:
// Key: product ID, value: product name
KTable<String, String> productsTable =
streamsBuilder.table(PRODUCTS_TOPIC, Consumed.with(stringSerde, stringSerde),
Materialized.<String, String, KeyValueStore<Bytes, byte[]>>as("productsStore")
.withKeySerde(stringSerde)
.withValueSerde(stringSerde));
streamsBuilder.stream(CUSTOMERS_TOPIC, Consumed.with(stringSerde, stringSerde))
// Key: customer ID, value: product ID
.map((customerId, productId) -> KeyValue.pair(productId, String.format("%s|%s", customerId, productId)),
Named.as("mapToProductIdAndCustomerIdProductId"))
// Key: product ID, value: customer ID | product ID
.join(productsTable, (customerIdProductId, productName) -> {
String[] parts = customerIdProductId.split("\\|");
String customerId = parts[0];
return String.format("%s|%s", customerId, productName);
},
Joined.<String, String, String>as("customersProductsInnerJoin")
.withKeySerde(stringSerde)
.withValueSerde(stringSerde))
// Key: product ID, value: customer ID | product name
.map((productId, customerIdProductName) -> {
String[] parts = customerIdProductName.split("\\|");
String customerId = parts[0];
String productName = parts[1];
return KeyValue.pair(customerId, productName);
}, Named.as("mapToCustomerIdAndProductName"))
// Key: customer ID, value: product name
.print(Printed.toSysOut());