系列第十七天,繼黑名單後攻克「近義詞/同義詞」模組。面對「同一類目下,不同屬性值對應不同近義詞群」的業務複雜度,設計 category_linklist 表結構、實作 LinklistCharListHandle 策略類、擴展 SelectorItem::getProperties() 介面,完成屬性粒度的近義詞展開。
女裝類目:
- 尺碼:XXL, 加大, 加大碼
- 品類:外套, 衣, 衣服, 外衣, 上衣
- 性別:女款, 女士, 女生, 女性
需求:商品屬性若包含群組內任一詞,自動展開為整組詞,提升搜尋召回率。
CREATE TABLE `category_linklist` (
`cid` BIGINT(20) DEFAULT NULL COMMENT '類目ID',
`catmatch` VARCHAR(50) DEFAULT NULL COMMENT '類目名稱',
`word` VARCHAR(255) DEFAULT NULL COMMENT '近義詞群,逗號分隔',
`created` DATETIME DEFAULT NULL COMMENT '錄入時間'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO category_linklist (cid, catmatch, word) VALUES
("50010850", "女裝", "XXL,加大,加大碼"),
("50010850", "女裝", "外套,衣,衣服,外衣,上衣"),
("50010850", "女裝", "女款,女士,女生,女性");
<?php
class SelectorItem {
// ... 既有代碼 ...
/** 回傳屬性物件陣列:[{id, fieldId, name, value}, ...] */
public function getProperties() {
$result = [];
$props = explode(';', $this->item->props_name); // 如 "1:2:尺碼:XXL;3:4:顏色:紅"
foreach ($props as $propStr) {
$result[] = self::createItemProperty(explode(':', $propStr));
}
return $result;
}
public static function createItemProperty($arr) {
$obj = new stdClass();
$obj->id = $arr[0];
$obj->fieldId = $arr[1];
$obj->name = $arr[2];
$obj->value = $arr[3];
return $obj;
}
}
?>
LinklistCharListHandle<?php
class LinklistCharListHandle extends CharListHandle {
public function exec() {
$sql = "SELECT word FROM category_linklist WHERE cid='{$this->selectorItem->cid}'";
$linklist = DB::makeArray($sql); // [{word: "XXL,加大,加大碼"}, ...]
foreach ($linklist as $row) {
$groupWords = explode(',', $row['word']); // 近義詞群
// 遍歷商品所有屬性
foreach ($this->selectorItem->getProperties() as $prop) {
// 1. 先將原屬性值加入核心詞
$this->charlist->addCore($prop->value);
// 2. 若屬性值命中某群組,展開整群
if (in_array($prop->value, $groupWords)) {
foreach ($groupWords as $w) {
$this->charlist->addCore($w);
}
}
}
}
}
}
?>
<?php
class Selector {
private static $charListHandle = [
"黑名單" => "BacklistCharListHandle",
"近義詞" => "LinklistCharListHandle", // 新增
];
// ... 其餘不變
}
?>
小帥帥自以為完美,於老大卻直接退回。核心問題預告:
foreach + in_array,屬性數 × 群組數 × 群組大小,資料量大時極慢。addCore($prop->value) 在內層迴圈重複呼叫,產生大量重複核心詞。下一回將揭曉於老大的優化方案:倒排索引、預計算、緩存策略與領域模型重構。
近義詞看似簡單的「多值映射」,實則考驗資料結構設計、演算法效能與領域建模能力。本回完成 MVP 實作,暴露出 naïvely 實作的典型問題,為後續架構升級鋪墊。