在 Laravel 項目中使用 Elasticsearch 做引擎,scout 全文搜索(小白出品, 絕對白話)


項目中需要搜索, 所以從零開始學習大家都在用的搜索神器 elasiticsearch. 剛開始 google 的時候, 搜到好多經驗貼和視頻(中文的, 英文的), 但是由於是第一次接觸, 一點概念都沒有, 大家介紹的方法又有點不盡相同, 所以有點懵逼, 最后經過層層篩選, 終於找到組織 Elasticsearch: 權威指南. 這是中文翻譯版的, 我目前覺得還可以哈, 語言比較朴實. 

然后呢, 因為我自己在從下載安裝這些基本的操作過程中都走了很多的彎路, 所以我把最實用的干貨還是總結一下, 方便下次直接上手, 最起碼可以先跑起來哈. 至於對於 elasticsearch 的深入理解, 大家還是看<<權威指南>>吧.

第一步: 下載安裝 ES

我真的是找到了各種版本的下載安裝命令, 有些命令根本跑不通, 讓我很是頭大, 當然, 我自己是 macos 系統的, 所以我的一切安裝步驟也都只是保證絕對適用於 macos:

  1. 到官網下載壓縮包 根據自己的系統選擇哈: 
  2. 把壓縮包解壓, 解壓后的文件我暫且放在我現在做的項目里了, 然后在終端進入這個文件.(這里說明一下, 只要進入你剛剛下載的那個文件夾就行了, 版本號不用 copy 我的, 因為有可能已經更新了.)
cd elasticsearch-6.6.1 

之后, 執行下面的命令啟動服務(如果你想把 Elasticsearch 作為一個守護進程在后台運行,那么可以在后面添加參數 -d):

./bin/elasticsearch 

通過以上兩步, 應該說 elasticsearch 就已經開始為你的站點服務了. 為了 double check 是否啟動成功,可以打開另一個終端,執行以下操作:

curl 'http://localhost:9200/?pretty' 

如果你能得到類似下面的結果, 就意味着你現在已經啟動並運行一個 Elasticsearch 節點了:

{ "name" : "27qRw7J", "cluster_name" : "elasticsearch", "cluster_uuid" : "RFuFAGLaRVqtlJOyn-hFWA", "version" : { "number" : "6.6.1", "build_flavor" : "default", "build_type" : "tar", "build_hash" : "1fd8f69", "build_date" : "2019-02-13T17:10:04.160291Z", "build_snapshot" : false, "lucene_version" : "7.6.0", "minimum_wire_compatibility_version" : "5.6.0", "minimum_index_compatibility_version" : "5.0.0" }, "tagline" : "You Know, for Search" } 

第二步: 安裝中文分詞插件 IK

Elasticsearch原裝分詞器會簡單地拆分每個漢字,沒有根據詞庫來分詞,這樣的后果就是搜索結果很可能不是你想要的。這里推薦使用elasticsearch-analysis-ik,支持自定義詞庫。 文檔推薦了兩種下載安裝方式, 兩種我都試了, 但是第二種一直報錯, google 了一下, 很多人都有這個問題, 貌似是不支持了....額. 所以就推薦大家直接用第一種方式吧, 就是直接下載文件, 解壓之后放到 your-es-root/plugins/ik 文件夾里. 這種方法理論上是沒啥問題的, 但是我依然踩了一個很丟人的坑, 估計大部分都不會犯這個錯誤吧, 就是我是手動解壓的, 解壓之后生成了一個文件夾, 我就把這個文件夾直接放到 ik 文件夾里了, 然后重啟 es 的時候就一直報錯. 所以應該是把解壓后的文件夾里的所有文件都直接放進 ik 文件夾里~~~~~ 

然后重啟 es 就好了. 

第三步: 安裝 scout

這個是 laravel 官方推出的全文搜索包, 是針對Eloquent 模型開發的一個簡單的,基於驅動的全文檢索系統. 如果你跟我一樣也是第一次接觸, 肯定也會覺得這句話有點晦澀難懂吧, 沒關系, 我開始也是這樣的. 通過把整個過程理順之后, 我現在的白話理解就是, elasticsearch 就好比是一個數據庫, 只不過跟 mysql 的存儲方式不同. 這個數據庫雖然使用 java 寫的, 但是它也支持很多很多其他語言, 大家都可以以 RESTful API 的形式跟它交互(無非就是存儲數據啦). 也就是說, 針對不同的請求它都有相應的接口暴露出來, 那我們可以直接使用這些接口的, 就好像你直接寫 sql 語句查數據庫一樣, 但是 貼心的 laravel 覺得原生請求太不優雅了, 所以它封裝了一個包 scout. 好了, 希望我這翻廢話能對你理清關系有所幫助. 下面開始安裝了:

先安裝 scout 的 es 驅動 tamayo/laravel-scout-elastic:

composer require tamayo/laravel-scout-elastic 

, 這里要說明一下, 目前這個包的最新版本是 4.0.0, 而這個版本只支持 scout ^5.0 的版本, 所以盡管此時 scout 的最新版本已經到了 7.0, 我在安裝 scout 的時候還是要指明 5.0 的版本:

composer require laravel/scout ^5.0 

通過 laravel/scout 的官方文檔可以看到, 它是默認只支持使用 Algolia 驅動, 但是我們的目標是用 es 做驅動, 所以要改一下 config/scout.php 的配置.

找到下面這行代碼:

‘driver’ => env(‘SCOUT_DRIVER’, ‘algolia’), 

把它改為:

‘driver’ => env(‘SCOUT_DRIVER’, ‘elasticsearch’), 

之后, 在最下面添加如下代碼:

elasticsearch’ => [ ‘index’ => env(‘ELASTICSEARCH_INDEX’, ‘laravel’), ‘config’ => [ ‘hosts’ => [ env(‘ELASTICSEARCH_HOST’, ‘localhost’), ], ], ], 

然后在 .env 文件中添加:

ELASTICSEARCH_INDEX=scout ELASTICSEARCH_HOST=http://localhost:9200 

以上, 算是把工具都准備齊了, 下面就是開干了.

但是, 在開始之前, 還想再說幾句廢話, 就是建議大家還是看一下  Elasticsearch: 權威指南, 雖然我也還沒有完全看完, 但是最起碼在我對 es 存儲數據的結構, 在腦海里是有大概了解的, 也就是對像 "索引", "文檔" 這些概念都知道是代表什么的, 這些在權威指南里都解釋得很白話的, 我是覺得在我這篇文章里, 很難去解釋的那么清楚...... 所以, 如果你不是那么趕時間的話, 還是建議先去大概過一遍. 如果實在沒時間, 就跟着下面的步驟做, 也是 OK 嗒.

接下來, 以我自己的項目為例, 我有一個 Post 表需要做全文索引, 我的表是已經建好的, 里面也已經有 40條測試數據, 現在我就要把這個表索引到 es 中:

php artisan scout:import "App\Post" 

會得到下面的反饋, 證明導入成功了:

Imported [App\Post] models up to ID: 40 All [App\Post] records have been imported. 

下面測試一下搜索功能, 打開 tinker:

php artisan tinker

執行以下命令:

App\Post::search('Blake Swaniawski')->get(); 

如果一切正常的話, 應該會返回一堆 JSON 字符串(注意: 這里換成你自己的 model)

通過簡單的測試以后, 我們就可以應用到項目中啦.
新建一個 searchController:

php artisan make:controller SearchController 

打開這個新建的 controller 文件, 添加如下方法:

public function search(Request $request){ if($request->has('search')){ $posts = Post::search($request->input('search'))->get(); } return view('web.search.results', compact('posts')); } 

打開 web.php 文件, 添加路由:

Route::get('/SearchQuery', 'SearchController@search'); 

之后打開帶搜索框的 blade 模板(我的就是在 layout 里, 我就只截取搜索框的代碼了). 這里的 class 大家都可以忽略, 主要就是關注配置表單提交的信息, 還有就是 input 框的 name 一定要是 "search":

<form class="form-inline my-2 my-lg-0" id="elasticScout" action="/SearchQuery" method="get"> <input class="form-control mr-sm-2 form-control-sm" type="search" placeholder="搜索" aria-label="Search" name="search"> <button class="btn btn-outline-secondary btn-sm my-2 my-sm-0" type="submit">搜索</button> </form> 

最后再根據 searchController 里返回的 view, 建一個展示查詢結果的 result 頁面, 並在頁面中把 查詢結果循環輸出:

@if(!empty($posts)) @foreach($posts as $post) <h1>{{ $post->content }} </h1> @endforeach @endif 

終於.....寫完了.....
我真的彎彎曲曲走了差不多兩天, follow 了好幾位前輩的經驗, 東拼西湊, 最終總結了一條最適合我自己的路(捂臉笑). 把我參考的前輩的文章也分享一下, just in case for u ~~~~~

這是我看到的最后一篇, 或許是由於有了前面一天的積累, 看到這篇的時候, 我有種豁然開朗的感覺, 所以我后面的主要思路也是參考它的, 之后稍微填了各別小坑:
Basic Search Functionality with ElasticSearch & Laravel Scout

我抄襲了這位前輩的題目, 因為我覺得我想不到更好的(嘻嘻), 但是恕我太白, 我無法完全 follow 他的思路:
Laravel5.5 使用 Elasticsearch 做引擎,scout 全文搜索

還有一篇來自 laravel-china 的, 我從那里學到了要用 ik 分詞, 好吧, 我承認我找不到了, 好吧, 我承認我實在不想找了, 閃~~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM