手把手教你做关键词匹配项目(搜索引擎)---- 第二十天,教你做第二十天
手把手教你做关键词匹配项目(搜索引擎)---- 第二十天,教你做第二十天
客串:屌丝的坑人表单神器、数据库那点事儿
面向对象升华:面向对象的认识----新生的初识、面向对象的番外----思想的梦游篇(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>);
这样就算你的算法怎么改,它也能从容面对了。
小帅帅理解了这个,当你觉得类做的事情太多的时候,可以考虑下单一职责原则。
单一职责原则:一个类,只有一个引起它变化的原因。应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。【来自百度百科】
当于老大提到是不是有其他分词算法的时候,我们能不能拿来用,小帅帅很高兴,因为现在它的代码是多么美好。
小帅帅如何玩转第三方分词扩展,请继续关注下回分解:手把手教你做关键词匹配项目(搜索引擎)---- 第二十一天

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











絞りサイズの調整は写真の効果に重大な影響を与えますが、Xiaomi Mi 14 Ultra はカメラの絞り調整にこれまでにない柔軟性を提供します。誰もがスムーズに絞りを調整し、絞りサイズの自由な調整を実現できるように、ここのエディターはXiaomi Mi 14Ultraで絞りを設定する方法に関する詳細なチュートリアルを提供します。 Xiaomi Mi 14Ultraで絞りを調整するにはどうすればよいですか?カメラを起動し、「プロフェッショナルモード」に切り替え、メインカメラ-Wレンズを選択します。絞りをクリックし、絞りダイヤルを開きます。A は自動です。必要に応じて f/1.9 または f/4.0 を選択します。

フェルマーの最終定理、AIに征服されようとしている?そして、全体の中で最も意味のある部分は、AI が解決しようとしているフェルマーの最終定理は、まさに AI が役に立たないことを証明するものであるということです。かつて、数学は純粋な人間の知性の領域に属していましたが、現在、この領域は高度なアルゴリズムによって解読され、踏みにじられています。画像 フェルマーの最終定理は、何世紀にもわたって数学者を悩ませてきた「悪名高い」パズルです。それは 1993 年に証明され、現在数学者たちはコンピュータを使って証明を再現するという大きな計画を立てています。彼らは、このバージョンの証明に含まれる論理的エラーがコンピュータによってチェックできることを望んでいます。プロジェクトアドレス: https://github.com/riccardobrasca/flt

Ce Modifier (CheatEngine) は、ゲーム メモリの変更と編集に特化したゲーム変更ツールです。それでは、CheatEngine で中国語を設定する方法を教えてください。次に、エディターが Ce Modifier で中国語を設定する方法を説明します。困っている友達を助けることができることを願っています。新しいソフトウェアをダウンロードすると、インターフェイスが中国語ではないことに気づくと混乱することがあります。このソフトウェアは中国で開発されたものではありませんが、中国版に変換する方法はあります。この問題は中国語パッチを適用するだけで解決できます。 CheatEngine (ce モディファイア) ソフトウェアをダウンロードしてインストールした後、以下の図に示すように、インストール場所を開き、langages という名前のフォルダーを見つけます。

Honor 90GT は、優れたパフォーマンスと優れたユーザー エクスペリエンスを備えたコスト効率の高いスマートフォンです。ただし、場合によっては、Honor 90GT で Honor MagicOS8.0 をアップデートする方法など、いくつかの問題が発生することがあります。この手順は携帯電話やモデルによって異なる場合があるため、システムを正しくアップグレードする方法について説明します。 Honor 90GT で Honor MagicOS 8.0 をアップデートするにはどうすればよいですか? 2 月 28 日のニュースによると、Honor は本日、3 つの携帯電話 90GT/100/100Pro 向けに MagicOS8.0 パブリック ベータ アップデートをプッシュしました。パッケージのバージョン番号は 8.0.0.106 (C00E106R3P1) 1 です。 90GT のバッテリーは完全に充電されています。

最近のニュースでは、lackMagic が DaVinci Resolve Studio ビデオ編集ソフトウェアの 18.5PublicBeta2 パブリック ベータ アップデートを開始し、AMD Radeon グラフィックス カードに AV1 エンコードのサポートをもたらしました。最新バージョンにアップデートすると、AMD グラフィックス カード ユーザーは、DaVinci Resolve Studio で AV1 エンコード用のハードウェア アクセラレーションを利用できるようになります。公式ではサポートされているアーキテクチャやモデルは明記されていませんが、すべての AMD グラフィックス カード ユーザーがこの機能を試すことができると予想されます。 2018 年、AOMedia は新しいビデオ コーディング標準 AV1 (AOMediaVideoCodec1.0) をリリースしました。 AV1 は多数の企業によって生産されています。

Appleは火曜日にiOS 17.4アップデートを公開し、iPhoneに多数の新機能と修正をもたらした。このアップデートには新しい絵文字が含まれており、EU ユーザーは他のアプリ ストアから絵文字をダウンロードすることもできます。さらに、このアップデートでは iPhone のセキュリティ制御も強化され、より多くの「盗難デバイス保護」設定オプションが導入され、ユーザーにより多くの選択肢と保護が提供されます。 「iOS17.3では、「盗難デバイス保護」機能が初めて導入され、ユーザーの機密情報のセキュリティが強化されています。ユーザーが自宅やその他の身近な場所から離れている場合、この機能ではユーザーは最初に生体認証情報を入力する必要がありますApple ID パスワードの変更や盗難デバイス保護の無効化など、特定のデータにアクセスして変更するには、情報を再度入力する必要があります。

最後の暗号サイクルで設立された人気のメタバース ゲーム プロジェクトは、その拡大を加速しています。 3 月 4 日、Web3 ゲーム メタバース プラットフォームである PlanetMojo は、次期パルクール ゲーム GoGoMojo の発表、主力オート チェスの新シーズン「Way of War」の開始など、ゲーム エコロジーにおける多くの重要な開発を発表しました。ゲーム MojoMelee、および MagicEden と協力して今シーズン開始された新しい最初の ETH シリーズ「WarBannerNFT」の祝賀。さらに、PlanetMojo は、今年後半に MojoMelee の Android および iOS モバイル版をリリースする予定であることも明らかにしました。このプロジェクトは 2021 年末に開始される予定です。弱気市場での約 2 年間の懸命な作業を経て、間もなく完了する予定です。

回答: はい、Golang はファイルのアップロード処理を簡素化する機能を提供します。詳細: MultipartFile タイプは、ファイルのメタデータとコンテンツへのアクセスを提供します。 FormFile 関数は、フォーム要求から特定のファイルを取得します。 ParseForm 関数と ParseMultipartForm 関数は、フォーム データとマルチパート フォーム データを解析するために使用されます。これらの機能を使用すると、ファイル処理プロセスが簡素化され、開発者はビジネス ロジックに集中できるようになります。
