手把手教你做關鍵詞匹配項目(搜尋引擎)---- 第二十天,教你做第二十天
客串:屌絲的坑人表單神器、資料庫那點事兒
物件導向升華:物件導向的認識----新生的初識、物件導向的番外----思想的夢遊篇(1)、物件導向的認識---如何找出類
負載平衡:負載平衡----概念認識篇、負載平衡----實現配置篇(Nginx)
吐槽:有人反饋了這樣的一個資訊,說該文章越到最後越難看懂,跟不上節奏,也有的人說小帥帥的能力怎麼飆的那麼快,是不是我比較蠢。也有的直接看文字,不看代碼,代碼太難懂了。
其實我這幾天也一直在思考這個問題,所以沒辦法就去開展了一些物件導向的課程,希望對那些跟不上的有些協助。其實說真的,讀者不反饋的話,我只好按照我認為的小帥帥去開展課程了。
第二十天
起點:手把手教你做關鍵詞匹配項目(搜尋引擎)---- 第一天
回顧:手把手教你做關鍵詞匹配項目(搜尋引擎)---- 第十九天
話說小帥帥為瞭解決那個分詞演算法寫出了初版,他拿給於老大看的時候,被要求重寫了。
原因有以下幾點:
1. 如何測試,測試資料呢?
2. Splitter是不是做了太多事情?
3. 連衣裙xxl裙連衣裙這種 有重複片語怎麼辦?
小帥帥拿著這些問題,開始重構。
首先他發現了這點,中文、英文和中英文的判斷,以及長度的計算,他把這個寫成了類:
phpclass UTF8 { /** * 檢測是否utf8 * @param $char * @return bool */ public static function is($char){ return (preg_match("/^([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}/",$char) || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}$/",$char) || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){2,}/",$char)); } /** * 計算utf8字的個數 * @param $char * @return float|int */ public static function length($char) { if(self::is($char)) return ceil(strlen($char)/3); return strlen($char); } /** * 檢測是否為片語 * @param $word * @return bool */ public static function isPhrase($word){ if(self::length($word)<=1) return false; return true; }}
小帥帥又考慮到詞典的來源有可能來自多個地方,比如我給的測試資料,這樣不就是可以解決於老大說到無法測試的問題了,小帥帥把詞典的來源抽成了個類,類如下:
phpclass DBSegmentation { public $cid; /** * 擷取類目下分詞的片語資料 * @return array */ public function transferDictionary(){ $ret = array(); $sql = "select word from category_linklist where cid='$this->cid'"; $words = DB::makeArray($sql); foreach($words as $strWords){ $words = explode(",",$strWords); foreach($words as $word){ if(UTF8::isPhrase($word)){ $ret[] = $word; } } } return $ret; }} class TestSegmentation { public function transferDictionary(){ $words = array( "連衣裙,連衣", "XXL,xxl,加大,加大碼", "X碼,中碼", "外套,衣,衣服,外衣,上衣", "女款,女士,女生,女性" ); $ret = array(); foreach($words as $strWords){ $words = explode(",",$strWords); foreach($words as $word){ if(UTF8::isPhrase($word)){ $ret[] = $word; } } } return $ret; }}
那麼Splitter 就專心分詞把,代碼如下:
class Splitter { public $keyword; private $dictionary = array(); public function setDictionary($dictionary = array()){ usort($dictionary,function($a,$b){ return (UTF8::length($a)>UTF8::length($b))?1:-1; }); $this->dictionary = $dictionary; } public function getDictionary(){ return $this->dictionary; } /** * 把關鍵詞拆分成片語或者單詞 * @return KeywordEntity $keywordEntity */ public function split(){ $remainKeyword = $this->keyword; $keywordEntity = new KeywordEntity($this->keyword); foreach($this->dictionary as $phrase){ $matchTimes = preg_match_all("/$phrase/",$remainKeyword,$matches); if($matchTimes>0){ $keywordEntity->addElement($phrase,$matchTimes); $remainKeyword = str_replace($phrase,"::",$remainKeyword); } } $remainKeywords = explode("::",$remainKeyword); foreach($remainKeywords as $splitWord){ if(!empty($splitWord)){ $keywordEntity->addElement($splitWord); } } return $keywordEntity; }}class KeywordEntity { public $keyword; public $elements = array(); public function __construct($keyword){ $this->keyword = $keyword; } public function addElement($word,$times=1){ if(isset($this->elements[$word])){ $this->elements[$word]->times += $times; }else $this->elements[] = new KeywordElement($word,$times); } /** * @desc 計算UTF8字串權重 * @param string $word * @return float */ public function calculateWeight($word) { $element = $this->elements[$word]; return ROUND(strlen($element->word)*$element->times / strlen($this->keyword), 3); }}class KeywordElement { public $word; public $times; public function __construct($word,$times){ $this->word = $word; $this->times = $times; }}
他把算權重的也丟給了一個類專門去處理。
小帥帥寫完之後,也順手寫了測試執行個體:
php$segmentation = new TestSegmentation();$splitter = new Splitter();$splitter->setDictionary($segmentation->transferDictionary());$splitter->keyword = "連衣裙xxl裙連衣裙";$keywordEntity = $splitter->split();var_dump($keywordEntity);
這樣就算你的演算法怎麼改,它也能從容面對了。
小帥帥理解了這個,當你覺得類做的事情太多的時候,可以考慮下單一職責原則。
單一職責原則:一個類,只有一個引起它變化的原因。應該只有一個職責。每一個職責都是變化的一個軸線,如果一個類有一個以上的職責,這些職責就耦合在了一起。這會導致脆弱的設計。當一個職責發生變化時,可能會影響其它的職責。另外,多個職責耦合在一起,會影響複用性。例如:要實現邏輯和介面的分離。【來自百度百科】
當於老大提到是不是有其他分詞演算法的時候,我們能不能拿來用,小帥帥很高興,因為現在它的代碼是多麼美好。
小帥帥如何玩轉第三方分詞擴充,請繼續關注下回分解:手把手教你做關鍵詞匹配項目(搜尋引擎)---- 第二十一天
http://www.bkjia.com/PHPjc/873919.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/873919.htmlTechArticle手把手教你做關鍵詞匹配項目(搜尋引擎)---- 第二十天,教你做第二十天 客串:屌絲的坑人表單神器、資料庫那點事兒 物件導向升華:面...