> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bensevern.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Privacy-preserving linkage

> Match records across organizations without sharing raw data, using Bloom-filter PPRL.

Privacy-preserving record linkage (PPRL) lets two parties find shared entities without exchanging plaintext identifiers. GoldenMatch encodes fields into Bloom filters and matches on those, reaching F1 0.924 on the FEBRL4 benchmark.

## Auto-configured

```python theme={null}
import goldenmatch as gm

result = gm.pprl_link("hospital_a.csv", "hospital_b.csv")
print(f"Found {result['match_count']} matches")
```

## Manual config

```python theme={null}
import goldenmatch as gm

result = gm.pprl_link(
    "party_a.csv", "party_b.csv",
    fields=["first_name", "last_name", "dob", "zip"],
    threshold=0.85,
    security_level="high",
)
```

## Large lists (memory-safe)

The trusted-third-party protocol scores every Party A record against every Party B record. Done densely, that materializes the full `N_a × N_b` similarity matrix in one allocation — a 50k × 50k link is \~10 GB and OOMs. Set `chunk_size` to stream Party B in blocks instead: Party A's bit matrix stays resident while B is processed `chunk_size` records at a time, so peak memory drops to roughly `matrix_a + one block`.

```python theme={null}
import goldenmatch as gm
import polars as pl

cfg = gm.PPRLConfig(
    fields=["first_name", "last_name", "dob", "zip"],
    threshold=0.85,
    chunk_size=5000,        # process Party B in 5k-record blocks
)
# run_pprl takes Polars DataFrames, not file paths
result = gm.run_pprl(pl.read_csv("party_a.csv"), pl.read_csv("party_b.csv"), config=cfg)
```

`chunk_size=None` (the default) runs the original single-block dense path and is byte-for-byte identical to leaving it unset — the threshold test, the cluster output, and the match count are all invariant to `chunk_size`. On a 4000 × 4000 link, dense peak memory of \~305 MB drops to \~34 MB at `chunk_size=200` (\~9×) and \~21 MB at `chunk_size=50` (\~14×) for identical output. Smaller chunks trade a little extra Python overhead for lower peak memory.

## CLI

```bash theme={null}
goldenmatch pprl link file_a.csv file_b.csv
```

<Warning>
  PPRL reduces but does not eliminate disclosure risk. Choose `security_level` and field sets with your privacy and compliance requirements in mind.
</Warning>
