使用 nodejs 和 ElasticSearch 快速搭建全文檢索
點(diǎn)擊藍(lán)色“有關(guān)SQL”關(guān)注我喲
加個“星標(biāo)”,天天與10000人一起快樂成長

上次群友問我,Python怎么學(xué),我說四個小時足夠了,你們不信。這次,我用2個小時,僅僅用Google,快速搭建了一個 nodejs + Elasticsearch 的小 Demo. 足可見,在有搜索的年代,快速上手一門技術(shù),已經(jīng)不是什么難事。
1 安裝
1.1 下載地址
https://nodejs.org/en/download
提供 windows, Linux, MacOS 三大操作系統(tǒng)的安裝包,選擇適合自己開發(fā)機(jī)器或服務(wù)器版本。
不同操作系統(tǒng)版本,均有兩種安裝方式。
第一種使用系統(tǒng)自帶安裝工具,安裝 nodejs, 好處是界面化操作,非常簡易,麻煩的地方在于 Linux/Unix 上安裝,你可能要找下安裝工具,再適應(yīng)下如何使用。
第二種不使用安裝工具,直接解壓 nodejs 壓縮包,到指定文件夾目錄,即可。它的好處是安裝快速,且可以同時部署好多服務(wù)器,但復(fù)雜的地方是,你必須要熟悉解壓縮,安裝權(quán)限等命令。如果是遠(yuǎn)程安裝,還要知道 shell, ssh 等命令。
1.2 安裝
我選擇部署的環(huán)境是 CentOS, 下載了 Linux Binaries(x64) 的壓縮版。
完整的安裝包是:node-v12.19.0-linux-x64.tar.xz
將其解壓縮到 nodejs 文件夾,并配置環(huán)境變量,使其可以被直接調(diào)用。
這點(diǎn)對于Linux初學(xué)者非常有難度,如果不配置環(huán)境變量,那么直接運(yùn)行 node 命令,就會出現(xiàn)找不到命令的錯誤。bash: node: command not found…
此時你會懷疑自己是不是哪里做錯了,于是從頭下一遍安裝包,再裝一遍,發(fā)現(xiàn)還是那樣。于是就開始懷疑人生了。
配置環(huán)境變量,很簡單:
PATH=$PATH:$HOME/.local/bin:$HOME/bin
NODE_PATH=/home/MySQLAdmin/Downloads/nodejs/nodejs/bin
PATH=$PATH:$NODE_PATH
export?PATH
使用 source 命令,將新配置的環(huán)境變量,應(yīng)用到當(dāng)前的命令窗口:
[MySQLAdmin@centos00?~]$?source?.bash_profile
再次執(zhí)行 node, 就變得絲滑柔順了:
[MySQLAdmin@centos00?~]$?node
Welcome?to?Node.js?v12.19.0.
Type?".help"?for?more?information.
>?
1.3 新建應(yīng)用
執(zhí)行 node app.js 命令,就可以運(yùn)行寫在 app.js 文件中的程序了。整個過程也很簡單,nodejs 監(jiān)控發(fā)到指定端口上的請求,把相應(yīng)的資源,數(shù)據(jù),文件等發(fā)給請求。
舉一個最簡單的 Web 服務(wù)例子,當(dāng)用戶請求達(dá)到 3000 端口時,nodejs 程序返回 hello ,Welcome to Nodejs world 的消息:

實(shí)現(xiàn)這個目的,換了以前,我們要配置一堆技術(shù)棧,IIS/Apache,還要用上c#/vb.net/java,現(xiàn)在幾行代碼搞定:
const?http=require("http");
const?hostname?=?"127.0.0.1";
const?port?=?3000;
const?server?=?http.createServer(
????????(req,res)?=>?{
????????res.statusCode?=?200?;
????????res.setHeader("Content-Type","text/plain");
????????res.end("Hello,?welcome?to?Nodejs?world!");
????????}
);
server.listen(port,hostname,
????????()=>{
????????console.log(`server?running?at?http://${hostname}:${port}/`);
????????}
);
2. 包的使用
開發(fā)過軟件的朋友,都知道,不能把全部的雞蛋都放一個籃子里。通常,遇到軟件代碼量很大,發(fā)生了臃腫的時候,我們會把這些軟件部分抽象出來,已達(dá)到復(fù)用的效果。
那么抽象出來的這部分代碼,通常會放在一個軟件包里。這樣不僅僅可以簡化代碼,更重要的是達(dá)到了可以多處復(fù)用,減少耦合的情況。
2.1 包的引用
nodejs 其實(shí)也一樣,當(dāng)我們要訪問數(shù)據(jù)庫的時候,不可能在 nodesjs 里面寫好全部的數(shù)據(jù)庫適配代碼。所以需要數(shù)據(jù)庫供應(yīng)商提供相應(yīng)的數(shù)據(jù)庫驅(qū)動包和開發(fā)包,這樣 nodejs 去調(diào)用這兩部分包就可以。甚至這兩部分包,還可以集成到一個包當(dāng)中。
從第一小節(jié)最后一個例子中,我給出了一段簡單的示例代碼:
const?http=require("http");
....
這里的 require 方法,給到一個參數(shù)值 http, 這個參數(shù)值,其實(shí)就是 nodejs 可以識別的包名。這段代碼引用了 http 模塊(包)。
2.2 包的管理
雖然 http 調(diào)用是很簡單,一行代碼就實(shí)現(xiàn)了。但回到數(shù)據(jù)庫這個方向上,由于數(shù)據(jù)庫的種類繁多,僅僅是RDBMS,關(guān)系型數(shù)據(jù)庫就有很多種,MySQL, Oracle, DB2, SQL Server 等等,更別說一堆開源的NoSQL數(shù)據(jù)庫。
如此之多的數(shù)據(jù)庫,想要窮盡他們所有的驅(qū)動程序和開發(fā)包,幾乎是不可能做到的事情。所以唯一能做到的方法,就是由數(shù)據(jù)庫廠商自行開發(fā)可以被 nodejs 識別的包。這就涉及到 nodejs 對包的管理。
所以 NPM 就出場了。NPM, Node Package Manager, nodejs的包管理器。這是nodejs內(nèi)置的管理器,一般來說 nodejs 安裝的時候,就隨之安裝好了。
包管理器有了,那么包從哪里來,又安裝到哪里去了呢?安裝的時候,會不會很像 Linux 安裝軟件一樣,那么復(fù)雜呢?其實(shí)一點(diǎn)也不。
朋友們,只要你想一下充電寶就知道了。滿大街都是的充電寶,就像是 Nodejs 中用到的包一樣。商家們往柜架上塞滿充電寶,就好比是我們使用 NPM 安裝包一樣;消費(fèi)者它從充電寶柜子拿出來,就是調(diào)用。就是如此簡單

2.3 增加 ElasticSearch 開發(fā)包
在新增開發(fā)包的時候,要弄清楚兩個概念,一個是本地包,一個是全局包。
其實(shí)這兩個概念非常好理解。全局包,就是連鎖的咖啡店,比如星巴克。去每個城市,如果要喝咖啡,我肯定選擇星巴克,它的環(huán)境,口味還有價格都是一樣的。而本地包,就類似我家樓下的漫貓咖啡,只有我家樓下有,你家樓下可能就沒有,雖然味道好,收費(fèi)低,但不是每個城市都有。
所以,全局包,就是隨時隨地都可以調(diào)用的包;而本地包,就只能單獨(dú)地存在一個或幾個項(xiàng)目里。如果可以的話,我當(dāng)然想把通用的包,都安裝成全局包。
但事實(shí)上,基于項(xiàng)目的考慮,有安全因素,有空間使用約束,還是有一部分的包,必須安裝在本地。
下面就介紹下,本地包該怎么裝。
剛才說,本地包是單獨(dú)安裝在一個項(xiàng)目或多個項(xiàng)目里,本質(zhì)上,它就是項(xiàng)目的一部分,寄托于項(xiàng)目。沒有項(xiàng)目,也就沒有本地包。
所以,討論本地包,肯定是在一個具體的項(xiàng)目里來討論,比如微博,微信的留言區(qū)。留言區(qū)能留言是一個功能,但實(shí)際上留言區(qū)還有個特別有用的功能,那就是搜索。
如果我們需要搜索某個KOL的留言區(qū)輿論傾向,比如輸入【中國女排】,就該把所有留言中帶有【中國女排】的留言都展示出來。
就這么簡單的一個功能,我們使用 Nodejs 和 ElasticSearch 來完成。大致需要完成以下步驟:
安裝 Nodejs, ElasticSearch
把留言區(qū)留言導(dǎo)入 ElasticSearch
Nodejs編程,實(shí)現(xiàn)請求與響應(yīng)。
當(dāng)我們把 Nodejs 安裝完畢,ElasticSearch 配置完成并成功導(dǎo)入數(shù)據(jù)后,就需要配置 ElasticSearch 的開發(fā)包,這個開發(fā)包就是本地包。
首先,新建一個項(xiàng)目文件夾 CommentArea, 初始化 Nodejs 應(yīng)用項(xiàng)目:
[MySQLAdmin@centos00?CommentArea]$?npm?init?-y
Wrote?to?/home/MySQLAdmin/Downloads/nodejs/NodeProjects/CommentArea/package.json:
{
??"name":?"CommentArea",
??"version":?"1.0.0",
??"description":?"",
??"main":?"index.js",
??"scripts":?{
????"test":?"echo?\"Error:?no?test?specified\"?&&?exit?1"
??},
??"keywords":?[],
??"author":?"",
??"license":?"ISC"
}
執(zhí)行完畢之后,瀏覽 CommentArea,會發(fā)現(xiàn)多了一個 package.json. 該文件用來管理 nodejs 項(xiàng)目的各類信息,比如名稱,版本,啟動程序,本地包引用等等。
既然要連接到 ElasticSearch 數(shù)據(jù)庫,那么再正常不過的操作,就是要安裝 ElasticSearch 的開發(fā)客戶端。怎么安裝,兩種方法:
使用 NPM
指向本地存儲的 ElasticSearch 開發(fā)客戶端
使用 NPM
使用 NPM 是我們最先想到的辦法,既然 NPM 是包管理器,ElasticSearch 肯定會定期給 NPM 中心庫提供最新的開發(fā)客戶端,我們唯一要做的事情,就是使用 NPM install 來下載和安裝,并且通過 NPM 可以實(shí)現(xiàn)全自動安裝:
[MySQLAdmin@centos00?CommentArea]$?npm?install?elasticsearch
npm?notice?created?a?lockfile?as?package-lock.json.?You?should?commit?this?file.
npm?WARN?CommentArea@1.0.0?No?description
npm?WARN?CommentArea@1.0.0?No?repository?field.
+?elasticsearch@16.7.1
added?12?packages?from?6?contributors?and?audited?12?packages?in?9.808s
found?0?vulnerabilities
怎么知道 NPM 已經(jīng)裝好 ElasticSearch 的開發(fā)客戶端了呢?NPM List 來幫忙:
[MySQLAdmin@centos00?CommentArea]$?npm?list?
CommentArea@1.0.0?/home/MySQLAdmin/Downloads/nodejs/NodeProjects/CommentArea
└─┬?elasticsearch@16.7.1
??├─┬?agentkeepalive@3.5.2
??│?└─┬?humanize-ms@1.2.1
??│???└──?ms@2.1.2
??├─┬?chalk@1.1.3
??│?├──?ansi-styles@2.2.1
??│?├──?escape-string-regexp@1.0.5
??│?├─┬?has-ansi@2.0.0
??│?│?└──?ansi-regex@2.1.1
??│?├─┬?strip-ansi@3.0.1
??│?│?└──?ansi-regex@2.1.1?deduped
??│?└──?supports-color@2.0.0
??└──?lodash@4.17.20
[MySQLAdmin@centos00?CommentArea]$
再來看 package.json 發(fā)生了什么變化,理論上,package.json既然記錄了整個項(xiàng)目的變化,那么新加的本地包肯定也有反應(yīng):
{
??"name":?"CommentArea",
??"version":?"1.0.0",
??"description":?"",
??"main":?"index.js",
??"scripts":?{
????"test":?"echo?\"Error:?no?test?specified\"?&&?exit?1"
??},
??"keywords":?[],
??"author":?"",
??"license":?"ISC",
??"dependencies":?{
????"elasticsearch":?"^16.7.1"
??}
}
果不其然,在這里多了 dependencies 節(jié)點(diǎn),其中包含了 elasticsearch 的引用以及版本。
nodejs 與 ElasticSearch 交互
既然 ElasticSearch 的開發(fā)客戶端安裝完畢,那么肯定要用它來連下 ES,測試下是否能用:
const?{?Client?}?=?require("@elastic/elasticsearch")
const?client?=?new?Client({?node:?"http://localhost:9200"})
async?function?run()?{
????//?首先,模擬部分留言,加載到ES索引comment_area
????//?有位Lenis讀者留言:這是個學(xué)SQL的好地方
????await?client.index(
????????{
????????????index:"comment_area",
????????????body:{
????????????????reader:"Lenis",
????????????????comment:"this?place?is?great?to?learn?sql"
????????????}
????????}
????)
????//有位Huang讀者留言:我想學(xué)更多數(shù)據(jù)分析內(nèi)容
????await?client.index(
????????{
????????????index:"comment_area",
????????????body:{
????????????????reader:"Huang",
????????????????comment:"i?want?to?learn?more?on?data?analysis"
????????????}
????????}
????)
????//有位Jie讀者留言:SQL易學(xué)難精
????await?client.index(
????????{
????????????index:"comment_area",
????????????body:{
????????????????reader:"Jie",
????????????????comment:"sql?is?easy?to?learn,but?hard?to?sharppen"
????????????}
????????}
????)
????//保存留言到索引comment_area
????await?client.indices.refresh({
????????index:"comment_area"
????})
????//搜索含有sql關(guān)鍵字的留言
????const?{?body?}?=?await?client.search(
????????{
????????????index:"comment_area",
????????????body:{
????????????????query:{
????????????????????match:{
????????????????????????comment:"sql"
????????????????????}
????????????????}?
????????????}
????????}
????)
????//統(tǒng)計有sql關(guān)鍵字留言的條數(shù)
????console.log(body.hits.total)
}
run().catch(console.log)
調(diào)用 node index.js ,證明可用:
{?value:?2,?relation:?'eq'?}
好了,有用的Demo,骨架到此為止。你們看,是不是沒啥難度?
往期精彩:
