v1.8.3: OV-matchfilter weert gewone-woord-botsingen (breng/overweg/sein/opwaarderen)
'NOS | Oldambt weigert Leninbeeld' kwam door het filter via het werkwoord 'breng je het gesprek op gang' (familie vervoerders, gewicht 3). Audit over 30 dagen productiedata toonde dezelfde klasse: 'sein brandmeester' (brandweer) 3x, 'overwegen' (werkwoord) 2x, idioom 'overweg kunnen' 1x. - breng/overweg/overwegen/sein/opwaarderen van sterk(3)/medium(2) naar zwak(1): dubbelzinnige woorden combineren nu met een ander OV-woord (bushalte/trein/spoor/NS blijven gewoon scoren) - _filter_passes eist sindsdien: alleen zwakke hits -> minimaal twee verschillende families (zelfde zwakke familie in titel+samenvatting is geen combinatie); voorkomt 'overwegen' in beide velden alsnog doorlaten - trein-familie matst nu ook samenstellingen (stoptrein/goederentrein/ sprinttrein) zodat overweg-demotie geen echte spoorincidenten verliest - blacklist + stationair/stationeren/stationeel (geen OV-waarde, matchen wel via \bstation\w*\b) - docs: module-commentaar en _filter_summary/_filter_passes bijgewerkt Verificatie: exacte storingscode-herhaling op de gemelde NOS-entry (nu gefilterd), 12 echte 30-dagen-entries (9 FP's eruit, 3 echte OV-berichten blijven), 10/10 echte OV-regressiegevallen doorlaten, 11/11 FP-vormen geweerd.
This commit is contained in:
parent
f4ea969f33
commit
eab249ea57
2 changed files with 47 additions and 21 deletions
|
|
@ -55,31 +55,41 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT
|
||||||
# Gewicht 3 (sterk, onmiskenbaar OV): één woord in titel óf samenvatting volstaat.
|
# Gewicht 3 (sterk, onmiskenbaar OV): één woord in titel óf samenvatting volstaat.
|
||||||
# Gewicht 2 (medium): één woord in de titel volstaat; in de samenvatting moet er
|
# Gewicht 2 (medium): één woord in de titel volstaat; in de samenvatting moet er
|
||||||
# een tweede OV-woord bijkomen.
|
# een tweede OV-woord bijkomen.
|
||||||
# Gewicht 1 (zwak/dubbelzinnig: los "bus", "kaartje", "rails"): moet met een ander
|
# Gewicht 1 (zwak/dubbelzinnig: los "bus", "breng", "overweg", "overwegen", "sein",
|
||||||
# OV-woord combineren. Weert zo "VW-bus"/"schoolbus", "weer op de rails" en
|
# "kaartje", "opwaarderen", "rails"): moet met een ander OV-woord combineren (een
|
||||||
# 112-berichten met "bussen rijden om" in de lead, zonder eenduidige
|
# tweede, andere familie — dezelfde zwakke familie in titel én samenvatting telt
|
||||||
# bushalte/overweg/NS/trein-berichten te raken.
|
# niet als combinatie). Weert zo "VW-bus"/"schoolbus", "weer op de rails", het
|
||||||
|
# werkwoord "brengen" ("hoe breng je ... in beeld"), het idioom "goed met elkaar
|
||||||
|
# overweg kunnen", het werkwoord "overwegen" ("gratieverlening overwegen"), het
|
||||||
|
# werkwoord "opwaarderen" ("een wijk opwaarderen") en brandweerjargon
|
||||||
|
# ("sein brandmeester"), zonder eenduidige bushalte/overweg/NS/trein-berichten
|
||||||
|
# te raken.
|
||||||
# MATCH_FILTER_BLACKLIST: gematchte woorden die tóch geen OV-waarde hebben (o.a.
|
# MATCH_FILTER_BLACKLIST: gematchte woorden die tóch geen OV-waarde hebben (o.a.
|
||||||
# straatnamen rond stations — "de Stationsstraat afsluiten voor een festival"
|
# straatnamen rond stations — "de Stationsstraat afsluiten voor een festival"
|
||||||
# is geen OV-nieuws). Zwartgelijste woorden leveren geen score op, maar
|
# is geen OV-nieuws). Zwartgelijste woorden leveren geen score op, maar
|
||||||
# blokkeren de familie niet: een écht "station"-woord ernaast scoort gewoon.
|
# blokkeren de familie niet: een écht "station"-woord ernaast scoort gewoon.
|
||||||
MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [
|
MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [
|
||||||
# sterk (3)
|
# sterk (3)
|
||||||
(r"\b(?:ns|arriva|qbuzz|connexxion|cxx|transdev|keolis|ret|gvb|ebs|htm|syntus|breng|u-ov|allgo|flixbus|blauwnet|r-net|valleilijn|waterbus|eurostar|thalys|randstadrail|gvu|ov)\b", 3), # vervoerders
|
(r"\b(?:ns|arriva|qbuzz|connexxion|cxx|transdev|keolis|ret|gvb|ebs|htm|syntus|u-ov|allgo|flixbus|blauwnet|r-net|valleilijn|waterbus|eurostar|thalys|randstadrail|gvu|ov)\b", 3), # vervoerders ('Breng' staat in de zwakke groep: botst met het werkwoord "brengen")
|
||||||
(r"\b(?:spoorweg|spoorbaan|spoorlijn|spoorverkeer|spoorwegovergang|spoorstoring|perron|perrons|overweg|overwegen|seinstoring|wisselstoring|sein|ontsporing|ontspoord|spoorstaking)\b", 3), # spoorinfra
|
(r"\b(?:spoorweg|spoorbaan|spoorlijn|spoorverkeer|spoorwegovergang|spoorstoring|perron|perrons|seinstoring|wisselstoring|ontsporing|ontspoord|spoorstaking)\b", 3), # spoorinfra ('overweg', 'overwegen' en 'sein' in de zwakke groep: botsen met idioom/werkwoord resp. brandweerjargon)
|
||||||
(r"\bstation\w*\b", 3), # station(s)
|
(r"\bstation\w*\b", 3), # station(s)
|
||||||
(r"\b(?:bus|tram|metro)(?:halte|haltes|lijn|lijnen|station|stations|verkeer|net|staking)\b", 3), # voertuig-samenstelling
|
(r"\b(?:bus|tram|metro)(?:halte|haltes|lijn|lijnen|station|stations|verkeer|net|staking)\b", 3), # voertuig-samenstelling
|
||||||
(r"\btrein\w*\b", 3), # trein(verkeer/staking/ongeluk/...)
|
(r"\b\w*trein\w*\b", 3), # trein(verkeer/staking/…), ook samenstellingen: stoptrein, goederentrein, sprinttrein
|
||||||
# medium (2)
|
# medium (2)
|
||||||
(r"\btram\b", 2),
|
(r"\btram\b", 2),
|
||||||
(r"\bmetro\b", 2),
|
(r"\bmetro\b", 2),
|
||||||
(r"\b(?:openbaar vervoer|dienstregeling|inchecken|uitchecken|lightrail|pendelbus|shuttlebus)\b", 2),
|
(r"\b(?:openbaar vervoer|dienstregeling|inchecken|uitchecken|lightrail|pendelbus|shuttlebus)\b", 2),
|
||||||
(r"\b(?:ov-chipkaart|chipkaart|ovpay|ov-pay|reisproduct|studentenreisproduct|vervoersbewijs|vervoerbewijs|opwaarderen)\b", 2),
|
(r"\b(?:ov-chipkaart|chipkaart|ovpay|ov-pay|reisproduct|studentenreisproduct|vervoersbewijs|vervoerbewijs)\b", 2),
|
||||||
(r"\b(?:ov-staking|conducteursstaking)\b", 2),
|
(r"\b(?:ov-staking|conducteursstaking)\b", 2),
|
||||||
(r"\b(?:pont|ponten)\b", 2), # waterbus/veerdienst
|
(r"\b(?:pont|ponten)\b", 2), # waterbus/veerdienst
|
||||||
# zwak (1) — dubbelzinnig, moet combineren
|
# zwak (1) — dubbelzinnig, moet combineren
|
||||||
(r"\bbus(?:sen)?\b", 1),
|
(r"\bbus(?:sen)?\b", 1),
|
||||||
|
(r"\bbreng\b", 1), # vervoerder Breng vs werkwoord "brengen" ("hoe breng je ... in beeld")
|
||||||
|
(r"\boverweg\b", 1), # spoorwegovergang vs idioom "goed met elkaar overweg kunnen"
|
||||||
|
(r"\boverwegen\b", 1), # meervoud van overweg vs werkwoord ("een gratieverlening overwegen")
|
||||||
|
(r"\bsein\b", 1), # spoorsein vs brandweerjargon ("sein brandmeester") en figuurlijk gebruik
|
||||||
(r"\bkaart(?:je|jes)\b", 1),
|
(r"\bkaart(?:je|jes)\b", 1),
|
||||||
|
(r"\bopwaarderen\b", 1), # ov-chipkaart opladen vs werkwoord "een wijk/park opwaarderen"
|
||||||
(r"\brails\b", 1),
|
(r"\brails\b", 1),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -98,6 +108,10 @@ MATCH_FILTER_BLACKLIST: frozenset[str] = frozenset({
|
||||||
"stationssteeg", "stationswal", "stationsbuurt", "stationswijk", "stationspark",
|
"stationssteeg", "stationswal", "stationsbuurt", "stationswijk", "stationspark",
|
||||||
# Idem voor "\btrein\w*\b".
|
# Idem voor "\btrein\w*\b".
|
||||||
"treinstraat", "treinweg",
|
"treinstraat", "treinweg",
|
||||||
|
# Idem voor "\bstation\w*\b": werkwoords-/bijvoeglijke vormen zonder OV-waarde
|
||||||
|
# ("motor stationair laten draaien", "auto's hier stationeren").
|
||||||
|
"stationair", "stationeel", "stationeren", "stationeert", "stationeerde",
|
||||||
|
"stationeerden", "stationerend",
|
||||||
})
|
})
|
||||||
|
|
||||||
_compiled_match_families: list[tuple[re.Pattern, int]] = [
|
_compiled_match_families: list[tuple[re.Pattern, int]] = [
|
||||||
|
|
@ -219,20 +233,20 @@ class RSSBot(Plugin):
|
||||||
self.log.exception("Fatal error while polling feeds")
|
self.log.exception("Fatal error while polling feeds")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _fam_score(text: str) -> int:
|
def _fam_hits(text: str) -> list[tuple[int, int]]:
|
||||||
"""Som van gewichten over de OV-families die in text voorkomen (1× per familie).
|
"""(familie-index, gewicht) voor elke OV-familie die in text voorkomt (1× per familie).
|
||||||
|
|
||||||
Gematchte woorden uit MATCH_FILTER_BLACKLIST (o.a. 'stationsstraat')
|
Gematchte woorden uit MATCH_FILTER_BLACKLIST (o.a. 'stationsstraat')
|
||||||
tellen niet mee en blokkeren de familie niet: een écht OV-woord in
|
tellen niet mee en blokkeren de familie niet: een écht OV-woord in
|
||||||
dezelfde tekst scoort gewoon verder."""
|
dezelfde tekst scoort gewoon verder."""
|
||||||
total = 0
|
hits: list[tuple[int, int]] = []
|
||||||
for family, weight in _compiled_match_families:
|
for idx, (family, weight) in enumerate(_compiled_match_families):
|
||||||
for m in family.finditer(text):
|
for m in family.finditer(text):
|
||||||
if m.group(0).lower() in MATCH_FILTER_BLACKLIST:
|
if m.group(0).lower() in MATCH_FILTER_BLACKLIST:
|
||||||
continue
|
continue
|
||||||
total += weight
|
hits.append((idx, weight))
|
||||||
break
|
break
|
||||||
return total
|
return hits
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _filter_passes(title: str, summary: str) -> bool:
|
def _filter_passes(title: str, summary: str) -> bool:
|
||||||
|
|
@ -240,22 +254,34 @@ class RSSBot(Plugin):
|
||||||
|
|
||||||
Sterke families (gewicht 3) halen de drempel al met één woord in titel óf
|
Sterke families (gewicht 3) halen de drempel al met één woord in titel óf
|
||||||
samenvatting. Medium (2) in de titel ook; in de samenvatting moet een tweede
|
samenvatting. Medium (2) in de titel ook; in de samenvatting moet een tweede
|
||||||
OV-woord bijkomen. Zwakke woorden (losse 'bus', 'kaartje', 'rails') moeten
|
OV-woord bijkomen. Zwakke woorden (losse 'bus', 'breng', 'overweg', 'overwegen',
|
||||||
combineren met een ander OV-woord. Weert oa 'VW-bus', 'schoolbus',
|
'sein', 'opwaarderen', 'kaartje', 'rails') moeten combineren met een ander
|
||||||
'bussen rijden om' in een woningbrand-lead en figuratief 'weer op de rails'.
|
OV-woord; dezelfde zwakke familie in titel én samenvatting is géén combinatie.
|
||||||
|
Weert oa 'VW-bus', 'schoolbus', 'bussen rijden om' in een woningbrand-lead,
|
||||||
|
het werkwoord 'brengen', het idioom 'goed met elkaar overweg kunnen',
|
||||||
|
'een wijk opwaarderen', brandweerjargon 'sein brandmeester' en figuratief
|
||||||
|
'weer op de rails'.
|
||||||
Bewust doorgelaten: krant 'De Metro'/café 'De Tram' in de titel (medium)."""
|
Bewust doorgelaten: krant 'De Metro'/café 'De Tram' in de titel (medium)."""
|
||||||
return 2 * RSSBot._fam_score(title) + RSSBot._fam_score(summary) >= MATCH_FILTER_THRESHOLD
|
t_hits = RSSBot._fam_hits(title)
|
||||||
|
s_hits = RSSBot._fam_hits(summary)
|
||||||
|
score = 2 * sum(w for _, w in t_hits) + sum(w for _, w in s_hits)
|
||||||
|
if score < MATCH_FILTER_THRESHOLD:
|
||||||
|
return False
|
||||||
|
# Alleen zwakke families? Dan moet een tweede (verschillende) familie meetellen.
|
||||||
|
if max(w for _, w in t_hits + s_hits) == 1 and len({i for i, _ in t_hits + s_hits}) < 2:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _filter_summary() -> str:
|
def _filter_summary() -> str:
|
||||||
"""Mensvriendelijke weergave van het vaste gewogen match-filter."""
|
"""Mensvriendelijke weergave van het vaste gewogen match-filter."""
|
||||||
return (
|
return (
|
||||||
"**OV-matchfilter (vast in code, gewogen families):**\n"
|
"**OV-matchfilter (vast in code, gewogen families):**\n"
|
||||||
"- Sterk (3): vervoerders (NS, Arriva, Qbuzz, ...), spoorinfra (perron, overweg, sein), "
|
"- Sterk (3): vervoerders (NS, Arriva, Qbuzz, ...), spoorinfra (perron, spoorwegovergang, seinstoring), "
|
||||||
"station(s), bushalte/buslijn/treinstel, trein\n"
|
"station(s), bushalte/buslijn/treinstel, trein\n"
|
||||||
"- Medium (2): tram, metro, openbaar vervoer/dienstregeling/inchecken, "
|
"- Medium (2): tram, metro, openbaar vervoer/dienstregeling/inchecken, "
|
||||||
"ov-chipkaart/ovpay/reisproduct, ov-staking, pont\n"
|
"ov-chipkaart/ovpay/reisproduct, ov-staking, pont\n"
|
||||||
"- Zwak (1): losse 'bus', 'kaartje', 'rails' — moet combineren met een ander OV-woord\n\n"
|
"- Zwak (1): losse 'bus', 'breng', 'overweg', 'overwegen', 'sein', 'kaartje', 'opwaarderen', 'rails' — moet combineren met een ander OV-woord\n\n"
|
||||||
"Uitgesloten (blacklist): woorden die wél matchen maar geen OV-waarde hebben, "
|
"Uitgesloten (blacklist): woorden die wél matchen maar geen OV-waarde hebben, "
|
||||||
"o.a. straatnamen rond stations ('stationsstraat', 'stationsweg', ...)\n\n"
|
"o.a. straatnamen rond stations ('stationsstraat', 'stationsweg', ...)\n\n"
|
||||||
"Doorlaten: `2×(titel-score) + 1×(samenvatting-score) ≥ 3`"
|
"Doorlaten: `2×(titel-score) + 1×(samenvatting-score) ≥ 3`"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
id: nl.eddydevink.rss
|
id: nl.eddydevink.rss
|
||||||
version: 1.8.2
|
version: 1.8.3
|
||||||
modules:
|
modules:
|
||||||
- buzzrss
|
- buzzrss
|
||||||
main_class: RSSBot
|
main_class: RSSBot
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue