Improve sparse and structured catalog matching
This commit is contained in:
1 parent
2982161374
commit
42f8f07207
8 files changed
+739
-20
No files matched your search
@@ -44,10 +44,17 @@ def _load_message_cases() -> tuple[MessageCase, ...]:
|
||||
|
||||
|
||||
MESSAGE_CASES = _load_message_cases()
|
||||
VALIDATED_MESSAGE_CASES = tuple(
|
||||
case for case in MESSAGE_CASES if case.source == "messages.txt"
|
||||
)
|
||||
MORE_MESSAGE_CASES = tuple(
|
||||
case for case in MESSAGE_CASES if case.source == "more_messages.txt"
|
||||
)
|
||||
|
||||
# Baseline approved for the current corpus. The key is the message text so adding
|
||||
# or moving unrelated lines does not invalidate every expectation below.
|
||||
EXPECTED_RESULTS: dict[str, ExpectedResult] = {
|
||||
# Hand-reviewed acceptance results for every required messages.txt query.
|
||||
# Do not regenerate this table from CatalogMatcher output: it is the independent
|
||||
# oracle that should catch semantic regressions in the implementation.
|
||||
VALIDATED_MESSAGE_RESULTS: dict[str, ExpectedResult] = {
|
||||
"здравствуйте, есть саморезы гкл 3.5х25?": ("ambiguous", ("SAM-0063", "SAM-0061", "SAM-0062")),
|
||||
"дрель ударная prowerk pw-750 в наличии?": ("matched", ("INS-0008",)),
|
||||
"кабель шввп 2х0.5 сколько за метр": ("matched", ("KAB-0017",)),
|
||||
@@ -88,6 +95,11 @@ EXPECTED_RESULTS: dict[str, ExpectedResult] = {
|
||||
"где находится ваш магазин": ("not_found", ()),
|
||||
"статус заказа 4512 подскажите": ("not_found", ()),
|
||||
"спасибо, заказ получил, все отлично": ("not_found", ()),
|
||||
}
|
||||
|
||||
# The larger exploratory corpus is useful as a regression snapshot, but it is
|
||||
# intentionally kept separate from the hand-reviewed acceptance set above.
|
||||
MORE_MESSAGE_BASELINE_RESULTS: dict[str, ExpectedResult] = {
|
||||
"добрый день, саморезы по дереву 3.5х25 пачка 200 штук": ("matched", ("SAM-0001",)),
|
||||
"саморез гкл 3,5 на 25 кг": ("matched", ("SAM-0063",)),
|
||||
"нужны черные саморезы 4.2x75 упаковка 1000": ("matched", ("SAM-0023",)),
|
||||
@@ -106,7 +118,7 @@ EXPECTED_RESULTS: dict[str, ExpectedResult] = {
|
||||
"ШВВП 2 X 0,75, цена за метр?": ("matched", ("KAB-0018",)),
|
||||
"кабель кг 3х2,5": ("not_found", ()),
|
||||
"кабель для чайника": ("ambiguous", ("KAB-0004", "KAB-0005", "KAB-0008")),
|
||||
"3х1.5": ("not_found", ()),
|
||||
"3х1.5": ("ambiguous", ("KAB-0022", "KAB-0002", "KAB-0010")),
|
||||
"ввгнг 20х20": ("not_found", ()),
|
||||
"труба профильная 40x20x2": ("not_found", ()),
|
||||
"профтруба 60 40 3": ("ambiguous", ("TRB-0009", "TRB-0010", "TRB-0015")),
|
||||
@@ -115,7 +127,7 @@ EXPECTED_RESULTS: dict[str, ExpectedResult] = {
|
||||
"нужна труба длиной до луны": ("ambiguous", ("TRB-0003", "TRB-0007", "TRB-0008")),
|
||||
"гипсокартон 12,5 влагостойкий": ("matched", ("GKL-0003",)),
|
||||
"гкл обычный 9.5 мм": ("matched", ("GKL-0001",)),
|
||||
"лист гипса зеленый": ("not_found", ()),
|
||||
"лист гипса зеленый": ("ambiguous", ("GKL-0001", "GKL-0002", "GKL-0004")),
|
||||
"гипсокортан 12.5": ("ambiguous", ("GKL-0002", "GKL-0004", "GKL-0003")),
|
||||
"фанера 18 мм": ("not_found", ()),
|
||||
"дрель prowerk pw-750": ("matched", ("INS-0008",)),
|
||||
@@ -140,7 +152,7 @@ EXPECTED_RESULTS: dict[str, ExpectedResult] = {
|
||||
"насадка на шуруповерт": ("ambiguous", ("INS-0010", "INS-0011", "INS-0024")),
|
||||
"диск отрезной 125х1,0 металл": ("matched", ("DSK-0003",)),
|
||||
"круг по металлу 230 на 2.5": ("not_found", ()),
|
||||
"пильный диск 190x48t": ("ambiguous", ("DSK-0034", "DSK-0032", "DSK-0033")),
|
||||
"пильный диск 190x48t": ("matched", ("DSK-0034",)),
|
||||
"алмазный диск 125 бетон": ("ambiguous", ("DSK-0025", "DSK-0026", "DSK-0027")),
|
||||
"диск на болгарку": ("ambiguous", ("DSK-0011", "DSK-0012", "DSK-0013")),
|
||||
"круг квадратный 12х34": ("not_found", ()),
|
||||
@@ -189,8 +201,30 @@ EXPECTED_RESULTS: dict[str, ExpectedResult] = {
|
||||
"хочу всё и сразу за сто рублей": ("not_found", ()),
|
||||
"статус заказа 4512 и бур 8х160": ("matched", ("BIT-0077",)),
|
||||
"диск": ("ambiguous", ("DSK-0011", "DSK-0012", "DSK-0013")),
|
||||
"24 зуба": ("ambiguous", ("DSK-0029", "DSK-0032", "DSK-0035")),
|
||||
"210 мм 24 зуба": ("matched", ("DSK-0035",)),
|
||||
"125 мм": ("ambiguous", ("INS-0013", "DSK-0025", "RAS-0054")),
|
||||
"12 в": ("ambiguous", ("INS-0003", "INS-0010", "INS-0024")),
|
||||
"900 вт": ("ambiguous", ("INS-0009", "INS-0013")),
|
||||
"M10": ("ambiguous", ("KRP-0030", "KRP-0020", "KRP-0009")),
|
||||
"P120": ("ambiguous", ("DSK-0024", "RAS-0050", "RAS-0057")),
|
||||
"SDS-plus": ("ambiguous", ("BIT-0073", "INS-0012")),
|
||||
"PH2": ("ambiguous", ("BIT-0004", "RIN-0010")),
|
||||
"20x20x2": ("matched", ("TRB-0003",)),
|
||||
"ToolKraft 125 мм": ("matched", ("INS-0027",)),
|
||||
"99999 мм": ("not_found", ()),
|
||||
"аквариум 125 мм": ("not_found", ()),
|
||||
"удар": ("ambiguous", ("INS-0008", "INS-0009", "INS-0022")),
|
||||
"ударная": ("ambiguous", ("INS-0008", "INS-0009", "INS-0022")),
|
||||
"удар мощный": ("ambiguous", ("INS-0008", "INS-0009", "INS-0022")),
|
||||
"удар мощно 900 хромированый анус долбить": ("ambiguous", ("INS-0009", "INS-0016", "INS-0023")),
|
||||
"дрель удар мощно 900 хромированый анус долбить": ("ambiguous", ("INS-0009", "INS-0023", "INS-0002")),
|
||||
"анус": ("not_found", ()),
|
||||
"долбить": ("not_found", ()),
|
||||
}
|
||||
|
||||
EXPECTED_RESULTS = VALIDATED_MESSAGE_RESULTS | MORE_MESSAGE_BASELINE_RESULTS
|
||||
|
||||
|
||||
def test_message_files_are_present_and_have_expected_size() -> None:
|
||||
counts = {
|
||||
@@ -206,10 +240,15 @@ def test_message_files_are_present_and_have_expected_size() -> None:
|
||||
messages = [case.message for case in MESSAGE_CASES]
|
||||
assert len(messages) == len(set(messages)), "message texts must be unique"
|
||||
assert set(EXPECTED_RESULTS) == set(messages)
|
||||
assert set(VALIDATED_MESSAGE_RESULTS) == {
|
||||
case.message for case in MESSAGE_CASES if case.source == "messages.txt"
|
||||
}
|
||||
assert set(MORE_MESSAGE_BASELINE_RESULTS) == {
|
||||
case.message for case in MESSAGE_CASES if case.source == "more_messages.txt"
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", MESSAGE_CASES, ids=lambda case: case.id)
|
||||
def test_every_message_can_be_matched(
|
||||
def _assert_expected_result(
|
||||
matcher: CatalogMatcher, case: MessageCase
|
||||
) -> None:
|
||||
result = matcher.match(case.message)
|
||||
@@ -232,3 +271,19 @@ def test_every_message_can_be_matched(
|
||||
expected_status, expected_skus = EXPECTED_RESULTS[case.message]
|
||||
assert result.status == expected_status
|
||||
assert tuple(candidate.sku for candidate in result.candidates) == expected_skus
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"case", VALIDATED_MESSAGE_CASES, ids=lambda case: case.id
|
||||
)
|
||||
def test_validated_messages_txt_result(
|
||||
matcher: CatalogMatcher, case: MessageCase
|
||||
) -> None:
|
||||
_assert_expected_result(matcher, case)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", MORE_MESSAGE_CASES, ids=lambda case: case.id)
|
||||
def test_more_messages_regression(
|
||||
matcher: CatalogMatcher, case: MessageCase
|
||||
) -> None:
|
||||
_assert_expected_result(matcher, case)
|
||||
Reference in new issue
Block a user