Rezept-Zuordnung: ein Eigenschaftswort frisst keinen Artikelnamen mehr

Gefunden bei der Probe, ob ein Embedding-Modell die Zuordnung besser
hinbekommt: Die Sperrliste der Eigenschaftswoerter lief als eine einzige
Liste mit Praefix-Vergleich. "Frischkaese" fing mit "frisch" an, galt
damit als blosse Eigenschaft und fiel aus dem Vergleich - die Zutat
"Kaese" fand den Frischkaese deshalb NIE. Ebenso "Biomilch" (bio),
"Rohrzucker" (roh), "Kleingebaeck" (klein), "Ganzkornbrot" (ganz),
"Grobgriess" (grob).

Unsichtbar, weil kein falscher Treffer entstand, sondern ein richtiger
ausblieb - die Zutat stand einfach als "nicht zugeordnet" da.

Jetzt zwei Toepfe statt einem. Stammformen wie "getrock" oder "vegan"
vergleichen weiter ueber den Wortanfang, weil Deutsch beugt und diese
Stuecke keine Lebensmittelnamen anfangen. Kurze Alltagswoerter wie
"frisch", "bio", "roh", "klein" zaehlen nur noch als Eigenschaft, wenn
hoechstens eine Beugungsendung dranhaengt: "frische" ja, "frischkase"
nein.

Gegenprobe im Test: "frische Hefe" findet die "Frischen Kraeuter"
weiterhin nicht - die Sperre ist praeziser geworden, nicht schwaecher.

7 neue Tests, Suite bei 494.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-02 14:01:56 +02:00
co-authored by Claude Opus 5
parent 8072e7f566
commit fe6327c913
2 changed files with 80 additions and 11 deletions
+38 -11
View File
@@ -145,29 +145,56 @@ def _stamm(text: str) -> str:
# „veganer Lime Curd" auf „Vegane Mühlen-Schnitzel". Geteilt wird dort nur die
# Eigenschaft, nicht die Sache.
#
# Als Wortanfänge aufgeführt, weil Deutsch beugt: „vegan", „vegane", „veganer",
# „veganes" sollen alle gemeint sein. Verglichen wird gegen die zusammengezogene
# Form aus ``_stamm`` (ae/oe/ue schon aufgelöst).
_NUR_EIGENSCHAFT = (
"vegan", "vegetar", "bio", "biologisch", "frisch", "roh",
# Verglichen wird gegen die zusammengezogene Form aus ``_stamm`` (ae/oe/ue schon
# aufgelöst) - die Listen unten stehen deshalb ebenfalls in dieser Form.
#
# Zwei Toepfe, weil es zwei Sorten Wort sind. Die Trennung ist nicht Kosmetik:
# Als EINE Liste mit Praefix-Vergleich hat sie ganze Artikelnamen verschluckt.
# 'Frischkaese' begann mit 'frisch', galt damit als blosse Eigenschaft und fiel
# aus dem Vergleich - die Zutat 'Kaese' fand den Frischkaese deshalb NIE. Ebenso
# 'Biomilch' (bio), 'Rohrzucker' (roh), 'Kleingebaeck' (klein), 'Ganzkornbrot'
# (ganz). Der Fehler war unsichtbar: kein falscher Treffer, nur ausbleibende
# richtige.
#
# 1. Stammformen, die in JEDER Beugung gemeint sind. Praefix-Vergleich, weil
# Deutsch beugt: 'getrock' deckt getrocknet/getrocknete/getrocknetes ab.
# Diese Stuecke fangen keine Komposita an, die ein Lebensmittel benennen.
_EIGENSCHAFT_STAMM = (
"vegan", "vegetar", "biologisch",
"gekocht", "gebacken", "geschmolz", "gesalz", "ungesalz", "gezuckert",
"getrock", "gefror", "gerieb", "gewurf", "geschnitt", "geschal", "gehackt",
"gemahl", "gepresst", "zimmertemperatur", "lauwarm",
"klein", "gross", "mittel", "fein", "grob", "ganz",
"oder", "sowie", "etwa", "circa", "nach", "ohne", "optional", "evtl",
"block", "stueck", "stuck", "gehauft", "gestrich",
"gemahl", "gepresst", "zimmertemperatur", "lauwarm", "gehauft", "gestrich",
"optional",
)
# 2. Kurze Alltagswoerter, die AUCH am Anfang echter Namen stehen. Hier zaehlt
# nur das Wort selbst, hoechstens mit einer Beugungsendung dran: 'frische'
# ja, 'frischkase' nein.
_EIGENSCHAFT_WORT = (
"bio", "frisch", "roh", "klein", "gross", "mittel", "fein", "grob", "ganz",
"oder", "sowie", "etwa", "circa", "nach", "ohne", "evtl",
"block", "stueck", "stuck",
)
# Deutsche Beugungsendungen. Was laenger ist, ist keine Endung mehr, sondern ein
# zweites Wort - und genau das soll den Namen retten.
_BEUGUNG = ("", "e", "er", "es", "en", "em", "ene", "enes", "ener", "enen")
def _nur_eigenschaft(wort: str) -> bool:
return wort.isdigit() or wort.startswith(_NUR_EIGENSCHAFT)
if wort.isdigit() or wort.startswith(_EIGENSCHAFT_STAMM):
return True
return any(
wort.startswith(w) and wort[len(w):] in _BEUGUNG
for w in _EIGENSCHAFT_WORT
)
def _woerter(text: str) -> list[str]:
"""Bedeutungstragende Wörter einer Zutat.
Weg fallen sehr kurze („1 TL"), reine Zahlen und alles, was die Zutat nur
beschreibt (siehe ``_NUR_EIGENSCHAFT``). Übrig bleibt, was sie IST: „Mehl",
beschreibt (siehe ``_nur_eigenschaft``). Übrig bleibt, was sie IST: „Mehl",
„Apfel", „Butter", „Joghurt".
"""
return [
+42
View File
@@ -372,6 +372,48 @@ def test_umlaut_und_mehrzahl_finden_sich(db):
assert zutat.status == "vorhanden"
def test_eigenschaftswort_verschluckt_den_artikelnamen_nicht(db):
'''Der Fund aus der Modellprobe: 'Frischkaese' fing mit 'frisch' an.
Damit galt der ganze Name als blosse Eigenschaft, fiel aus dem Vergleich -
und die Zutat 'Kaese' fand den Frischkaese NIE. Unsichtbar, weil kein
falscher Treffer entstand, sondern ein richtiger ausblieb.
'''
cat = _kategorie(db, "Molkerei")
kaese = _artikel(db, "Frischkäse", cat, bestand=400)
[zutat] = pruefe_zutaten(db, [_zutat("Käse", 100, "g")])
assert zutat.ziel_id == kaese.id
assert zutat.status == "vorhanden"
@pytest.mark.parametrize("artikel,zutat_name", [
("Biomilch", "Milch"),
("Rohrzucker", "Zucker"),
("Kleingebäck", "Gebäck"),
("Ganzkornbrot", "Brot"),
("Grobgrieß", "Grieß"),
])
def test_komposita_mit_eigenschaft_am_anfang_bleiben_auffindbar(db, artikel, zutat_name):
cat = _kategorie(db, "Vorrat")
ziel = _artikel(db, artikel, cat, bestand=1000)
[zutat] = pruefe_zutaten(db, [_zutat(zutat_name, 100, "g")])
assert zutat.ziel_id == ziel.id
def test_das_eigenschaftswort_selbst_begruendet_weiter_keinen_treffer(db):
"""Die Gegenprobe – sonst waere die Sperre bloss ausgehebelt."""
cat = _kategorie(db, "Kuehlregal")
_artikel(db, "Frische Kräuter", cat, bestand=100)
[zutat] = pruefe_zutaten(db, [_zutat("frische Hefe", 20, "g")])
assert zutat.status == "kein_treffer"
def test_vollmilch_findet_die_h_vollmilch(db):
cat = _kategorie(db, "Molkerei")
milch = _artikel(db, "H Vollmilch", cat, base=BaseUnit.milliliter, bestand=1000)