Joining streams — combine & merge
The question for this lesson: so far each pipeline has read from one source. But real data is scattered. Orders live in one file, the product catalog in another; web logins in one stream, mobile logins in a second. How do you bring two streams together?
There are two different ways, and choosing the right one is the whole lesson:
combine(join two streams on a key) makes each row wider (orders + their product details).merge(stack same-shaped streams) makes more rows (web logins + mobile logins, one list).
What you’ll be able to do
Section titled “What you’ll be able to do”- Use a
combinenode to join two streams on a key, and say whatmatchandon_missdo. - Use a
mergenode to stack same-shaped streams into one. - Say when you need
combinevsmerge.
Combine: join two streams on a key
Section titled “Combine: join two streams on a key”A combine node
takes two named inputs and joins them where a key matches. This is Clinker’s real
order_fulfillment join: orders enriched with details from a product catalog.
- type: combine name: product_lookup input: orders: normalize_fields # two NAMED inputs (not a list) products: products config: where: "orders.product_code == products.product_code" # the join key match: first # if several products match, take the first on_miss: null_fields # no match? keep the order, product fields null cxl: | emit order_id = orders.order_id emit product_name = products.product_name emit category = products.category🌱 New here? — input: as a named map
A normal node has a single input: naming one upstream node (lesson 03). A combine instead
takes a named map of inputs (orders: and products:), so its where and cxl can say
which side a field comes from (orders.order_id vs products.product_name). The names are
yours to choose; they’re just labels for the two sides.
The two knobs that decide the join’s behavior:
match: when more than one row on the other side matches the key,firsttakes one; other modes keep all matches.on_miss: when nothing matches,null_fieldskeeps the order and leaves the product columns null (a left join). The alternative is to drop the unmatched row.
Predict first
Section titled “Predict first”Merge: stack same-shaped streams
Section titled “Merge: stack same-shaped streams”When two streams are the same shape and you just want them in one list, use merge. This is
Clinker’s multi_source_session example: web and mobile logins, combined into one stream.
- type: merge name: all_logins inputs: [src_web, src_mobile] # a LIST — order-agnostic unionNo where, no key. merge simply interleaves the rows of every input into a single stream
for the next node (often an aggregate). Note the shape of the wiring is different from
combine: merge takes inputs: as a list, because the streams are peers; combine
takes input: as a named map, because it must tell the two sides apart.
// quick check
You have last year's sales and this year's sales in two files, same columns, and want one combined dataset to total. combine or merge?
Same shape + you want all the rows in one stream = merge (a union). combine is for joining different streams on a key to make each row wider.
Combining streams isn’t the only thing you can do across rows. Restructuring rows (rewriting
some of them, or dropping/routing whole groups) gets its own lesson next, with the
reshape and cull nodes.