Skip to main content
GoldenMatch runs a 10-step pipeline from raw files to golden records. Each step is a separate module in goldenmatch/core/.

Pipeline steps

1. Ingest

Load data from CSV, Excel, Parquet, or a Polars DataFrame.
Supported formats: .parquet, .xlsx, and delimited-text suffixes (.csv, .tsv, .txt, .dat, .tab, .psv). Cloud paths (s3://, gs://, az://) are handled by cloud_ingest. Each record gets an __row_id__ (int64) and __source__ column.

2. Column Map

Map columns between different schemas when matching across sources.
Column maps can be specified in the config or auto-detected. File specs support a third element: (path, source_name, column_map).

3. Auto Fix

Automatic data cleaning before validation.
Fixes include: encoding normalization, whitespace cleanup, type coercion (Polars infers zip/phone as Int64 — auto-fix converts to string).

4. Validate

Apply validation rules and quarantine bad records.
Actions: flag (keep but mark), null (set value to null), quarantine (remove from matching).

5. Standardize

Apply per-column standardization transforms.
Standardizers have a native Polars fast path (_NATIVE_STANDARDIZERS) that avoids Python UDFs for common transforms.

6. Matchkeys

Compute matchkey columns by applying field transforms.
Internal columns are prefixed with __mk_*__. Matchkey transforms also have a native Polars fast path (_try_native_chain).

7. Block

Reduce the comparison space by grouping records that share a blocking key.
Blocking key choice dominates fuzzy performance — coarse keys create huge blocks. Use auto_select: true to let GoldenMatch pick the best key by histogram analysis. Dynamic block splitting automatically handles oversized blocks by splitting on the highest-cardinality column.

8. Score

Compare record pairs within each block. Exact matching uses Polars self-join (not Python loops):
Fuzzy matching uses rapidfuzz.process.cdist for vectorized NxN scoring:
Parallel scoring: blocks are scored concurrently via ThreadPoolExecutor. RapidFuzz’s cdist releases the GIL, so threads give real parallelism. For 2 or fewer blocks, threading overhead is skipped. Intra-field early termination: after each expensive field, the scorer breaks early if no pair can reach the threshold. Backend selection: _get_block_scorer(config) returns score_blocks_parallel (threads) or score_blocks_ray (Ray distributed) based on config.backend.

9. Cluster

Group matched pairs into clusters via iterative Union-Find.
Confidence scoring: confidence = 0.4 * min_edge + 0.3 * avg_edge + 0.3 * connectivity. The bottleneck_pair identifies the weakest link in each cluster. Incremental updates:

10. Golden

Merge each cluster into one canonical record.
Eight merge strategies: most_complete, majority_vote, source_priority, most_recent, first_non_null, longest_value, unanimous_or_null, confidence_majority. Strategies can be set per-field.

Output

Write results to files or database.
Outputs: golden records, duplicates, unique records, lineage JSON, HTML report, dashboard. Lineage is auto-generated when the pipeline writes output. Each merge decision is saved with per-field score breakdown.

Pipeline entry points

The _run_dedupe_pipeline() and _run_match_pipeline() internal functions are shared by both file-based and DataFrame-based entry points.

Domain extraction (optional step)

Between standardize and matchkeys, domain extraction auto-detects product subdomains and extracts structured fields:
Electronics extraction: brand, model, SKU, color, specs. Software extraction: name, version, edition, platform.