KPD closed beta Sign inRequest access

4. Build the pipeline

Avro schemas, a PostgreSQL CDC source, two raw topics, a Flink join to a canonical topic, and two data products.

Part 4 of 10 in the Hello World tutorial · Follow this part in the guided wizard · Printable version

This is the longest part: you build the whole pipeline. In order:

  1. rename the pipeline;
  2. create five Avro schemas;
  3. add the CDC source and its two raw topics;
  4. add the Flink join and the canonical topic;
  5. add the two data product statements and their topics.

4.1 Rename the pipeline

  1. In the explorer, right-click data-product.kpd under Pipelines and choose Rename…
Right-click the pipeline → Rename…
Right-click the pipeline → Rename…
  1. Type store-orders and click Rename. The file becomes store-orders.kpd.
The new name.
The new name.

4.2 Create the five Avro schemas

Every topic carries messages of a known shape, described by a schema. KPD has a visual editor for Avro, so you never need to write the JSON by hand. You need five: one for each raw table, one for the canonical order, and one for each data product. Their file names follow the topic names with -value on the end (the Schema Registry subject for a topic's values).

  1. In the explorer, scroll down to Shared schemas, right-click it and choose New schema…
Right-click Shared schemas → New schema…
Right-click Shared schemas → New schema…
  1. The New schema dialog opens with an example record. Keep Folder as Shared schemas (top level) and Format as Avro (.avsc).
A new schema starts as an example with two fields. You replace them.
A new schema starts as an example with two fields. You replace them.
  1. File name: hwc.prod.raw.order.shopdb.v1-value
  2. Record name: Order. Namespace: com.hellocoffee.raw
  3. Change the two example fields and use Add field until you have these five. Type each name, then pick its type from the list (timestamp-millis is in the list too):
    FieldType
    order_idlong
    customer_idlong
    store_idstring
    total_penceint
    ordered_attimestamp-millis
The raw Order record. The arrows reorder fields; the bin deletes one.
The raw Order record. The arrows reorder fields; the bin deletes one.

Two handy extras while you are here. Open Example message to see a sample record that matches the schema. Click Source to see the Avro JSON KPD writes for you. The blue Valid Avro bar means the schema is checked against the Avro specification as you type.

An illustrative example message, with a Copy button.
An illustrative example message, with a Copy button.
The Source view: the same schema as Avro JSON. You can edit either view.
The Source view: the same schema as Avro JSON. You can edit either view.
  1. Click Create schema.
  2. Repeat for the other four schemas:
    File nameRecord / namespaceFields
    hwc.prod.raw.customer.shopdb.v1-valueCustomer / com.hellocoffee.rawcustomer_id long, name string, email string (tick nullable)
    hwc.prod.ent.order.cdm.v1-valueStoreOrder / com.hellocoffee.cdmorderId long, customerId long, customerName string, customerEmail string (nullable), storeId string, totalPence int, orderedAt timestamp-millis
    hwc.prod.ent.order.history.v1-valueOrderHistory / com.hellocoffee.productorderId long, customerId long, customerName string, storeId string, totalPence int, orderedAt timestamp-millis
    hwc.prod.ent.order.big-orders.v1-valueBigOrder / com.hellocoffee.productorderId long, storeId string, totalPence int, orderedAt timestamp-millis
The canonical StoreOrder: business-friendly names, and the customer’s name and email joined in. nullable is ticked on customerEmail because not every customer gives one.
The canonical StoreOrder: business-friendly names, and the customer’s name and email joined in. nullable is ticked on customerEmail because not every customer gives one.
Why the names changeRaw topics keep the database's own column names (order_id), exactly as captured. The canonical layer uses the business's names (orderId) once, so every data product built on it agrees. That is the DPCF raw → canonical → product pattern.
All five schemas under Shared schemas.
All five schemas under Shared schemas.

4.3 Add the CDC source

CDC (change data capture) reads the database's own change log, so every insert and update is captured once, in order, without querying the tables.

  1. Make sure the store-orders.kpd tab is showing. On the Start your pipeline card, click Add a source. (Start from a system would draw the shop database itself first, which is a good way into a workshop; here we go straight to the connector.)
  2. Type postgres and choose Postgres CDC (its full name is PostgreSQL CDC Source V2).
Type to search; choose Postgres CDC.
Type to search; choose Postgres CDC.
  1. The connector appears on the canvas. If it isn't inside the green Ingestion box, drag it there: sources belong in the ingestion layer.
  2. On its General tab: Name hwc-shopdb-cdc; Description Captures every new and changed row in the shop database's orders and customers tables, one raw topic per table. (Leave Service account for Part 6.)
The connector in the Ingestion box, with its General tab. Each tab across the panel is one group of connector settings.
The connector in the Ingestion box, with its General tab. Each tab across the panel is one group of connector settings.
  1. Connector tab: database.hostname shopdb.hello-coffee.example, database.port 5432, database.dbname shopdb, database.sslmode require. (No password: that is a secret, supplied when deploying.)
Where the database is. Reset returns a field to its default.
Where the database is. Reset returns a field to its default.
  1. Capture tab: table.include.list public.orders,public.customers; snapshot.mode initial (copy the existing rows first, then stream changes); slot.name hwc_shopdb_slot; publication.name hwc_shopdb_pub; publication.autocreate.mode filtered (the publication covers just these two tables).
Which tables to capture, and how.
Which tables to capture, and how.
  1. Data format tab: output.data.format AVRO, output.key.format STRING, topic.prefix hwc.prod.raw.shopdb.
Avro values, string keys.
Avro values, string keys.
How a CDC connector names its topicsA CDC connector writes one topic per table and names each one itself: topic.prefix, then the schema and table. With our prefix, public.orders would land in hwc.prod.raw.shopdb.public.orders. KPD works these names out and checks the topics you wire against them. Our DPCF standard wants names like hwc.prod.raw.order.shopdb.v1 instead, so the next step adds a transform that renames them. (Without it, KPD would offer to Add topics with the connector's own names. See CDC sources and their topics.)
  1. Advanced tab: in SMT chain, type RegexRouter and press Enter. RegexRouter is the single message transform that renames each topic to our DPCF name.
The SMT chain records that a RegexRouter renames the topics. The red 1 on Problems says the connector captures two tables but has no topics yet; 4.4 adds them.
The SMT chain records that a RegexRouter renames the topics. The red 1 on Problems says the connector captures two tables but has no topics yet; 4.4 adds them.

Because a transform renames the topics, KPD can't predict the names any more, so it checks only that there is one topic per captured table. (The transform's own settings, the pattern and the replacement, are added to the Terraform by hand.)

Hover the ⓘ iconsEvery setting has a short explanation from the connector's documentation. The Docs link top right opens Confluent's page for the connector.

4.4 Add the two raw topics

  1. With the connector selected, click the + on its right-hand edge (its Records output).
The + on the connector’s output.
The + on the connector’s output.
  1. Choose Topic. A topic appears, already connected.
Quick add only offers what can connect: a Topic, or a Dead Letter topic.
Quick add only offers what can connect: a Topic, or a Dead Letter topic.
  1. On the topic's General tab: Name hwc.prod.raw.order.shopdb.v1; Description Every order row from shopdb (public.orders), as captured. Raw: never published.
  2. Partitions & durability tab: Partitions 3; Partition key order_id (a design note: which field keeps one order's changes in order).
Three partitions, keyed by order. (The red 1 on Problems goes away when the schema is set.)
Three partitions, keyed by order. (The red 1 on Problems goes away when the schema is set.)
  1. Schema tab: Key format String; Value schema file hwc.prod.raw.order.shopdb.v1-value.avsc.
The topic’s value schema is the file you made in 4.2.
The topic’s value schema is the file you made in 4.2.
  1. Select the connector again, click its + again and add a second Topic: name hwc.prod.raw.customer.shopdb.v1, description Every customer row from shopdb (public.customers), as captured. Raw: never published., 3 partitions, partition key customer_id, key format String, value schema hwc.prod.raw.customer.shopdb.v1-value.avsc.
One connector, two raw topics, both in the Ingestion box.
One connector, two raw topics, both in the Ingestion box.
One connector, two topicsOne wire per captured table shows where the data really goes, and the connector's warning about tables without a topic has gone. The Terraform will create both topics before the connector starts, with the partitions and schemas you set here, so the connector never has to create them itself (it would make them with 1 partition). To let the connector create a topic instead, set the topic's Managed by to Connector; see Who creates the topics.

4.5 Join orders to customers in Flink

  1. Select the order raw topic and click its +. Choose Flink SQL. The statement is placed in the purple Process box.
After a topic, quick add suggests things that read topics. Choose Flink SQL.
After a topic, quick add suggests things that read topics. Choose Flink SQL.
  1. On the statement's General tab: Name orders_raw_to_cdm; Description Joins each raw order with its customer to make the canonical store order: business field names, the customer's name and email added.; Compute pool hwc-raw-to-cdm.
The statement runs in the raw-to-canonical pool. The hint under the pool shows how many of its 10 CFUs are used.
The statement runs in the raw-to-canonical pool. The hint under the pool shows how many of its 10 CFUs are used.
  1. Now wire the customer topic in as the join. A Flink statement has a Main input on its left and a Join input on its bottom edge. Drag from the customer topic's right-hand dot (its output) to the dot on the bottom of the statement. A line follows the mouse while you drag.
Dragging from the customer topic’s output to the statement’s Join input.
Dragging from the customer topic’s output to the statement’s Join input.
Connected. Hovering a statement labels its ports: Main input, Join input, Output, Errors and UDFs / models.
Connected. Hovering a statement labels its ports: Main input, Join input, Output, Errors and UDFs / models.
  1. SQL tab: Statement kind INSERT INTO. Keep the SQL in a file of its own, so it can be reviewed like any other code: under SQL file choose + New SQL file…. The dialog suggests the name orders_raw_to_cdm in a new store-orders folder; keep both, replace the starter text with this, and click Create SQL file:
    -- Each order, with the customer who placed it.
    INSERT INTO `hwc.prod.ent.order.cdm.v1`
    SELECT
      o.order_id    AS orderId,
      o.customer_id AS customerId,
      c.name        AS customerName,
      c.email       AS customerEmail,
      o.store_id    AS storeId,
      o.total_pence AS totalPence,
      o.ordered_at  AS orderedAt
    FROM `hwc.prod.raw.order.shopdb.v1` AS o
    JOIN `hwc.prod.raw.customer.shopdb.v1` AS c
      ON o.customer_id = c.customer_id;
    The SQL tab now shows the file, Read-only so it isn’t changed by accident. To change it later, untick Read-only and edit it there, or open it from Stream configuration → SQL in the explorer.
The join, in its own file, sql/store-orders/orders_raw_to_cdm.sql. In Confluent Cloud Flink every topic is a table, so the SQL uses the topic names in back-quotes.
The join, in its own file, sql/store-orders/orders_raw_to_cdm.sql. In Confluent Cloud Flink every topic is a table, so the SQL uses the topic names in back-quotes.
KPD doesn't run your SQLIt stores it, shows it in the design document, and puts it in Terraform exactly as written. Check it in Confluent Cloud's SQL workspace before you rely on it.

4.6 Add the canonical topic

  1. Select orders_raw_to_cdm, click the + on its Output and choose Topic.
  2. Name hwc.prod.ent.order.cdm.v1; Description Canonical store orders: every order with its customer, in business field names. The single source for the data products.; 3 partitions, partition key orderId; key format String; value schema hwc.prod.ent.order.cdm.v1-value.avsc.

4.7 Add the two data products

Each data product is a Flink statement that reads the canonical topic and writes its own topic, in the blue Surface box.

  1. Select the canonical topic, click its + and choose Flink SQL. Name it order_history_product, description Data product DP-001: every order with who placed it, for the app's order history., compute pool hwc-cdm-to-surface. On SQL, choose + New SQL file… as before, keep the suggested name, and create it with:
    -- DP-001: each customer's orders, without their email.
    INSERT INTO `hwc.prod.ent.order.history.v1`
    SELECT orderId, customerId, customerName, storeId, totalPence, orderedAt
    FROM `hwc.prod.ent.order.cdm.v1`;
  2. Select order_history_product, click the + on its Output, choose Topic: name hwc.prod.ent.order.history.v1, description DP-001 Customer order history: every store order with the customer who placed it., 3 partitions keyed by orderId, key String, value schema hwc.prod.ent.order.history.v1-value.avsc.
  3. Select the canonical topic again and add a second Flink SQL: big_orders_product, description Data product DP-002: orders of £20 or more, for store managers., pool hwc-cdm-to-surface, and a + New SQL file… with:
    -- DP-002: orders of £20 (2000 pence) or more.
    INSERT INTO `hwc.prod.ent.order.big-orders.v1`
    SELECT orderId, storeId, totalPence, orderedAt
    FROM `hwc.prod.ent.order.cdm.v1`
    WHERE totalPence >= 2000;
  4. Give it an output Topic: hwc.prod.ent.order.big-orders.v1, description DP-002 Big orders: orders of £20 or more, as they happen., 3 partitions keyed by orderId, key String, value schema hwc.prod.ent.order.big-orders.v1-value.avsc.
The Big orders statement: a simple filter on the canonical topic, in its own SQL file.
The Big orders statement: a simple filter on the canonical topic, in its own SQL file.
The whole pipeline: source and raw topics in Ingestion, the join and canonical topic in Process, two data products in Surface. The status bar says No problems.
The whole pipeline: source and raw topics in Ingestion, the join and canonical topic in Process, two data products in Surface. The status bar says No problems.
Tidy as you goDrag assets to line them up; Snap to grid keeps them neat. If a line runs through an asset, move one of them a little. Shift+1 fits the whole pipeline on screen.

Save. Next: 5. Governance: tags and the catalogue.