This commit is contained in:
@@ -448,6 +448,9 @@ def _has_bundle_offer(identity: ProductIdentity) -> bool:
|
||||
or "優惠套組" in text
|
||||
or "禮盒組" in text
|
||||
or "加大組" in text
|
||||
or "加量組" in text
|
||||
or "分享組" in text
|
||||
or "明星組" in text
|
||||
or "套組" in text
|
||||
)
|
||||
|
||||
@@ -461,6 +464,17 @@ def _has_multi_component(identity: ProductIdentity) -> bool:
|
||||
)
|
||||
|
||||
|
||||
def _has_refill_pack(identity: ProductIdentity) -> bool:
|
||||
text = identity.normalized_name
|
||||
return bool(
|
||||
"補充瓶" in text
|
||||
or "補充包" in text
|
||||
or "替換蕊" in text
|
||||
or "替換芯" in text
|
||||
or "refill" in text
|
||||
)
|
||||
|
||||
|
||||
def _spec_mention_count(identity: ProductIdentity) -> int:
|
||||
return len(re.findall(r"\d+(?:\.\d+)?\s*(?:ml|毫升|l|g|公克|kg)", identity.normalized_name, re.I))
|
||||
|
||||
@@ -488,6 +502,23 @@ def _chinese_bigram_score(left: ProductIdentity, right: ProductIdentity) -> floa
|
||||
return 2 * len(left_signature & right_signature) / (len(left_signature) + len(right_signature))
|
||||
|
||||
|
||||
def _has_strong_product_line_signal(
|
||||
left: ProductIdentity,
|
||||
right: ProductIdentity,
|
||||
token_score: float,
|
||||
chinese_name_score: float,
|
||||
) -> bool:
|
||||
shared_core = left.core_tokens & right.core_tokens
|
||||
shared_latin_or_model = {
|
||||
token for token in shared_core
|
||||
if re.fullmatch(r"[a-z][a-z0-9-]{3,}", token)
|
||||
or re.fullmatch(r"[a-z]{2,}-?\d+[a-z0-9-]*", token)
|
||||
}
|
||||
if shared_latin_or_model and token_score >= 0.50:
|
||||
return True
|
||||
return token_score >= 0.56 and chinese_name_score >= 0.45
|
||||
|
||||
|
||||
def score_marketplace_match(
|
||||
momo_name: str,
|
||||
competitor_name: str,
|
||||
@@ -525,6 +556,8 @@ def score_marketplace_match(
|
||||
reasons.append("bundle_offer_conflict")
|
||||
if _has_multi_component(left) != _has_multi_component(right):
|
||||
reasons.append("multi_component_conflict")
|
||||
if _has_refill_pack(left) != _has_refill_pack(right):
|
||||
reasons.append("refill_pack_conflict")
|
||||
left_spec_mentions = _spec_mention_count(left)
|
||||
right_spec_mentions = _spec_mention_count(right)
|
||||
if left_spec_mentions and right_spec_mentions and left_spec_mentions != right_spec_mentions:
|
||||
@@ -537,6 +570,8 @@ def score_marketplace_match(
|
||||
hard_veto = True
|
||||
if _has_multi_component(left) != _has_multi_component(right):
|
||||
hard_veto = True
|
||||
if _has_refill_pack(left) != _has_refill_pack(right):
|
||||
hard_veto = True
|
||||
if left_spec_mentions and right_spec_mentions and left_spec_mentions != right_spec_mentions:
|
||||
hard_veto = True
|
||||
if chinese_name_score < 0.16 and token_score < 0.72:
|
||||
@@ -568,6 +603,16 @@ def score_marketplace_match(
|
||||
|
||||
if token_score >= 0.72 and spec_score >= 0.82 and not brand_conflict:
|
||||
score += 0.08
|
||||
if (
|
||||
brand_score >= 0.95
|
||||
and not hard_veto
|
||||
and price_penalty == 0
|
||||
and type_score >= 0.55
|
||||
and spec_score >= 0.55
|
||||
and _has_strong_product_line_signal(left, right, token_score, chinese_name_score)
|
||||
):
|
||||
score += 0.07
|
||||
reasons.append("strong_product_line_match")
|
||||
if hard_veto:
|
||||
score = min(score, 0.32)
|
||||
score = max(0.0, min(1.0, score))
|
||||
|
||||
Reference in New Issue
Block a user