目錄
手把手教你做关键词匹配项目(搜索引擎)---- 第二十天,教你做第二十天
首頁 php教程 php手册 手把手教你做关键词匹配项目(搜索引擎)---- 第二十天,教你做第二十天

手把手教你做关键词匹配项目(搜索引擎)---- 第二十天,教你做第二十天

Jun 13, 2016 am 09:25 AM
- 關鍵字 匹配 手把手 搜尋引擎 教你 專案

手把手教你做关键词匹配项目(搜索引擎)---- 第二十天,教你做第二十天

客串:屌丝的坑人表单神器、数据库那点事儿

面向对象升华:面向对象的认识----新生的初识、面向对象的番外----思想的梦游篇(1)、面向对象的认识---如何找出类

负载均衡:负载均衡----概念认识篇、负载均衡----实现配置篇(Nginx)

吐槽:有人反馈了这样的一个信息,说该文章越到最后越难看懂,跟不上节奏,也有的人说小帅帅的能力怎么飙的那么快,是不是我比较蠢。也有的直接看文字,不看代码,代码太难懂了。

其实我这几天也一直在思考这个问题,所以没办法就去开展了一些面向对象的课程,希望对那些跟不上的有些帮助。其实说真的,读者不反馈的话,我只好按照我认为的小帅帅去开展课程了。

 

第二十天

起点:手把手教你做关键词匹配项目(搜索引擎)---- 第一天

回顾:手把手教你做关键词匹配项目(搜索引擎)---- 第十九天

话说小帅帅为了解决那个分词算法写出了初版,他拿给于老大看的时候,被要求重写了。

原因有以下几点:

    1. 如何测试,测试数据呢?

    2. Splitter是不是做了太多事情?

    3. 连衣裙xxl裙连衣裙这种 有重复词组怎么办?

小帅帅拿着这些问题,开始重构。

首先他发现了这点,中文、英文和中英文的判断,以及长度的计算,他把这个写成了类:

<?<span>php

</span><span>class</span><span> UTF8 {

    </span><span>/*</span><span>*
     * 检测是否utf8
     * @param $char
     * @return bool
     </span><span>*/</span>
    <span>public</span> <span>static</span> <span>function</span> is(<span>$char</span><span>){
        </span><span>return</span> (<span>preg_match</span>("/^([".<span>chr</span>(228)."-".<span>chr</span>(233)."]{1}[".<span>chr</span>(128)."-".<span>chr</span>(191)."]{1}[".<span>chr</span>(128)."-".<span>chr</span>(191)."]{1}){1}/",<span>$char</span>) ||
            <span>preg_match</span>("/([".<span>chr</span>(228)."-".<span>chr</span>(233)."]{1}[".<span>chr</span>(128)."-".<span>chr</span>(191)."]{1}[".<span>chr</span>(128)."-".<span>chr</span>(191)."]{1}){1}$/",<span>$char</span>) ||
            <span>preg_match</span>("/([".<span>chr</span>(228)."-".<span>chr</span>(233)."]{1}[".<span>chr</span>(128)."-".<span>chr</span>(191)."]{1}[".<span>chr</span>(128)."-".<span>chr</span>(191)."]{1}){2,}/",<span>$char</span><span>));
    }

    </span><span>/*</span><span>*
     * 计算utf8字的个数
     * @param $char
     * @return float|int
     </span><span>*/</span>
    <span>public</span> <span>static</span> <span>function</span> length(<span>$char</span><span>) {

        </span><span>if</span>(self::is(<span>$char</span><span>))
            </span><span>return</span> <span>ceil</span>(<span>strlen</span>(<span>$char</span>)/3<span>);
        </span><span>return</span> <span>strlen</span>(<span>$char</span><span>);
    }

    </span><span>/*</span><span>*
     * 检测是否为词组
     * @param $word
     * @return bool
     </span><span>*/</span>
    <span>public</span> <span>static</span> <span>function</span> isPhrase(<span>$word</span><span>){

        </span><span>if</span>(self::length(<span>$word</span>)<=1<span>)
            </span><span>return</span> <span>false</span><span>;
        </span><span>return</span> <span>true</span><span>;
    }

}</span>
登入後複製

小帅帅又考虑到词典的来源有可能来自多个地方,比如我给的测试数据,这样不就是可以解决于老大说到无法测试的问题了,小帅帅把词典的来源抽成了个类,类如下:

<?<span>php

</span><span>class</span><span> DBSegmentation {

    </span><span>public</span> <span>$cid</span><span>;

    </span><span>/*</span><span>*
     * 获取类目下分词的词组数据
     * @return array
     </span><span>*/</span>
    <span>public</span> <span>function</span><span> transferDictionary(){
        </span><span>$ret</span> = <span>array</span><span>();
        </span><span>$sql</span> = "select word from category_linklist where cid='<span>$this</span>->cid'"<span>;
        </span><span>$words</span> = DB::makeArray(<span>$sql</span><span>);
        </span><span>foreach</span>(<span>$words</span> <span>as</span> <span>$strWords</span><span>){
            </span><span>$words</span> = <span>explode</span>(",",<span>$strWords</span><span>);

            </span><span>foreach</span>(<span>$words</span> <span>as</span> <span>$word</span><span>){
                </span><span>if</span>(UTF8::isPhrase(<span>$word</span><span>)){
                    </span><span>$ret</span>[] = <span>$word</span><span>;
                }
            }
        }
        </span><span>return</span> <span>$ret</span><span>;
    }
} 

</span><span>class</span><span> TestSegmentation {
    
    </span><span>public</span> <span>function</span><span> transferDictionary(){
        </span><span>$words</span> = <span>array</span><span>(
            </span>"连衣裙,连衣",
            "XXL,xxl,加大,加大码",
            "X码,中码",
            "外套,衣,衣服,外衣,上衣",
            "女款,女士,女生,女性"<span>
        );

        </span><span>$ret</span> = <span>array</span><span>();
        </span><span>foreach</span>(<span>$words</span> <span>as</span> <span>$strWords</span><span>){
            </span><span>$words</span> = <span>explode</span>(",",<span>$strWords</span><span>);

            </span><span>foreach</span>(<span>$words</span> <span>as</span> <span>$word</span><span>){
                </span><span>if</span>(UTF8::isPhrase(<span>$word</span><span>)){
                    </span><span>$ret</span>[] = <span>$word</span><span>;
                }
            }
        }
        </span><span>return</span> <span>$ret</span><span>;

    }
}</span>
登入後複製

那么Splitter 就专心分词把,代码如下:

<span>class</span><span> Splitter {

    </span><span>public</span> <span>$keyword</span><span>;
    </span><span>private</span> <span>$dictionary</span> = <span>array</span><span>();

    </span><span>public</span> <span>function</span> setDictionary(<span>$dictionary</span> = <span>array</span><span>()){

        </span><span>usort</span>(<span>$dictionary</span>,<span>function</span>(<span>$a</span>,<span>$b</span><span>){
            </span><span>return</span> (UTF8::length(<span>$a</span>)>UTF8::length(<span>$b</span>))?1:-1<span>;
        });

        </span><span>$this</span>->dictionary = <span>$dictionary</span><span>;
    }

    </span><span>public</span> <span>function</span><span> getDictionary(){
        </span><span>return</span> <span>$this</span>-><span>dictionary;
    }

    </span><span>/*</span><span>*
     * 把关键词拆分成词组或者单词
     * @return KeywordEntity $keywordEntity
     </span><span>*/</span>
    <span>public</span> <span>function</span> <span>split</span><span>(){

        </span><span>$remainKeyword</span> = <span>$this</span>-><span>keyword;

        </span><span>$keywordEntity</span> = <span>new</span> KeywordEntity(<span>$this</span>-><span>keyword);

        </span><span>foreach</span>(<span>$this</span>->dictionary <span>as</span> <span>$phrase</span><span>){

            </span><span>$matchTimes</span> = <span>preg_match_all</span>("/<span>$phrase</span>/",<span>$remainKeyword</span>,<span>$matches</span><span>);
            </span><span>if</span>(<span>$matchTimes</span>>0<span>){
                </span><span>$keywordEntity</span>->addElement(<span>$phrase</span>,<span>$matchTimes</span><span>);

                </span><span>$remainKeyword</span> = <span>str_replace</span>(<span>$phrase</span>,"::",<span>$remainKeyword</span><span>);
            }
        }

        </span><span>$remainKeywords</span> = <span>explode</span>("::",<span>$remainKeyword</span><span>);
        </span><span>foreach</span>(<span>$remainKeywords</span> <span>as</span> <span>$splitWord</span><span>){

            </span><span>if</span>(!<span>empty</span>(<span>$splitWord</span><span>)){
                </span><span>$keywordEntity</span>->addElement(<span>$splitWord</span><span>);
            }
        }

        </span><span>return</span> <span>$keywordEntity</span><span>;

    }

}


</span><span>class</span><span> KeywordEntity {

    </span><span>public</span> <span>$keyword</span><span>;
    </span><span>public</span> <span>$elements</span> = <span>array</span><span>();

    </span><span>public</span> <span>function</span> __construct(<span>$keyword</span><span>){
        </span><span>$this</span>->keyword = <span>$keyword</span><span>;
    }

    </span><span>public</span> <span>function</span> addElement(<span>$word</span>,<span>$times</span>=1<span>){

        </span><span>if</span>(<span>isset</span>(<span>$this</span>->elements[<span>$word</span><span>])){
            </span><span>$this</span>->elements[<span>$word</span>]->times += <span>$times</span><span>;
        }</span><span>else</span>
            <span>$this</span>->elements[] = <span>new</span> KeywordElement(<span>$word</span>,<span>$times</span><span>);
    }

    </span><span>/*</span><span>*
     * @desc 计算UTF8字符串权重
     * @param string $word
     * @return float
     </span><span>*/</span>
    <span>public</span> <span>function</span> calculateWeight(<span>$word</span><span>)
    {
        </span><span>$element</span> = <span>$this</span>->elements[<span>$word</span><span>];
        </span><span>return</span> <span>ROUND</span>(<span>strlen</span>(<span>$element</span>->word)*<span>$element</span>->times / <span>strlen</span>(<span>$this</span>->keyword), 3<span>);
    }
}


</span><span>class</span><span> KeywordElement {
    </span><span>public</span> <span>$word</span><span>;
    </span><span>public</span> <span>$times</span><span>;

    </span><span>public</span> <span>function</span> __construct(<span>$word</span>,<span>$times</span><span>){
        </span><span>$this</span>->word = <span>$word</span><span>;
        </span><span>$this</span>->times = <span>$times</span><span>;
    }
}</span>
登入後複製

他把算权重的也丢给了一个类专门去处理。

小帅帅写完之后,也顺手写了测试实例:

<?<span>php

</span><span>$segmentation</span> = <span>new</span><span> TestSegmentation();

</span><span>$splitter</span> = <span>new</span><span> Splitter();
</span><span>$splitter</span>->setDictionary(<span>$segmentation</span>-><span>transferDictionary());
</span><span>$splitter</span>->keyword = "连衣裙xxl裙连衣裙"<span>;
</span><span>$keywordEntity</span> = <span>$splitter</span>-><span>split</span><span>();

</span><span>var_dump</span>(<span>$keywordEntity</span>);
登入後複製

 

这样就算你的算法怎么改,它也能从容面对了。

 

小帅帅理解了这个,当你觉得类做的事情太多的时候,可以考虑下单一职责原则。

 

单一职责原则:一个类,只有一个引起它变化的原因。应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。【来自百度百科】

 

当于老大提到是不是有其他分词算法的时候,我们能不能拿来用,小帅帅很高兴,因为现在它的代码是多么美好。

小帅帅如何玩转第三方分词扩展,请继续关注下回分解:手把手教你做关键词匹配项目(搜索引擎)---- 第二十一天

 

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

小米 14 Ultra怎麼調整光圈? 小米 14 Ultra怎麼調整光圈? Mar 19, 2024 am 09:01 AM

光圈大小的調整對於拍照效果有著至關重要的影響,小米14Ultra在相機光圈調整方面提供了前所未有的靈活性。為了讓大家都能順利調節光圈,實現光圈大小的自由調節,小編在這裡為大家帶來了小米14Ultra怎麼設定光圈的詳細教學。小米14Ultra怎麼調整光圈?啟動相機,切換至“專業模式”,選擇主鏡頭-W鏡頭。點選光圈,開啟光圈轉盤,A為自動,按需選擇f/1.9或f/4.0。

AI攻克費馬大定理?數學家放棄5年職業生涯,將100頁證明變代碼 AI攻克費馬大定理?數學家放棄5年職業生涯,將100頁證明變代碼 Apr 09, 2024 pm 03:20 PM

費馬大定理,即將被AI攻克?而整件事最有意義的地方在於,AI即將解決的費馬大定理,正是為了證明AI無用。曾經,數學屬於純粹的人類智力王國;如今,這片疆土正被先進的演算法所破解,所踐踏。圖片費馬大定理,是一個「臭名昭著」的謎題,在幾個世紀以來,一直困擾著數學家。它在1993年被證明,而現在,數學家們有一個偉大計畫:用電腦把證明過程重現。他們希望在這個版本的證明中,如果有任何邏輯上的錯誤,都可以由電腦檢查出來。專案網址:https://github.com/riccardobrasca/flt

Cheat Engine怎麼設定中文?ce修改器設定中文的方法 Cheat Engine怎麼設定中文?ce修改器設定中文的方法 Mar 18, 2024 pm 01:20 PM

Ce修改器(CheatEngine)是一款專用於對遊戲內存進行修改和編輯的遊戲修改工具,那麼在CheatEngine中怎麼設置中文呢?接下來小編為大夥講述ce修改器設置中文的方法內容,希望可以幫助到有需要的朋友。在我們下載的新軟體中,若發現它不是中文介面,可能會讓人感到困惑。儘管這款軟體不是由中國開發的,但我們仍有方法將其轉換為中文版本。只要簡單地套用中文補丁,就能解決這個問題。在下載並安裝了CheatEngine(ce修改器)軟體後,開啟安裝位置,找到名為languages的資料夾,如下圖所示

榮耀 90 GT怎麼更新榮耀MagicOS 8.0? 榮耀 90 GT怎麼更新榮耀MagicOS 8.0? Mar 18, 2024 pm 06:46 PM

榮耀90GT是一款性價比很高的智慧型手機,擁有出色的效能和出色的使用者體驗。然而,有時候我們可能會遇到一些問題,例如榮耀90GT怎麼更新榮耀MagicOS8.0呢?這個步驟因為不同的手機不同的機型可能會有些差別,那麼,讓我們一起來探討一下,如何正確地升級系統。榮耀90GT怎麼更新榮耀MagicOS8.0?2月28日訊息,榮耀今天為旗下90GT/100/100Pro三款手機推送MagicOS8.0公測更新,包版本號為8.0.0.106(C00E106R3P1)1.確保您的榮耀90GT的電池電量充足,

教你使用 iOS 17.4「失竊裝置保護」新進階功能 教你使用 iOS 17.4「失竊裝置保護」新進階功能 Mar 10, 2024 pm 04:34 PM

Apple在周二推出了iOS17.4更新,為iPhone帶來了一系列新功能和修復。這次更新包含了全新的表情符號,同時歐盟用戶也能夠下載其他應用程式商店。此外,更新還加強了對iPhone安全性的控制,引入了更多的「失竊設備保護」設定選項,為用戶提供更多選擇和保障。 "iOS17.3首次引入了「失竊設備保護」功能,為用戶的敏感資料增加了額外的安全保障。當用戶不在家等熟悉地點時,該功能要求用戶首次輸入生物特徵信息,並在一小時後再次輸入資訊才能存取和更改某些數據,如修改AppleID密碼或關閉失竊設備保護功能

DaVinci Resolve Studio 已支援AMD顯示卡的AV1硬體編碼 DaVinci Resolve Studio 已支援AMD顯示卡的AV1硬體編碼 Mar 06, 2024 pm 10:04 PM

最近新消息,lackMagic目前推出了達文西DaVinciResolveStudio影片編輯軟體的18.5PublicBeta2公測版更新,為AMDRadeon顯示卡帶來了AV1編碼支援。更新到最新版本後,AMD顯示卡用戶將能夠在DaVinciResolveStudio中利用硬體加速來進行AV1編碼。儘管官方並未具體指明支援的架構或型號,但預計所有的AMD顯示卡用戶都可以嘗試這項功能。 2018年,AOMedia發布了全新的視訊編碼標準AV1(AOMediaVideoCodec1.0)。 AV1是由多家

Planet Mojo:從自走棋遊戲Mojo Melee建起Web3遊戲元宇宙 Planet Mojo:從自走棋遊戲Mojo Melee建起Web3遊戲元宇宙 Mar 14, 2024 pm 05:55 PM

成立於上個加密週期的熱門元宇宙遊戲項目們正在加速擴張。 3月4日,Web3遊戲元宇宙平台PlanetMojo宣布了其遊戲生態的多個重要動態,包括預告即將推出跑酷遊戲GoGoMojo、旗艦自走棋遊戲MojoMelee推出新賽季“戰之道”,以及為慶祝新賽季與MagicEden合作推出的首個ETH系列「WarBannerNFT」。另外,PlanetMojo也透露,他們計劃在今年稍後推出MojoMelee的Android和iOS行動版本。這個計畫在2021年底啟動,經過在熊市中近兩年的努力建設,即將在

用Golang函數簡化檔案上傳處理 用Golang函數簡化檔案上傳處理 May 02, 2024 pm 06:45 PM

答案:是,Golang提供的函數可以簡化檔案上傳處理。詳情:MultipartFile類型提供對文件元資料和內容的存取。 FormFile函數從表單請求中取得特定檔案。 ParseForm和ParseMultipartForm函數用於解析表單資料和多部分錶單資料。使用這些函數簡化了文件處理流程,讓開發者專注於業務邏輯。

See all articles