大家好,我是魚皮,今天搞一場技術(shù)實(shí)戰(zhàn),需求分析 => 技術(shù)選型 => 設(shè)計(jì)實(shí)現(xiàn),從 0 到 1,帶大家優(yōu)化網(wǎng)站搜索的靈活性。

ES + 云開發(fā)搜索優(yōu)化實(shí)戰(zhàn)本文大綱:

背景我" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運(yùn)營 > 優(yōu)化了破網(wǎng)站的搜索功能

優(yōu)化了破網(wǎng)站的搜索功能

時(shí)間:2023-05-30 11:21:02 | 來源:網(wǎng)站運(yùn)營

時(shí)間:2023-05-30 11:21:02 來源:網(wǎng)站運(yùn)營

優(yōu)化了破網(wǎng)站的搜索功能:
使用 ES + 云開發(fā)實(shí)戰(zhàn)優(yōu)化網(wǎng)站搜索
大家好,我是魚皮,今天搞一場技術(shù)實(shí)戰(zhàn),需求分析 => 技術(shù)選型 => 設(shè)計(jì)實(shí)現(xiàn),從 0 到 1,帶大家優(yōu)化網(wǎng)站搜索的靈活性。

ES + 云開發(fā)搜索優(yōu)化實(shí)戰(zhàn)

本文大綱:

背景

我開發(fā)的 編程導(dǎo)航網(wǎng)站 已經(jīng)上線 6 個(gè)月了,但是從上線之初,網(wǎng)站一直存在一個(gè)很嚴(yán)重的問題,就是搜索功能并不好用。

此前,為了追求快速上線,搜索功能就簡單地使用了數(shù)據(jù)庫模糊查詢(包含)來實(shí)現(xiàn),開發(fā)是方便了,但這種方式很不靈活。

舉個(gè)例子,網(wǎng)站上有個(gè)資源叫 “Java 設(shè)計(jì)模式”,而用戶搜索 “Java設(shè)計(jì)模式” 就啥都搜不出來,原因是資源名中包含了空格,而用戶搜索時(shí)輸入的關(guān)鍵詞并不包含空格。

空格只是一種特例,類似的情況還有很多,比如網(wǎng)站上有個(gè)資源叫 “Java 并發(fā)編程實(shí)戰(zhàn)”,但用戶搜索 “Java 實(shí)戰(zhàn)” 時(shí),明明前者包含 “Java” 和 “實(shí)戰(zhàn)” 這兩個(gè)詞,但卻是什么都搜不出來的。

要知道,搜索功能對于一個(gè)信息聚合類站點(diǎn)是至關(guān)重要的,直接影響用戶的體驗(yàn)。在你的網(wǎng)站上搜不到資源,誰還會(huì)用?

所以我也收到了一些小伙伴的禮貌建議,比如這位禿頭 Tom:

之前沒有優(yōu)化搜索,主要是兩個(gè)原因:窮 + 怕麻煩。但隨著網(wǎng)站用戶量的增大,是時(shí)候填坑了!

技術(shù)選型

想要提高網(wǎng)站搜索靈活性,可以使用 全文搜索 技術(shù),在前端和后端都可以實(shí)現(xiàn)。

前端全文搜索

有時(shí),我們要檢索的數(shù)據(jù)是有限的,且所有數(shù)據(jù)都是 存儲(chǔ)在客戶端 的。

比如個(gè)人博客網(wǎng)站,我們通常會(huì)把每篇文章作為一個(gè)文件存放在某目錄下,而不是存在后臺(tái)數(shù)據(jù)庫中,這種情況下,不需要再從服務(wù)器上去請求動(dòng)態(tài)數(shù)據(jù),那么可以直接在前端搜索數(shù)據(jù)。

有一些現(xiàn)成的搜索庫,比如 Lunr.js(GitHub 7k+ star),先添加要檢索的內(nèi)容:

var idx = lunr(function () { this.field('title') this.field('body') // 內(nèi)容 this.add({ "title": "yupi", "body": "wx搜程序員魚皮,閱讀我的原創(chuàng)文章", "id": "1" })})然后搜索就可以了:

idx.search("魚皮")純前端全文搜索的好處是無需后端、簡單方便,可以節(jié)省服務(wù)器的壓力;無需連網(wǎng),也沒有額外的網(wǎng)絡(luò)開銷,檢索更快速。

后端全文搜索

區(qū)別于前端,后端全文搜索在服務(wù)器上完成,從遠(yuǎn)程數(shù)據(jù)庫中搜索符合要求的數(shù)據(jù),再直接返回給前端。

目前主流的后端全文搜索技術(shù)是 Elasticsearch,一個(gè)分布式、RESTful 風(fēng)格的搜索和數(shù)據(jù)分析引擎。

它的功能強(qiáng)大且靈活,但是需要自己搭建、定義數(shù)據(jù)、管理詞典、上傳和維護(hù)數(shù)據(jù)等,可操作性很強(qiáng),需要一些水平,新手和大佬設(shè)計(jì)出的 ES 搜索系統(tǒng)那是天差地別。

所以,對于不熟悉 Elasticsearch 的同學(xué),也可以直接使用現(xiàn)成的全文檢索服務(wù)。比如 Algolia,直接通過它提供的 API 上傳需要檢索的數(shù)據(jù),再用它提供的 API 檢索就行了。它提供了一定的免費(fèi)空間,對于小型網(wǎng)站和學(xué)習(xí)使用完全足夠了。

選擇

那么我的編程導(dǎo)航網(wǎng)站選擇哪種實(shí)現(xiàn)方式呢?

首先,該網(wǎng)站的資源數(shù)是不固定的、無規(guī)律動(dòng)態(tài)更新的,因此不適合前端全文檢索。

其次,考慮到日后網(wǎng)站的數(shù)據(jù)量會(huì)比較大,而且可能要根據(jù)用戶的搜索動(dòng)態(tài)地去優(yōu)化檢索系統(tǒng)(比如自定義編程詞典),因此考慮使用 Elasticsearch 技術(shù) 自行搭建搜索引擎,而不用現(xiàn)成的全文檢索服務(wù),這樣今后自己想怎么定制系統(tǒng)都可以。此外,不用向其他平臺(tái)發(fā)送網(wǎng)站數(shù)據(jù),能保證數(shù)據(jù)的安全。

ES 安裝

確定使用 Elasticsearch 后,要先搭建環(huán)境。

可以自己購買服務(wù)器,再按照官方文檔一步步手動(dòng)安裝。對于有一定規(guī)模的個(gè)人網(wǎng)站來說,雖然搭建過程不難,但后期的維護(hù)成本卻是巨大的,比如性能分析、監(jiān)控、告警、安全等等,都需要自己來配置。尤其是后期網(wǎng)站數(shù)據(jù)量更大了,還要考慮搭建集群、水平擴(kuò)容等等。

因此,我選擇直接使用云服務(wù)商提供的 Elasticsearch 服務(wù),這里選擇騰訊云,自動(dòng)為你搭建了現(xiàn)成的 ES 集群服務(wù),還提供了可視化架構(gòu)管理、集群監(jiān)控、日志、高級插件、智能巡檢等功能。

雖然 ES 服務(wù)的價(jià)格貴,但節(jié)省下大量時(shí)間成本,對我來說是值得的。

還有個(gè)很方便的定制化搜索服務(wù) Elastic App Search,大家感興趣可以試試。

ES 公共服務(wù)

我們的目標(biāo)是優(yōu)化網(wǎng)站資源的搜索功能,但接下來要做的不是直接編寫具體的業(yè)務(wù)邏輯,而是先開發(fā)一個(gè) 公共的 ES 服務(wù) 。

其實(shí)對 ES 的操作比較簡單,可以先簡單地把它理解為一個(gè)數(shù)據(jù)庫,那么公共的 ES 服務(wù)應(yīng)具有基本的增刪改查功能,供其他函數(shù)調(diào)用。

實(shí)現(xiàn)

由于編程導(dǎo)航的后端使用的是騰訊云開發(fā)技術(shù),用 Node.js 來編寫服務(wù),所以選用官方推薦的 @elastic/elasticsearch 庫來操作 ES。

沒用過云開發(fā)也沒事,可以先把它理解為一個(gè)后端,歡迎閱讀我之前的文章:了解云開發(fā) 。
代碼很簡單,先是建立和 ES 的連接,此處為了保證數(shù)據(jù)安全,使用內(nèi)網(wǎng)地址:

const client = new Client({ // 內(nèi)網(wǎng)地址 node: 'http://10.0.61.1:9200', // 用戶名和密碼 auth: { username: esConfig.username, password: esConfig.password, },});然后是編寫增刪改查。這里做一步 抽象,通過 switch 等分支語句,根據(jù)請求參數(shù)來區(qū)分操作、要操作的數(shù)據(jù)等,這樣就不用把每個(gè)操作都獨(dú)立寫成一個(gè)接口了。

// 接受請求參數(shù)const { op, index, id, params } = event;// 根據(jù)操作執(zhí)行增刪改查switch (op) { case 'add': return doAdd(index, id, params); case 'delete': return doDelete(index, id); case 'search': return doSearch(index, params); case 'update': return doUpdate(index, id, params);}
在云開發(fā)中,假如某個(gè)函數(shù)太久沒被調(diào)用,就會(huì)釋放資源。下次請求時(shí),會(huì)進(jìn)行冷啟動(dòng),重新創(chuàng)建資源,導(dǎo)致接口返回較慢。因此,把多個(gè)操作封裝到同一個(gè)函數(shù)中,也可以減少冷啟動(dòng)的幾率。
具體的增刪改查代碼就不贅述了,對著 ES Node 的官方文檔看一遍就行了,后面會(huì)把代碼開源到編程導(dǎo)航倉庫中(https://github.com/liyupi/code-nav)。

本地調(diào)試

編寫好代碼后,可以用云開發(fā)自帶的 tcb 命令行工具在本地執(zhí)行該函數(shù)。

記得先把 ES 的連接地址改成公網(wǎng),然后輸入一行命令就行了。比如我們要向 ES 插入一條數(shù)據(jù),傳入要執(zhí)行的函數(shù)名、請求參數(shù)、代碼路徑:

tcb fn run --name <functionName> --params "{/"op/": /"add/"}" --path <functionPath>執(zhí)行成功后,就能在 ES 中看到新插入的數(shù)據(jù)了(通過 Kibana 面板或 curl 查看):

遠(yuǎn)程測試

本地測試好公共服務(wù)代碼后,把 ES 連接地址改成內(nèi)網(wǎng) IP,然后發(fā)布到云端。

接下來試著編寫一個(gè)其他的函數(shù)來訪問公共 ES 服務(wù),比如插入資源到 ES,通過 callFunction 請求:

// 添加資源到 ESfunction addData() { // 請求公共服務(wù) app.callFunction({ name: 'esService', data: { op: 'add', index: 'resource', id, params: data, } });}但是,數(shù)據(jù)并沒有被成功插入,而是返回了接口超時(shí),Why?

內(nèi)網(wǎng)配置

通過日志得知是 ES 連接不上,會(huì)不會(huì)是因?yàn)榘l(fā)布上線的 ES 公共服務(wù)所在的機(jī)器和 ES 不在同一個(gè)內(nèi)網(wǎng)呢?

所以需要在云開發(fā)控制臺(tái)更改 ES 公共服務(wù)的私有網(wǎng)絡(luò)配置,選擇和購買 ES 時(shí)同樣的子網(wǎng)就行了:

修改之后,再次遠(yuǎn)程請求 ES 公共服務(wù),數(shù)據(jù)就插入成功了~

數(shù)據(jù)索引

開發(fā)好 ES 公共服務(wù)后,就可以編寫具體的業(yè)務(wù)邏輯了。

首先要在 ES 中建立一個(gè)索引(類似數(shù)據(jù)庫的表),來約定數(shù)據(jù)的類型、分詞等信息,而不是允許隨意插入數(shù)據(jù)。

比如為了更靈活搜索,資源名應(yīng)該指定為 "text" 類型,以開啟分詞,并指定 ik 中文分詞器:

"name": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } }}而點(diǎn)贊數(shù)應(yīng)設(shè)置為 "long" 類型,只允許傳入數(shù)字:

"likeNum": { "type": "long"}最好還要為索引指定一個(gè)別名,便于后續(xù)修改字段時(shí)重建索引:

"aliases" : { "resource": {}}編寫好建立索引的 json 配置后,通過 curl 或 Kibana 去調(diào)用 ES 新建索引接口就行了。

數(shù)據(jù)同步

之前,編程導(dǎo)航網(wǎng)站的資源數(shù)據(jù)都是存在數(shù)據(jù)庫中的,用戶從數(shù)據(jù)庫中查詢。而現(xiàn)在要改為從 ES 中查詢,ES 空空如也可不行,得想辦法把數(shù)據(jù)庫中的資源數(shù)據(jù)同步到 ES 中。

這里有幾種同步策略。

雙寫

以前,用戶推薦的資源只會(huì)插入到數(shù)據(jù)庫,雙寫是指在資源插入數(shù)據(jù)庫的時(shí)候,同時(shí)插入到 ES 就好了。

聽上去挺簡單的,但這種方式存在一些問題:

  1. 會(huì)改動(dòng)以前的代碼,每個(gè)寫數(shù)據(jù)庫的地方都要補(bǔ)充寫入 ES。
  2. 會(huì)存在一邊兒寫入失敗、另一邊兒成功的情況,導(dǎo)致數(shù)據(jù)庫和 ES 的數(shù)據(jù)不一致。
那有沒有對現(xiàn)有代碼 侵入更小 的方法呢?

定時(shí)同步

如果對數(shù)據(jù)實(shí)時(shí)性的要求不高,可以選擇定時(shí)同步,每隔一段時(shí)間將最新插入或修改的數(shù)據(jù)從數(shù)據(jù)庫復(fù)制到 ES 上。

實(shí)現(xiàn)方式有很多種,比如用 Logstash 數(shù)據(jù)傳輸管道,或者自己編寫定時(shí)任務(wù)程序,這樣就完全不用改現(xiàn)有的代碼。

實(shí)時(shí)同步

如果對數(shù)據(jù)實(shí)時(shí)性要求很高,剛剛插入數(shù)據(jù)庫的數(shù)據(jù)就要能立刻就能被搜索到,那么就要實(shí)時(shí)同步。除了雙寫外,還可以監(jiān)聽數(shù)據(jù)庫的 binlog,在數(shù)據(jù)庫發(fā)生任何變更時(shí),我們都能感知到。

阿里有個(gè)開源項(xiàng)目叫 Canal ,能夠?qū)崟r(shí)監(jiān)聽 MySQL 數(shù)據(jù)庫,并推送通知給下游,感興趣的朋友可以看看。

實(shí)現(xiàn)

由于編程資源的搜索對實(shí)時(shí)性要求不高,所以定時(shí)同步就 ok。

云開發(fā)默認(rèn)提供了定時(shí)函數(shù)功能,我就直接寫一個(gè)云函數(shù),每 1 分鐘執(zhí)行一次,每次讀取數(shù)據(jù)庫中近 5 分鐘內(nèi)發(fā)生了變更的數(shù)據(jù),以防止上次執(zhí)行失敗的情況。此外,還要配置超時(shí)時(shí)間,防止函數(shù)執(zhí)行時(shí)間過長導(dǎo)致的執(zhí)行失敗。

在云開發(fā) - 云函數(shù)控制臺(tái)就能可視化配置了,需要為定時(shí)任務(wù)指定一個(gè) crontab 表達(dá)式:

開啟定時(shí)同步后,不要忘了再編寫并執(zhí)行一個(gè) 首次 同步函數(shù),用于將歷史的全量數(shù)據(jù)同步到 ES。

數(shù)據(jù)檢索

現(xiàn)在 ES 上已經(jīng)有數(shù)據(jù)了,只剩最后一步,就是怎么把數(shù)據(jù)搜出來呢?

首先我們要學(xué)習(xí) ES 的搜索 DSL(語法),包括如何取列、搜索、過濾、分頁、排序等,對新手來講,還是有點(diǎn)麻煩的,尤其是查詢條件中布爾表達(dá)式的組合,稍微不注意就查不出數(shù)據(jù)。所以建議大家先在 Kibana 提供的調(diào)試工具中編寫查詢語法:

查出預(yù)期的數(shù)據(jù)后,再編寫后端的搜索函數(shù),接受的請求參數(shù)最好和原接口保持一致,減少改動(dòng)。

可以根據(jù)前端傳來的請求動(dòng)態(tài)拼接查詢語法,比如要按照資源名搜索:

// 傳了資源名if (name) { // 拼接查詢語句 query.bool.should = [ { match: { name } } ];}由此,整個(gè)網(wǎng)站的搜索優(yōu)化完畢。

再去試一下效果,現(xiàn)在哪怕我輸入一些多 “魚” 的詞,也能搜到了!

ES 是怎么實(shí)現(xiàn)靈活搜索的呢?歡迎閱讀 這篇文章 。
新 ES 搜索接口的發(fā)布并不意味著老的數(shù)據(jù)庫查詢接口淘汰,可以同時(shí)保留。按名稱搜索資源時(shí)用新接口,更靈活;而根據(jù)審核狀態(tài)、搜索某用戶發(fā)布過的資源時(shí),可以用老接口,從數(shù)據(jù)庫查。從而分?jǐn)傌?fù)載,職責(zé)分離,讓對的技術(shù)做對的事情!


以上就是本期分享,有幫助的話點(diǎn)個(gè)贊吧 ??

我是魚皮,最后再送大家一些 幫助我拿到大廠 offer 的學(xué)習(xí)資料

歡迎閱讀 我從 0 自學(xué)進(jìn)入騰訊的編程學(xué)習(xí)、求職、考證、寫書經(jīng)歷,不再迷茫!

關(guān)鍵詞:功能

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉