简体   繁体   English

如何在 KStream (Kafka Streams) 中加入列表的每个元素

[英]How to join each element of a list in KStream (Kafka Streams)

For example I have a KStream of shopping carts and each shopping cart has a List of product id's.例如,我有一个 KStream 的购物车,每个购物车都有一个产品 ID 列表。 Additionally there is a KStream with products.此外,还有一个带有产品的 KStream。 How do I join them together?我如何将它们连接在一起?

public class ShoppingCart {
    List<ProductKey> productKeys;
}

public class Product {
    ProductKey key;
    String name;
}

public class ProductKey {
    String id;
}

KStream<String, ShoppingCart> shoppingCartKStream;
KStream<ProductKey, Product> productKStream;

My desired result would look like this我想要的结果看起来像这样

KStream<String, ShoppingCartWithProducts> joinedStream;
public class ShoppingCartWithProducts {
    List<Product> products;
}

Is there an easy way to archive this?有没有简单的方法来存档?

EDIT: I know there is a way but I find it too complicated.编辑:我知道有一种方法,但我觉得它太复杂了。 To put it simply:简而言之:

  1. I need to flatMap the shoppingCart-KStream我需要对 shoppingCart-KStream 进行平面映射

  2. Then I can join the result with the product-KStream然后我可以将结果与产品-KStream 结合起来

  3. Group and aggregate the intermediate result对中间结果进行分组和聚合

  4. And finally join back with shoppingCart-KStream最后加入 shoppingCart-KStream

     KStream<String, ProductKey> productKeyStream = shoppingCartKStream.flatMap((key, shoppingCart) -> shoppingCart.productKeys.stream().map(productKey -> KeyValue.pair(key, productKey)).collect(Collectors.toList()) ); KTable<String, Product> productStreamWithShoppingCartKey = productKeyStream.toTable().join( productKStream.toTable(), productKey -> productKey, (productKey, product) -> product ); KTable<String, ArrayList<Product>> productListStream = productStreamWithShoppingCartKey.groupBy(KeyValue::pair).aggregate( (Initializer<ArrayList<Product>>) ArrayList::new, (key, value, aggregate) -> addProductToList(aggregate, value), (key, value, aggregate) -> removeProductFromList(aggregate, value) ); KStream<String, ShoppingCartWithProducts> shoppingCartWithProductsKStream = shoppingCartKStream.join( productListStream, (shoppingCart, productList) -> new ShoppingCartWithProducts(productList) );

And of course it's very simplified, I also need to handle tombstone and so on.当然它非常简化,我还需要处理墓碑等。

After you define you StreamsBuilder that is the entry point to the Streams DSL.定义StreamsBuilder后,它是 Streams DSL 的入口点。

StreamsBuilder builder = new StreamsBuilder();

you can do a join of a 5 minutes window using JoinWindows.of(Duration.ofMinutes(5)) .您可以使用JoinWindows.of(Duration.ofMinutes(5))加入 5 分钟 window 。 You have to have the keys of both stream using the same type otherwise kafka-stream cannot compare keys of different types.您必须使用相同类型的 stream 的密钥,否则kafka-stream无法比较不同类型的密钥。 It is like a database join.它就像一个数据库连接。 So, I am using String for ShoppingCart and Product .因此,我将String用于ShoppingCartProduct Then the .join(... operator matches events of the same key and you can build your new event ShoppingCartWithProducts .然后.join(...运算符匹配相同键的事件,您可以构建新事件ShoppingCartWithProducts

KStream<String, ShoppingCart> shoppingCartKStream = ...;
KStream<String, Product> productKStream = ...;

shoppingCartKStream.join(productKStream,
    (shop, prod) -> {
        log.info("ShoppingCart: {} with Product: {}", shop, prod);

        ShoppingCartWithProducts shoppingCartWithProducts = new ShoppingCartWithProducts();
        shoppingCartWithProducts.setShoppingCart(shop);
        shoppingCartWithProducts.setProduct(prod);
        return shoppingCartWithProducts;
    },
    JoinWindows.of(Duration.ofMinutes(5)),
    StreamJoined.with(Serdes.String(),
        new JsonSerde<>(ShoppingCart.class),
        new JsonSerde<>(Product.class)))
   .foreach((k, v) -> log.info("ShoppingCartWithProducts ID: {}, value: {}", k, v));

you can find more detailed information here .你可以在这里找到更详细的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM