CoolFace
Datasetpublic

zal-analytics-core/dutch-law-enforcement-entity-resolution-dataset

Dutch Law Enforcement Entity Resolution Benchmark A collection of synthetic benchmark datasets for entity resolution and record linkage research, modelled on real Dutch and EU/EEA law enforcement data schemas. All data is 100% synthetic. No records correspond to real persons, vehicles, phone numbers, transactions, or criminal histories. Every name, date, plate number, IBAN, IMSI, and identifier is procedurally generated. The datasets are freely usable, shareable, and… See the full description on the dataset page: https://huggingface.co/datasets/zal-analytics-core/dutch-law-enforcement-entity-resolution-dataset.

sourceHugging Facecc-by-4.0updated 3mo agoView on Hugging Face
2likes326downloads
Dataset Card

Dutch Law Enforcement Entity Resolution Benchmark

A collection of synthetic benchmark datasets for entity resolution and record linkage research, modelled on real Dutch and EU/EEA law enforcement data schemas.

All data is 100% synthetic. No records correspond to real persons, vehicles, phone numbers, transactions, or criminal histories. Every name, date, plate number, IBAN, IMSI, and identifier is procedurally generated. The datasets are freely usable, shareable, and publishable without privacy or legal concerns.
Work in progress. This dataset collection is actively evolving. Generation logic, schemas, and demographic distributions are being progressively ported from the internal zsimulate and zbroker simulation libraries maintained by ZAL Analytics. Not all providers have reached feature parity with those systems yet; schemas and ground truth formats may change between releases.

Datasets are generated from real-world schemas (KvK Handelsregister, Basisregistratie Personen, SIS II Article 26/36 specification, Dutch ANPR kentekencamera feed, HKS criminal antecedents, Interpol I-24/7 notice schema, telecom CDR / ETSI LI standard, FIU-NL GTR) combined with authentic Dutch demographic distributions from CBS (Centraal Bureau voor de Statistiek) statistics. Error patterns, name variants, OCR confusion, romanization differences, estimated dates of birth, SIM swap events, are injected to replicate the specific challenges found in Dutch and cross-Schengen identity data.


Why this dataset exists

Standard entity resolution benchmarks (DBLP-ACM, Febrl, Cora) do not reflect the challenges of Dutch law enforcement data:

  • —Dutch name complexity, tussenvoegsel prefixes (van, de, van der, van den, van 't) are frequently omitted, abbreviated, or formatted inconsistently across registrations
  • —Multicultural name variation, Dutch-Moroccan and Dutch-Turkish communities produce names with authentic spelling variants (Mohammed / Mohamed / Muhammad, dropped Turkish diacritics like Çelik → Celik)
  • —Cross-Schengen identity, SIS II entries are registered by different member states in different scripts; the same person may appear as Benabdallah Fatima in one state and Fatima Benabdallah in another, with Arabic-script aliases alongside Latin ones
  • —ANPR OCR errors, Dutch highway cameras produce predictable single-character plate confusions (0↔O, 1↔I, 8↔B, 5↔S, 2↔Z) that require fuzzy matching rather than exact lookup
  • —Estimated dates of birth, asylum and immigration records frequently use YYYY-01-01 (January 1st fallback) when the exact birth date is unknown, creating year-boundary matching challenges
  • —Telecom identity churn, SIM swap events mean the same MSISDN can be associated with different persons over time, while IMEI reuse links different subscribers through a shared device
  • —Financial network structure, money mule rings and structuring patterns require graph-aware resolution rather than pairwise comparison

Versioning

v1.1 (current)

v1.1 changes how records are identified throughout the pipeline and in all generated datasets. The changes are breaking: v1.0 datasets and entity stores are not compatible with v1.1 and must be regenerated.

Record identity: natural keys replace sequential integers

In v1.0, records were assigned sequential integer IDs by the caller and ID offsets were required to prevent collisions between sources. In v1.1, every record is anchored to its natural key (the value from whichever column is its authoritative identifier: BSN for BRP, kvk_nummer for KvK, etc.). The internal numeric ID is derived deterministically via FNV-1a(source:key), so the same (source, key) pair always produces the same ID with no collision risk across sources.

Ground truth format: natural key pairs replace integer ID pairs

In v1.0, all ground truth files used record_id_a, record_id_b columns containing sequential integers. In v1.1, ground truth files use the natural key of each source directly:

Datasetv1.0 columnsv1.1 columns
BRP persons (dedup)record_id_a, record_id_bbsn_a, bsn_b
Cross-source linkagerecord_id_a, record_id_bkey_a, key_b
Multi-source (BRP↔KvK)record_id_a, record_id_bkey_a (BSN), key_b (kvk_nummer)
Benchmarksrecord_id_a, record_id_brecord_id_a, record_id_b (values are already BSN/UUID: column names unchanged for backward compatibility with zer-bench, which reads by position)

Data directory layout: versioned subdirectory

Demo, example, and test datasets are now generated under data/v1.1/ to preserve v1.0 data in data/demos/, data/tests/, and data/examples/ for reference:

PathContent
data/demos/v1.0 demo datasets (sequential integer IDs)
data/v1.1/demos/v1.1 demo datasets (natural key IDs)
data/tests/v1.0 integration test datasets
data/v1.1/tests/v1.1 integration test datasets
data/examples/v1.0 crate example datasets
data/v1.1/examples/v1.1 crate example datasets
data/benchmarks/Benchmark scenarios (all versions: zer-bench reads by column position so both formats are accepted)

EntityMember `record_key` field

The entity_members table in .zes entity store files has a new record_key TEXT NOT NULL column. v1.0 .zes files cannot be opened by v1.1: delete and regenerate them.

`data/raw/` removed

The data/raw/ directory and its generator (generate_raw.py) have been removed. Raw provider datasets at multiple scale tiers are no longer part of the standard generation workflow. Benchmark scenarios in data/benchmarks/ cover the same providers at appropriate scales for evaluation purposes.

v1.0

Original release. Records identified by caller-managed sequential integers. Ground truth files used record_id_a, record_id_b columns. Multi-source pipelines required manual ID offsets to prevent collisions. Demo/test/example data under data/demos/, data/tests/, data/examples/ without version subdirectory.


Datasets

1. KvK Director Records

Company director registrations from the Dutch Chamber of Commerce (Kamer van Koophandel). The same person often directs multiple companies, with each registration entered independently, producing name variants, formatting differences, and address drift over time. Directors of BV and NV companies are registered as bestuurders; sole proprietors (Eenmanszaak) are both owner and entity.

Files: kvk_director_flat.csv, kvk_director_extract.json, ground_truth_pairs.csv

Schema, `kvk_director_flat.csv`:

FieldTypeDescription
kvkNummerstringChamber of Commerce registration number (8 digits)
rechtsvormcategoricalLegal form (Eenmanszaak, BV, NV, VOF, …)
handelsnaamstringCompany trading name
voornamenstringDirector given names
tussenvoegselstringDutch name infix (van, de, van der, …), may be empty
achternaamstringDirector surname
geboortedatumdateDate of birth (ISO 8601)
geboorteplaatsstringPlace of birth
woonplaatsstringCity of residence
postcodestringDutch postcode (DDDDLL)
straatnaamstringStreet name
huisnummerstringHouse number
sbiCodestringSBI sector classification code
aantalWerkzamePersonenintegerNumber of employees

Ground truth format: kvk_a, kvk_b, is_match, match_type

Match types: same_person_multi_company, duplicate_entry, name_variant

Default scale: ~2,000 director records · ~1,300 true pairs

Injected error patterns:

  • —Tussenvoegsel variants: van der / v/d / vd / omitted entirely
  • —Abbreviated given names: Johannes → J. or J.A.
  • —Case and whitespace inconsistencies across independent registrations
  • —Address drift between an individual's multiple company registrations

2. BRP Population Register

Person records modelled on the Basisregistratie Personen (BRP), the Dutch municipal population register. Every resident, Dutch national or foreign national with a registered address, has a BRP entry. The dataset tests string similarity matching, address normalisation, date of birth transcription errors, and dual-nationality scoring.

Files: brp_persons.csv, ground_truth_pairs.csv

Schema, `brp_persons.csv`:

FieldTypeDescription
bsnstringBurgerservicenummer, passes 11-test (elfproef)
voornamenstringGiven names
tussenvoegselstringTussenvoegsel, may be empty
achternaamstringSurname
geboortedatumdateDate of birth (ISO 8601)
geboorteplaatsstringMunicipality of birth
geboortelandstringCountry of birth (ISO 3166-1 alpha-2)
nationaliteitstringNationality; dual nationality separated by / (e.g. NL/MA)
geslachtcategoricalSex (M, V)
straatnaamstringStreet name
huisnummerstringHouse number (may include toevoeging: 12A, 12bis)
postcodestringDutch postcode (DDDDLL)
woonplaatsstringMunicipality of residence
verblijfstitelstringResidence permit type (blank for Dutch nationals)

Ground truth format: bsn_a, bsn_b, is_match, match_type

Match types: address_move, name_variant, dob_error, nationality_partial

Default scale: ~11,000 records · ~1,000 true pairs

Injected error patterns:

  • —Address moves: same person registered at two different addresses across time
  • —Name variants: abbreviated given names, tussenvoegsel capitalised or omitted
  • —Date of birth transcription errors: day and month transpositions
  • —Partial nationality: one record shows dual nationality, the other only one

3. SIS II Wanted and Missing Persons

Person records modelled on the Schengen Information System II (SIS II) Article 26 (wanted persons) and Article 36 (missing persons) schemas. The key challenge is cross-Schengen alias pairs: the same individual entered by different member states using different name order conventions, romanizations, or scripts.

Files: sis_persons.csv, ground_truth_alias_pairs.csv

Schema, `sis_persons.csv`:

FieldTypeDescription
sis_idstringSIS II alert identifier (8 hex chars)
categoriecategoricalAlert category (wanted_person, missing_person)
voornamenstringGiven names
achternaamstringSurname
alias_namenstringPipe-delimited alias list (`alias1\alias2\alias3`)
geboortedatumdateDate of birth; YYYY-01-01 for estimated DOBs
geboorteplaatsstringPlace of birth
geboortelandstringCountry of birth (ISO 3166-1 alpha-2)
nationaliteitstringNationality (ISO 3166-1 alpha-2)
geslachtcategoricalSex (M, V)
document_typecategoricalDocument type (Paspoort, Identiteitskaart, …)
document_nummerstringDocument number
uitgevend_landstringIssuing country (ISO 3166-1 alpha-2)
lengteintegerHeight in cm
haarkleurcategoricalHair colour
oogkleurcategoricalEye colour
aanmakende_staatstringSchengen member state that created the alert

Ground truth format: sis_id_a, sis_id_b, is_match, match_type

Match types: alias_romanization_variant, name_transposition, estimated_dob_variant, cross_script_alias

Default scale: ~9,000 records · ~4,000 true pairs

Injected error patterns:

  • —Name transposition: Benabdallah Fatima ↔ Fatima Benabdallah (given/surname order varies by country convention)
  • —Romanization variants: Mohammed / Mohamed / Muhammed; Youssef / Yousef / Yusuf
  • —Estimated date of birth: ~30% of records use YYYY-01-01 (January 1st fallback)
  • —Non-Latin script aliases: Arabic-script aliases alongside Latin primary names
  • —Document number prefix variation: same serial with different country-code prefixes

4. HKS Criminal Antecedents

Records modelled on the Herkenningsdienstsysteem (HKS), the Dutch National Police criminal antecedents system. HKS records are subject-oriented rather than incident-oriented: a single individual may appear under their registered name in the BRP while their HKS entry carries a street alias or romanization variant. The BSN is present for ~60% of records.

Files: hks_records.csv, ground_truth_pairs.csv

Schema, `hks_records.csv`:

FieldTypeDescription
hks_idstringHKS record identifier
voornamenstringGiven names (may be alias)
achternaamstringSurname (may be alias)
tussenvoegselstringTussenvoegsel, may be empty
alias_namenstringPipe-delimited street and document aliases
geboortedatumdateDate of birth (ISO 8601)
geboorteplaatsstringPlace of birth
geboortelandstringCountry of birth (ISO 3166-1 alpha-2)
nationaliteitstringNationality (ISO 3166-1 alpha-2)
geslachtcategoricalSex (M, V)
bsnstringBSN, present in ~60% of records; empty otherwise
document_typecategoricalIdentity document type
document_nummerstringDocument number
lengteintegerHeight in cm
haarkleurcategoricalHair colour
oogkleurcategoricalEye colour
delict_typesstringPipe-delimited offence categories

Ground truth format: hks_id_a, hks_id_b, is_match, match_type

Match types: alias_vs_registered_name, bsn_linked, street_alias, romanization_variant

Default scale: ~6,400 records · ~1,400 true pairs

Injected error patterns:

  • —Registered name vs. street alias: BRP name differs from HKS operational alias
  • —BSN linkage: direct BSN match despite all name fields differing
  • —Street alias abbreviation: Mohammed El Haddad → Mo Haddad
  • —Romanization: Arabic-origin surnames appear in multiple Latin transcriptions

5. Interpol Notices

Records modelled on the Interpol I-24/7 notice schema (Red, Blue, Yellow, and Green notices). The primary cross-source challenge is that the same individual may appear in SIS II under a Dutch or German romanization convention and in Interpol under a French or English convention, producing the same person with systematically different spellings across two datasets.

Files: interpol_notices.csv, ground_truth_pairs.csv

Schema, `interpol_notices.csv`:

FieldTypeDescription
notice_idstringInterpol notice identifier
notice_typecategoricalNotice colour (Red, Blue, Yellow, Green)
voornamenstringGiven names
achternaamstringSurname
alias_namenstringPipe-delimited aliases
geboortedatumdateDate of birth (ISO 8601)
geboorteplaatsstringPlace of birth
geboortelandstringCountry of birth (ISO 3166-1 alpha-2)
nationaliteitstringNationality (ISO 3166-1 alpha-2)
geslachtcategoricalSex (M, V)
talenstringPipe-delimited languages spoken
document_typecategoricalIdentity document type
document_nummerstringDocument number
lengteintegerHeight in cm
gewichtintegerWeight in kg
haarkleurcategoricalHair colour
oogkleurcategoricalEye colour
aanvragende_landenstringPipe-delimited requesting member countries

Ground truth format: notice_id_a, notice_id_b, is_match, match_type

Match types: cross_source_romanization_variant, alias_match, partial_dob

Default scale: ~3,600 records · ~630 true pairs

Injected error patterns:

  • —Cross-source romanization: different transliteration conventions per requesting country
  • —Name-order transposition between Western (given-surname) and Eastern (surname-given) conventions
  • —Partial date of birth: year only, or year + month, without day

6. ANPR Vehicle Passages

Highway camera passage events modelled on the Dutch ANPR (Automatische NummerPlaat Herkenning) kentekencamera feed operated by Dienst Verkeerspolitie. The primary challenge is single-character OCR confusion: a camera may read CX-I80-W when the true plate is CX-180-W. Vehicle trajectories link the same vehicle across multiple cameras on a corridor.

Files: anpr_passages.csv, ground_truth_vehicle_pairs.csv

Schema, `anpr_passages.csv`:

FieldTypeDescription
passage_idstringPassage identifier ({8hex}-{3hex})
tijdstipdatetimePassage timestamp (ISO 8601 with time)
camera_idstringCamera identifier (CAM-{road}-{seq}, e.g. CAM-A12-001)
wegstringHighway designation (A1, A2, A4, A10, A12, A20, …)
latfloatCamera latitude (decimal degrees, WGS84)
lonfloatCamera longitude (decimal degrees, WGS84)
rijrichtingcategoricalDirection of travel (N, Z, O, W)
kentekenstringLicense plate as read by OCR, may contain a single-character error
kenteken_betrouwbaarheidintegerOCR confidence score 0–100
merk_herkendstringVehicle make (if MMR camera detected it)
kleur_herkendcategoricalVehicle colour (if detected)
snelheid_kmhintegerSpeed in km/h

Ground truth format: passage_id_a, kenteken_true, kenteken_ocr, is_match, match_type

Match types: ocr_confusion (with specific substitution noted, e.g. 1_to_I)

Default scale: ~50,000 passages · ~2,490 true pairs

Injected OCR confusion pairs (single substitution per plate, bidirectional):

Character readPossible true charactersTypical cause
O0, QRounded glyphs
0O, QRounded glyphs
QO, 0Rounded glyphs
1I, TVertical strokes
I1, TVertical strokes
T1, IVertical strokes
8B, E, 3, 6Closed loops
B8, P, RClosed loops
E8, FHorizontal bars
5S, 3Curved top
S5Curved top
2ZDiagonal stroke
Z2Diagonal stroke
PR, BClosed loop + stem
CGOpen arc
GCOpen arc
MWMirrored peaks
WM, VMirrored peaks
DOCurved back
A4Crossbar
4A, 9Crossbar / tail
KXDiagonal arms
XKDiagonal arms

The confusion table was extended beyond the original five pairs using documented sources on ANPR character confusion under Dutch highway conditions (low-angle cameras, motion blur, wet conditions). The default OCR error rate is calibrated at 1% per plate, consistent with published accuracy figures for modern Dutch kentekencamera systems on dry, well-lit motorways. Earlier synthetic datasets used a 5% rate, which overrepresents errors by a factor of 5–25× relative to operational data.

Dutch license plate formats used: DD-LLL-D, LL-DD-LL, DD-LL-DD, L-DDD-LL, LL-DDD-L (current RDW series). Camera coordinates are sampled from bounding boxes around real Dutch highway corridors (A1, A2, A4, A10, A12, A15, A20, A28).


7. CDR Call Detail Records

Call detail records modelled on the telecom CDR / ETSI LI standard as used in Dutch lawful interception. The primary resolution challenge is identity across the MSISDN/IMSI/IMEI triple: a SIM swap leaves the MSISDN the same but changes the IMSI; a device sale leaves the IMEI the same but changes both MSISDN and IMSI. Graph-annotated variants include structured subscriber clusters (10–40 nodes, 85% intra-cluster calling) for community detection tests.

Files: cdr_records.csv, ground_truth_clusters.csv

Schema, `cdr_records.csv`:

FieldTypeDescription
cdr_idstringRecord identifier (UUID)
tijdstip_startdatetimeCall start timestamp (ISO 8601)
duur_secondenintegerCall duration in seconds
call_typecategoricalCall type (voice, sms, data)
msisdn_astringCalling party MSISDN (E.164, +316…)
imsi_astringIMSI of calling party
imei_astringIMEI of calling device (15 digits)
cell_id_a_startstringCell tower ID at call start
msisdn_bstringCalled party MSISDN (E.164)
imsi_bstringIMSI of called party
imei_bstringIMEI of called device
carrier_astringCarrier of calling party (KPN, T-Mobile, Vodafone, …)
carrier_bstringCarrier of called party

Ground truth format: msisdn, imsi, cluster_id, is_hub

The ground truth table is a cluster-membership list rather than a pair list. Each row assigns a subscriber (MSISDN + IMSI) to a cluster and flags whether they are the communication hub of that cluster.

Default scale: ~50,000 records · ~6,300 cluster-membership rows

Call duration calibration: Call duration distributions are grounded in two real-world CDR datasets from Kaggle (see Base data sources). Distributions were derived from approximately 101,000 records across both sources and show the characteristic Dutch mobile calling pattern: median call ~86 seconds, long tail up to ~76 minutes for extended calls. Cluster sizes for social-graph mode (10th–75th percentile: 1–29 contacts per subscriber) are likewise derived from the network degree distribution observed in the same sources.

Injected identity patterns:

  • —SIM swap: same MSISDN, old IMSI replaced by new IMSI mid-dataset (~15% of clusters)
  • —IMEI reuse: same device IMEI appears under two different MSISDNs (device resold / shared)
  • —Burner handset: new IMEI + new MSISDN registered within existing communication cluster

8. SIM Subscriber Registrations

Subscriber registration records modelled on Dutch telecom subscriber databases as maintained by KPN, T-Mobile, Vodafone, Tele2, and associated MVNOs. Pairs the identity data collected at point-of-sale (name, date of birth, document number) with the technical subscriber identity (MSISDN, IMSI, ICCID). A companion swap-events table records IMSI changes on the same SIM card.

Files: sim_subscribers.csv, sim_swap_events.csv, ground_truth_swaps.csv

Schema, `sim_subscribers.csv`:

FieldTypeDescription
sim_idstringInternal subscriber record identifier
msisdnstringMobile number (E.164, +316…)
imsistringInternational Mobile Subscriber Identity
iccidstringSIM card serial number (19 digits)
carrierstringCarrier name
contract_typecategoricalContract type (prepaid, postpaid)
activatiedatumdateSIM activation date (ISO 8601)
voornamenstringSubscriber given names
achternaamstringSubscriber surname
geboortedatumdateDate of birth
nationaliteitstringNationality (ISO 3166-1 alpha-2)
document_typecategoricalIdentity document used at registration
document_nummerstringDocument number
bsnstringBSN, present for postpaid contracts; empty for prepaid

Schema, `sim_swap_events.csv`:

FieldTypeDescription
swap_idstringSwap event identifier
msisdnstringMSISDN on which the swap occurred
oude_imsistringIMSI before the swap
nieuwe_imsistringIMSI after the swap
tijdstipdatetimeTimestamp of the swap event

Ground truth format: sim_id_a, sim_id_b, msisdn, is_match, match_type

Match types: sim_swap_same_person, shared_device, identity_document_reuse

Default scale: ~10,800 subscriber records · ~800 swap events · ~800 true pairs

Injected identity patterns:

  • —SIM swap: same subscriber activates a replacement SIM, same MSISDN, new ICCID and IMSI
  • —Prepaid registration gap: prepaid subscribers registered without BSN, matched via name + DOB
  • —Document reuse: same identity document number associated with two subscriber registrations (stolen / cloned document scenario)

9. FIU Unusual Transaction Reports

Transaction records modelled on FIU-NL (Financial Intelligence Unit Nederland) Geldtransactie Reporting (GTR) reports, as required under the Wwft (Anti-Money Laundering Act). Graph-annotated variants include structured money mule rings (5–15 accounts per ring, feeder → mule hub → offshore IBAN pattern) for graph analytics and network-aware entity resolution.

Files: fiu_transactions.csv, ground_truth_clusters.csv

Schema, `fiu_transactions.csv`:

FieldTypeDescription
melding_idstringFIU report identifier
tijdstipdatetimeTransaction timestamp (ISO 8601)
transaction_typecategoricalTransaction type (overboeking, contant, crypto, betaalverzoek)
iban_senderstringSender IBAN (NL format: NL{check}{bank}{account})
naam_senderstringSender name
geboortedatum_senderdateSender date of birth
nationaliteit_senderstringSender nationality (ISO 3166-1 alpha-2)
iban_receiverstringReceiver IBAN
naam_receiverstringReceiver name
land_receiverstringReceiver country (ISO 3166-1 alpha-2)
bedrag_eurfloatTransaction amount in EUR
reden_meldingcategoricalReason for unusual transaction report

Ground truth format: iban, cluster_id, rol, is_mule

The ground truth table is a cluster-membership list. Each row assigns an IBAN to a money mule ring (cluster_id), specifies the role (feeder, hub, offshore), and flags whether the account is a mule account.

Default scale: ~20,000 transaction records · ~490 ring-membership rows

Transaction amount calibration: Transaction amounts are calibrated against the real financial transactions network dataset published by Cerqueira et al. (2022), a directed graph of 1.6 million accounts and 3.8 million transactions derived from a European banking dataset (see Base data sources). The empirical amount distribution shows a strongly right-skewed pattern: median transaction ~€2,000, 75th percentile ~€18,200, 90th percentile ~€275,000. Cash transaction structuring (amounts clustered just below the €10,000 mandatory reporting threshold) is modelled from the same source. Feeder-to-hub ring topology (number of feeders per mule account) is derived from the weakly connected component analysis of that network.

Injected network patterns:

  • —Structuring: large amounts split across multiple small transfers just below reporting thresholds
  • —Layering: feeder accounts transfer to a central mule hub, which then moves funds offshore
  • —Name discrepancy: IBAN holder name does not match the name on the FIU report (third-party account)
  • —IBAN prefix clustering: offshore IBANs cluster around a small set of high-risk jurisdictions

Benchmark Scenarios

The data/benchmarks/ directory contains pre-built evaluation scenarios derived from the schemas described above. Each scenario pairs one or more source files with a ground truth file that lists every true match pair, enabling precision/recall evaluation without requiring an exhaustive pairwise scan.

Task types

TypeDescription
DeduplicationA single source file; the task is to find all pairs of records within that file that refer to the same person
Record linkageTwo or more source files from different schemas; the task is to find all cross-source pairs that refer to the same person; no within-source duplicates are present
Link-and-dedupTwo or more source files; the task is to find both cross-source matches and within-source duplicates simultaneously

Standard scale (~10,000 records per source)

ScenarioTaskSourcesTotal recordsTrue pairs
brp/dedupeDeduplication1 × BRP11,1001,000
brp/linkRecord linkage2 × BRP7,100 + 7,1004,000
brp/link_and_dedupeLink-and-dedup2 × BRP7,800 + 7,8005,400
kvk/dedupeDeduplication1 × KvK11,1001,000
brp_kvk/linkRecord linkageBRP + KvK10,100 + 2,5002,500
brp_sis/linkRecord linkageBRP + SIS II10,100 + 500500
brp_hks/linkRecord linkageBRP + HKS10,100 + 1,5001,500
brp_kvk_hks/link_and_dedupeLink-and-dedupBRP + KvK + HKS11,100 + 2,500 + 1,5005,000

Micro scale (~1,000 records per source)

Reduced-scale versions of a subset of the standard scenarios. Schemas, error patterns, and generation logic are identical to their standard counterparts; only record counts differ. Intended as fast smoke tests.

ScenarioTaskTrue pairs
micro/brp/dedupeDeduplication100
micro/brp/linkRecord linkage400
micro/brp/link_and_dedupeLink-and-dedup540
micro/brp_sis/linkRecord linkage50

How benchmark datasets are generated

Each benchmark scenario is generated by data_generator/generate_bench.py using the same _common.py name, address, and demographic helpers that underpin all other generators. Generation proceeds in three steps:

  1. 1.Anchor population sampling: A pool of unique synthetic persons is drawn for the appropriate schema (BRP, KvK, SIS II, or HKS) using the same name distributions, demographic compositions, and field constraints described in the Datasets section above.
  1. 1.Duplicate and variant injection: For each true match pair, one record is treated as the canonical version and one or more perturbed variants are generated. Perturbations are drawn from the same error pattern catalogue as the raw datasets: tussenvoegsel variants, given name abbreviations, date-of-birth day errors (day shifted ±1, year and month preserved), address drift, name-order transpositions, romanization variants, estimated dates of birth, and alias substitutions. The specific patterns applied depend on the schemas involved: cross-schema scenarios apply the patterns that reflect real challenges between those two sources.
  1. 1.Confounder padding: Non-matching records are added to reach the target total. Confounders are always drawn from the most frequent surnames (following the same Zipf-weighted distribution as the raw data) so that same-surname, different-person pairs occur at realistic rates and are not trivially rejected.

The result is a scenario where true matches are scattered among a realistic population of non-matches, reproducing the difficulty of operational Dutch administrative data without including any real personal information.

Each dataset group in data/benchmarks/ (e.g. brp/, brp_kvk/) also contains a mapping.toml file that declares field comparison settings (comparison type, null handling, blocking keys) for use with splink. See data/benchmarks/README.md for the full format description.

Cross-schema field coverage

Cross-source scenarios are harder than single-schema scenarios because not all fields are available in both sources. A missing field should be treated as absent information, not as evidence of non-match:

FieldBRPKvKSIS IIHKS
voornamenYesYesYesYes
tussenvoegselYesYesNoYes
achternaamYesYesYesYes
geboortedatumYesYesYesYes
geboorteplaatsYesNoYesYes
geboortelandYesNoYesYes
nationaliteitYesNoYesYes
geslachtYesNoYesYes
woonplaatsYesYesNoNo
postcodeYesYesNoNo
straatnaam, huisnummerYesNoNoNo

Ground truth format

All ground truth files share the same structure:

FieldDescription
key_aNatural key of the first record (e.g. BSN, KvK number)
key_bNatural key of the second record
is_matchTrue for all rows (only confirmed matches are listed)
match_typeperturbed_duplicate (within-source duplicate) or cross_source_match (cross-source true match)

Any pair of records not listed in the ground truth file should be treated as a non-match.


Demographic composition

Name distributions reflect Dutch population demographics (CBS 2025, source: cbs.nl, Population by origin):

Name originShareApprox. number
Dutch (both parents born in NL)~72%~13.0 million
Other European~8–9%~1.5 million
Moroccan~2.4%~433,000
Turkish~2.4%~435,000
Surinamese~2.0%~360,000
Indonesian~2.0%~360,000
Other / rest of world~8–9%~1.5 million

Surname sampling follows a Zipf (power-law) distribution, the most common Dutch surnames (de Jong, Jansen, de Vries, van den Berg, …) are sampled proportionally more often than rare ones, matching the actual CBS surname frequency table. This ensures that confounders (records that share a common surname but are different persons) occur at a realistic rate and are not drawn from artificially uniform distributions.

Arabic and Turkish names are generated with authentic spelling variants to replicate the romanization challenges found in real Dutch administrative data. SIS II and Interpol records include a proportion of non-Latin script aliases.


File formats

All files are UTF-8 encoded CSV with a header row. Pipe (|) is used as the internal delimiter for multi-valued fields (e.g. alias_namen, delict_types). Ground truth files always include an is_match column (True / False) and a match_type column describing the specific error pattern injected. Cluster ground truth files use a membership-list format rather than a pair list.


Base data sources

Name and address pools

Name and address pools are derived from the following publicly available Kaggle datasets:

PurposeDatasetHow it influences generation
Surnames by national originalenic/surname-dataset-classificationDutch, German, Belgian, and Scandinavian surnames are drawn from this pool. Names are sampled with Zipf-weighted frequency so common surnames (de Jong, Jansen, de Vries) appear at realistic rates rather than uniformly.
Dutch postal codes, street names, and citiespieter79/postalcodes-street-city-netherlands-holland-dutchStreet names, postcode ranges, and municipality names in BRP, KvK, and SIM datasets are sampled from actual Dutch postcodes rather than procedurally generated strings.
Name classification by nationalityshubhampatel231/name-classificationUsed as a supplementary surname source. Falls back to the built-in CBS-derived pools when format does not match.

The Zipf weighting means that the top-ranked surnames are sampled far more often than rare ones, mirroring the real Dutch population register where de Jong is roughly 60× more common than a mid-ranked surname. This is important for confounder injection: confounders are always drawn from the most common surnames, matching real operational conditions where common names cause genuine ambiguity.

CDR call statistics

Call duration and network topology statistics are derived from two real-world CDR datasets published on Kaggle:

DatasetWhat was extracted
marcodena/mobile-phone-activityCell tower activity patterns for the Milan metropolitan area; used to inform geographic distribution modelling.
jakefurgoson/fraud-detection-using-call-detail-recordsAggregated per-subscriber CDR profiles (~101,000 records). Day-level minute totals and call counts were used to derive a realistic per-call duration distribution (median ~86 s, p90 ~558 s). Network degree distribution from the same source informs subscriber cluster sizes in social-graph mode.

FIU financial network topology

Money mule ring topology and transaction amount distributions are grounded in the Financial Transactions Network dataset:

Cerqueira, V., Torgo, L., & Moreira-Matias, L. (2022). Financial Transactions Network [Data set]. Available at the data accompanying "Fraud Detection under Privileged Information", IEEE TNNLS.

The dataset contains two directed graphs (GN and GT) of 1.6 million accounts and 3.8 million labelled financial transactions. The following statistics were extracted and used to calibrate generation:

  • —Transaction amounts, empirical percentiles (p25 ≈ €300, p50 ≈ €2,000, p75 ≈ €18,200, p90 ≈ €275,000) set the amount ranges for each transaction type. Cash structuring is calibrated so that ~40% of cash transactions cluster in the €8,500–€9,999 range, consistent with documented structuring patterns in FIU-NL reports.
  • —Ring (cluster) size, weakly connected component analysis of the labelled graph determines realistic feeder-per-hub counts (range: 2–30 feeders, consistent with the p50 WCC size of 2 and max of 200).
  • —Hub out-degree, p90 hub out-degree from the labelled graph (2.0) calibrates how many downstream offshore accounts a mule hub forwards to.

The source dataset is not redistributed in this repository. The extracted statistics are stored in data/base/fiu/fiu_topology.json.


Domain logic and error pattern definitions are being progressively ported from the zsimulate and zbroker simulation libraries developed at ZAL Analytics. Providers ported: BRP, SIS II, HKS, ANPR, KvK, CDR, FIU (all with calibrated distributions). Providers still in progress: Interpol, SIM.


License

All data is fully synthetic and released under CC BY 4.0. No real personal data, criminal records, vehicle information, or financial records are included. Attribution: cite this dataset as Dutch Law Enforcement Entity Resolution Benchmark (synthetic), arsalan-anwari, 2026.