From 4e1043897db3b706c2dc0fba4ae5f6ff9cfd7de3 Mon Sep 17 00:00:00 2001 From: Thomas Hackner Date: Tue, 7 Jul 2026 07:25:04 +0000 Subject: [PATCH] Blacklist: Firmen schreibweisen-robust matchen (eine Firma nur einmal) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sameCompany() vergleicht Firmen-Slugs jetzt per Gleichheit ODER führendem Bindestrich-Präfix (>=2 Tokens), sodass Kurzname und voller Firmenname derselben Firma als gleich gelten (z. B. "it-problemloeser" = "it-problemloeser-verwaltungs-und-handels", "stadtwerke-essen" = "stadtwerke-essen-netz"). firmaMatch() nutzt das für die Blacklist-Typen firma/firma_stelle/auto. Distinkte Firmen mit nur gleichem ersten Wort ("meyer-it" vs "meyer-logistik") bleiben getrennt. Co-Authored-By: Claude Opus 4.8 --- lib/blacklist.js | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/blacklist.js b/lib/blacklist.js index 7b127bd..fefc72e 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -107,6 +107,27 @@ function firmaSlug(s) { return (kept.length ? kept : words).join('-'); } +// Do two company slugs refer to the SAME employer? True when they are equal, or +// when the shorter one's hyphen tokens are a leading prefix of the longer one's. +// The prefix rule collapses "short name" vs "full legal name" spellings of one +// firm — e.g. "it-problemloeser" vs "it-problemloeser-verwaltungs-und-handels", +// or "stadtwerke-essen" vs "stadtwerke-essen-netz". To avoid merging distinct +// firms that merely share a first word ("meyer-it" vs "meyer-logistik"), a pure +// prefix match requires the shorter slug to carry at least two tokens; a +// single-token slug only matches an identical one. +function sameCompany(a, b) { + if (!a || !b) return false; + if (a === b) return true; + const ta = String(a).split('-').filter(Boolean); + const tb = String(b).split('-').filter(Boolean); + const [short, long] = ta.length <= tb.length ? [ta, tb] : [tb, ta]; + if (short.length < 2) return false; // single distinctive token → exact only + for (let i = 0; i < short.length; i++) { + if (short[i] !== long[i]) return false; + } + return true; +} + // Normalise a company / job-title string for fuzzy identity matching: // unescape, lowercase, drop gender markers like "(m/w/d)", collapse anything // non-alphanumeric to single spaces. @@ -138,10 +159,12 @@ function offerSignature(offer) { }; } -// Company identity match: prefer the robust slug, fall back to firma_norm for -// legacy rows written before firma_slug existed (or not yet backfilled). +// Company identity match: prefer the robust slug (equal or prefix — see +// sameCompany, which absorbs spelling / legal-form / umlaut variants of one +// employer), fall back to firma_norm for legacy rows written before firma_slug +// existed (or not yet backfilled). function firmaMatch(row, sig) { - if (row.firma_slug && sig.firma_slug) return row.firma_slug === sig.firma_slug; + if (row.firma_slug && sig.firma_slug) return sameCompany(row.firma_slug, sig.firma_slug); return !!row.firma_norm && row.firma_norm === sig.firma_norm; } @@ -259,6 +282,7 @@ module.exports = { urlDomain, normText, firmaSlug, + sameCompany, offerSignature, rowMatches, matchBlacklist,