Replace Java DUKE with a Splink matching engine#302
Closed
FabianHofmann wants to merge 2 commits into
Closed
Conversation
Experiment (cf. #301): swap the JVM DUKE record-linkage engine for powerplantmatching.linkage, a fixed-parameter Splink (Fellegi-Sunter) model on DuckDB. m/u probabilities are set directly from the former DUKE field weights, so no per-call EM training is needed and matching is deterministic. Java and the bundled .jar binaries are no longer required; splink is a hard dependency. Benchmarks vs DUKE on a ground truth recovered from powerplants.csv (analysis/linkage_findings.md): linkage F1 0.747 vs 0.780 at ~2.6x speed (recall exceeds DUKE at a lower threshold); dedup makes a comparable number of merges (459 vs 454, 86% principled) at ~7x speed.
for more information, see https://pre-commit.ci
| query = " and ".join(filter(None, [agg_query, block_query, country_query])) | ||
| duplicates = pd.concat( | ||
| [duke(df.query(query), threads=threads) for c in countries] | ||
| [match(df.query(query), threads=threads) for c in countries] |
|
|
||
| logging.disable(logging.WARNING) | ||
|
|
||
| import powerplantmatching as pm # noqa: E402 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
AI generated draft
Fully experimental
Side experiment, companion to #301 (which swaps DUKE for a
rapidfuzz+numpybackend). This one replaces the Java/JVM DUKE record-linkage engine with a pure-Python backend built on Splink + DuckDB, and makes it the sole matching engine. Matching no longer needs Java or the bundled DUKE.jarbinaries.Summary
powerplantmatching.linkage.match()builds a fixed-parameter Splink (Fellegi-Sunter) model: the per-fieldm/uprobabilities are set directly from the former DUKE field weights (Comparison.xml/Deleteduplicates.xml), so the model needs no per-call EM training and is deterministic and stable across the many small per-country slices the pipeline produces. A 0.5 prior reproduces DUKE's belief update; only the relative Bayes factor between levels matters for ranking, so one calibratedmatch_probabilitythreshold per mode sets the operating point.Rationale and benchmark numbers are in
analysis/linkage_findings.md.Changes
New engine
powerplantmatching/linkage.py—match()(list of two frames → record linkage, single frame → deduplication). Jaro-Winkler name levels, exact categoricals, capacity min/max ratio, haversine distance ladder.analysis/benchmark_splink.py— reproducible ground-truth + benchmark harness.Removed
duke.py,package_data/duke_binaries/*.jar(520K),Comparison.xml,Deleteduplicates.xmlLICENSES/Apache-2.0.txt(only the DUKE jars used it) and its REUSE / MANIFEST / docs referencestest/test_duke.pyWiring & config
matching.py/cleaning.pycallmatch()directly;**dukeargs→**kwargsacrossmatching.py,collection.py,accessor.pyparallel_duke_processes→parallel_processessplink>=4added topyproject.tomldependencies; docs (API reference, license notes, release notes)Results (vs DUKE, ground truth from
powerplants.csv)Record linkage (GEO × GPD, 12 countries, GT = 567 pairs):
~2.6× faster, within ~3 F1-points; recall exceeds DUKE at a lower threshold (raw recall ceiling 0.82).
Deduplication (GPD, 8 countries): the
powerplants.csvdedup clusters are DUKE's own output (circular), so the fair metric is merge behaviour — Splink makes 459 merges vs DUKE's 454, 86 % of them principled (same fueltype + within 5 km + high name similarity), at ~7× speed (3.2 s vs 21.7 s).Compatibility
parallel_duke_processesis renamed toparallel_processes— existing configs must update the key.powerplantmatching.dukeno longer resolve.Testing
test/test_linkage.py— 6 passed (format parity, identical-row matching, singlematch uniqueness, empty input, symmetric dedup pairs, geo proximity raises score)test/test_cleaning.py— 3 passed (real-dataaggregate_units→match()dedup path)ruff checkclean;reuse lintcompliant (used licenses: MIT, CC0-1.0, CC-BY-4.0)