Articles
Talend Interview Questions: tMap Lookup Matches, Reject Flows, and Duplicate Rows
Prepare for Talend tMap interviews with a four-row lookup fixture, match-model matrix, inner-join reject routing, and duplicate-row reconciliation.
A Talend tMap interview is often really a cardinality and reconciliation interview. Give one main row two lookup matches, switch the match model, and ask how many rows leave the normal and reject outputs. The strong answer names the main and lookup flows, the join model, the match model, and the output setting before doing the count. “It is just a SQL join” skips the behavior that makes a Talend Job fail quietly.
The mechanics here are grounded in Qlik's Talend Studio 8.0 explicit-join guide, match-model documentation, and inner-join reject guidance. The rows, reconciliation ledger, and suggested tests are original exercises, not an account of any employer's questions or a claim that we ran this Job in Talend Studio.
What should you establish before predicting rows?
Ask which flow is main, which flows are lookup, and how the lookup is joined. The Talend lookup documentation describes one main flow and one or more lookup flows in a tMap. That asymmetry matters: main rows drive the transformation, while a matching lookup can enrich or multiply their output depending on the selected model. A common interview mistake is to count lookup records as if they were independent main inputs.
Next inspect the explicit or inner join, the expression key, match model, lookup filter, output filter, and output's reject setting. Do not infer cardinality from the diagram alone. A join on customer_id differs from a join on (customer_id, region); a lookup with duplicate business keys differs from one constrained unique at the source. Talend's match-model choices are not merely performance switches. They decide which lookup results are considered.
Finally establish what the candidate means by “duplicate.” It could mean duplicate lookup keys, repeated main business keys, identical final rows, or a second output that deliberately receives the same main input. Those are different incidents. Name a unique main-row identifier and keep it through a diagnostic output. That lets a row ledger distinguish intentional one-to-many expansion from accidental reprocessing.
What do Unique, First, and All matches mean?
Qlik's tMap match-model example documents three explicit choices. All matches emits each qualifying lookup match for a main row in its output path. First match selects the first matching lookup row. Counterintuitively, Unique match behaves as a last match in the documented standard-component example. “Unique” here does not certify that lookup keys are unique in the source; it chooses one result when duplicates exist. The selection's practical stability depends on the lookup's ordering/loading behavior, so do not promise a reproducible business winner without an explicit ordering or upstream deduplication rule.
This distinction is visible with two lookup rows for the same key. If both are semantically valid, All matches may be exactly what a one-to-many enrichment needs. If only one current dimension record should win, selecting First or Unique hides a data-quality question unless a source rule defines the winner. For example, “latest by effective timestamp, then greatest source event ID” is an explicit rule. “Whichever Talend reads last” is not a defensible business rule, even if a sample run happens to look right.
The Talend All Rows guide adds a separate trap: with no join set up, its default All rows behavior can produce a Cartesian product. Do not confuse All rows without a join with All matches under an explicit join. The names sound similar but answer different questions. The quickest diagnosis is to inspect whether an actual expression key and join link exist.
Work through a four-row tMap fixture
Use this original, unexecuted fixture. The main flow has four physical rows: M1: A, M2: A, M3: B, and M4: C. The lookup flow has L1: A/red, L2: A/blue, and L3: B/green. Join on the letter key, use an Inner Join, and put unmatched main rows on a dedicated lookup-inner-join reject output. There is no output filter. The colors are payloads, not ordering guarantees.
| Main row | Qualifying lookup rows | All matches normal output | First/Unique normal output | Inner-join reject |
|---|---|---|---|---|
M1: A | L1, L2 | Two rows | One selected row | None |
M2: A | L1, L2 | Two rows | One selected row | None |
M3: B | L3 | One row | One row | None |
M4: C | None | None | None | One M4 row |
| Totals | — | Five normal | Three normal | One reject |
The table assumes the documented match models and one inner-join reject output. It does not prove which A payload wins in a real Job without the lookup's ordering behavior. Under All matches, the two A main rows each fan out twice: four A outputs plus one B output. There are still only four input main rows. Therefore a naive check normal_count + reject_count == main_count would fail despite correct one-to-many behavior. The right check is by main-row ID: every main row has either one reject or the expected number of matched descendants.
Change one thing at a time in the interview. Remove the expression key and ask what All rows does. Add a second lookup row for B. Add a lookup filter that removes L2. Ask whether M4 should be rejected or preserved with null lookup fields under a left outer join. Each variation tests a distinct contract; piling them together before writing a baseline makes errors hard to explain.
How does the inner-join reject flow differ from an output filter?
Qlik's Inner Join guide explains that a failed inner join can be routed to an output defined as an Inner Join Reject table. Its worked transformation sets Catch Lookup inner join reject on the reject output. That is a specific reason for rejection: the lookup match was not established. A row removed later by an output filter is not automatically the same kind of reject. Likewise, malformed input rejected by a file-reading component may never reach this tMap.
If a stakeholder says “put bad rows in reject,” ask which bad condition they mean. Unknown lookup key? Null required value? Filtered-out status? Expression evaluation failure? Route each reason deliberately, preferably with an error code, source identifier, run ID, and minimum useful context. An unmatched reference should not be labeled a parse failure. The distinction shapes whether the recovery action is to fix dimension data, repair source schema, or change a business filter.
For a multi-lookup tMap, rejection can be harder to attribute. A row might fail the first lookup, the second lookup, or a filter. Preserve the lookup keys and instrument intermediate row counts or diagnostic outputs while investigating. Once the reason is clear, simplify the production Job; an always-on network of duplicate diagnostic outputs can itself create confusion. The interview answer should show where evidence is collected, not just say “look at logs.”
Why did an ETL target suddenly double in size?
Start with a row-grain statement. If the target is one row per order, but the lookup contains two valid prices for an order key, All matches makes two output rows unless the join includes an effective date or an upstream winner rule. Before changing All matches to Unique, ask whether the lookup was supposed to be one-to-one. If yes, count keys with COUNT(*) > 1, inspect source history, and define a deterministic policy. If no, the target grain or later aggregation may be wrong instead.
Build a simple ledger for one run: physical main inputs, distinct main IDs, lookup key counts, outputs by route, and distinct main IDs observed on each route. In the fixture, normal output is five, reject is one, distinct matched main IDs are three, and distinct rejected main IDs are one. Those facts reconcile four main inputs without pretending output count should equal input count. If the target writes six rows, the extra one may come from another output branch, rerun, append mode, or duplicate input—not necessarily this lookup.
The second ledger is temporal. Check whether the Job reran a batch and appended results, whether a target write is idempotent, and whether a prior partial run left records. A tMap match-model change can explain multiplication within one run; it does not by itself explain two identical runs. Preserve a batch ID or source event ID in test data so you can distinguish them.
How would you make the winner deterministic?
First decide what the business rule is. “Prefer the active dimension record effective at the transaction timestamp” is different from “take the newest arrival.” If two rows tie under the chosen timestamp, add a tie-breaker. Then apply the rule before the tMap lookup, or use a component/query that produces one row per key with the rule visible. Verify the lookup uniqueness assertion as data quality, rather than relying on Unique match to hide violations.
For slowly changing data, the join key may include a validity interval, not simply a customer ID. Define boundary inclusivity (valid_from <= event_time < valid_to), time zone, null open-ended interval, and what happens if intervals overlap. Two matches may indicate corrupt dimension history. A candidate who switches to a single match mode without noticing overlap has concealed a data defect. If several matches are intentional, retain All matches and make the target grain explicit.
In a small test, shuffle the lookup's input order while keeping rows the same. If the chosen payload changes, the selection was order-dependent. That is a useful falsification of “Unique guarantees one correct row.” We have not executed this Talend test here; it is a proposed Job-level check to run in the installed Studio version and component mode. Version and component scope should be recorded with the evidence because documentation and generated code can vary.
What should a candidate test in Talend Studio?
Create small main and lookup files from the four-row fixture. Preview the inputs to confirm physical rows and key types. Configure the join and one match model, run the Job, and capture both normal and reject outputs. Compare row IDs and payloads with the matrix. Change only the match model, rerun into clean output destinations, and inspect counts again. Finally remove the join link in a separate test and confirm the All rows behavior so a missing key cannot silently pass review.
Test a null key, a case or whitespace mismatch, a duplicate lookup key, and an output filter separately. Capture what the component actually emits for each; do not infer string normalization or null matching. If the Job has multiple lookups, add them one at a time and record the cardinality after each. At deployment scale, also inspect lookup loading strategy, memory, and rejected-row volume. A small correct preview does not prove that a large lookup fits memory or that a target's batch replay is safe.
For reconciliation, assert on identity, not only totals. Every input main ID should be accounted for as matched, rejected, or intentionally filtered, with a reason. For an intended one-to-one target, assert no key produces more than one normal descendant. For an intended one-to-many target, assert that descendants match the qualifying lookup count. These tests catch both lost rows and silent fan-out.
What is a concise interview answer?
“I would label the main and lookup flows, expression key, join model, match model, and reject-output setting. With two lookup matches for an A key, All matches can create two normal rows per A main row; First match picks one; Talend's documented Unique match behaves as a last match in the standard example, so I would not treat its name as a uniqueness constraint. A failed inner join can go to a Catch Lookup inner join reject output, while an output-filtered row is a different case. I would preserve main-row IDs, reconcile distinct IDs and descendant counts, and define any one-row winner upstream with a deterministic business rule. Then I would run a tiny fixture in the actual Studio/component version.”
If the interviewer changes the target grain, revisit the match policy rather than repeating the same one-row assumption.