使用 nodejs 和 ElasticSearch 快速搭建全文检索

共 6938字,需浏览 14分钟

 ·

2020-10-20 05:35

点击蓝色“有关SQL”关注我哟

加个“星标”,天天与10000人一起快乐成长



上次群友问我,Python怎么学,我说四个小时足够了,你们不信。这次,我用2个小时,仅仅用Google,快速搭建了一个 nodejs + Elasticsearch 的小 Demo. 足可见,在有搜索的年代,快速上手一门技术,已经不是什么难事。

1 安装

1.1 下载地址

https://nodejs.org/en/download

提供 windows, Linux, MacOS 三大操作系统的安装包,选择适合自己开发机器或服务器版本。

不同操作系统版本,均有两种安装方式。

第一种使用系统自带安装工具,安装 nodejs, 好处是界面化操作,非常简易,麻烦的地方在于 Linux/Unix 上安装,你可能要找下安装工具,再适应下如何使用。

第二种不使用安装工具,直接解压 nodejs 压缩包,到指定文件夹目录,即可。它的好处是安装快速,且可以同时部署好多服务器,但复杂的地方是,你必须要熟悉解压缩,安装权限等命令。如果是远程安装,还要知道 shell, ssh 等命令。

1.2 安装

我选择部署的环境是 CentOS, 下载了 Linux Binaries(x64) 的压缩版。

完整的安装包是:node-v12.19.0-linux-x64.tar.xz

将其解压缩到 nodejs 文件夹,并配置环境变量,使其可以被直接调用。

这点对于Linux初学者非常有难度,如果不配置环境变量,那么直接运行 node 命令,就会出现找不到命令的错误。bash: node: command not found…
此时你会怀疑自己是不是哪里做错了,于是从头下一遍安装包,再装一遍,发现还是那样。于是就开始怀疑人生了。

配置环境变量,很简单:

PATH=$PATH:$HOME/.local/bin:$HOME/bin
NODE_PATH=/home/MySQLAdmin/Downloads/nodejs/nodejs/bin
PATH=$PATH:$NODE_PATH

export PATH

使用 source 命令,将新配置的环境变量,应用到当前的命令窗口:

[MySQLAdmin@centos00 ~]$ source .bash_profile

再次执行 node, 就变得丝滑柔顺了:

[MySQLAdmin@centos00 ~]$ node
Welcome to Node.js v12.19.0.
Type ".help" for more information.

1.3 新建应用

执行 node app.js 命令,就可以运行写在 app.js 文件中的程序了。整个过程也很简单,nodejs 监控发到指定端口上的请求,把相应的资源,数据,文件等发给请求。

举一个最简单的 Web 服务例子,当用户请求达到 3000 端口时,nodejs 程序返回 hello ,Welcome to Nodejs world 的消息:

image

实现这个目的,换了以前,我们要配置一堆技术栈,IIS/Apache,还要用上c#/vb.net/java,现在几行代码搞定:

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. 包的使用

开发过软件的朋友,都知道,不能把全部的鸡蛋都放一个篮子里。通常,遇到软件代码量很大,发生了臃肿的时候,我们会把这些软件部分抽象出来,已达到复用的效果。

那么抽象出来的这部分代码,通常会放在一个软件包里。这样不仅仅可以简化代码,更重要的是达到了可以多处复用,减少耦合的情况。

2.1 包的引用

nodejs 其实也一样,当我们要访问数据库的时候,不可能在 nodesjs 里面写好全部的数据库适配代码。所以需要数据库供应商提供相应的数据库驱动包和开发包,这样 nodejs 去调用这两部分包就可以。甚至这两部分包,还可以集成到一个包当中。

从第一小节最后一个例子中,我给出了一段简单的示例代码:

const http=require("http");

....

这里的 require 方法,给到一个参数值 http, 这个参数值,其实就是 nodejs 可以识别的包名。这段代码引用了 http 模块(包)。

2.2 包的管理

虽然 http 调用是很简单,一行代码就实现了。但回到数据库这个方向上,由于数据库的种类繁多,仅仅是RDBMS,关系型数据库就有很多种,MySQL, Oracle, DB2, SQL Server 等等,更别说一堆开源的NoSQL数据库。

如此之多的数据库,想要穷尽他们所有的驱动程序和开发包,几乎是不可能做到的事情。所以唯一能做到的方法,就是由数据库厂商自行开发可以被 nodejs 识别的包。这就涉及到 nodejs 对包的管理。

所以 NPM 就出场了。NPM, Node Package Manager, nodejs的包管理器。这是nodejs内置的管理器,一般来说 nodejs 安装的时候,就随之安装好了。

包管理器有了,那么包从哪里来,又安装到哪里去了呢?安装的时候,会不会很像 Linux 安装软件一样,那么复杂呢?其实一点也不。

朋友们,只要你想一下充电宝就知道了。满大街都是的充电宝,就像是 Nodejs 中用到的包一样。商家们往柜架上塞满充电宝,就好比是我们使用 NPM 安装包一样;消费者它从充电宝柜子拿出来,就是调用。就是如此简单

image

2.3 增加 ElasticSearch 开发包

在新增开发包的时候,要弄清楚两个概念,一个是本地包,一个是全局包。

其实这两个概念非常好理解。全局包,就是连锁的咖啡店,比如星巴克。去每个城市,如果要喝咖啡,我肯定选择星巴克,它的环境,口味还有价格都是一样的。而本地包,就类似我家楼下的漫猫咖啡,只有我家楼下有,你家楼下可能就没有,虽然味道好,收费低,但不是每个城市都有。

所以,全局包,就是随时随地都可以调用的包;而本地包,就只能单独地存在一个或几个项目里。如果可以的话,我当然想把通用的包,都安装成全局包。

但事实上,基于项目的考虑,有安全因素,有空间使用约束,还是有一部分的包,必须安装在本地。

下面就介绍下,本地包该怎么装。

刚才说,本地包是单独安装在一个项目或多个项目里,本质上,它就是项目的一部分,寄托于项目。没有项目,也就没有本地包。

所以,讨论本地包,肯定是在一个具体的项目里来讨论,比如微博,微信的留言区。留言区能留言是一个功能,但实际上留言区还有个特别有用的功能,那就是搜索。

如果我们需要搜索某个KOL的留言区舆论倾向,比如输入【中国女排】,就该把所有留言中带有【中国女排】的留言都展示出来。

就这么简单的一个功能,我们使用 Nodejs 和 ElasticSearch 来完成。大致需要完成以下步骤:

  1. 安装 Nodejs, ElasticSearch

  2. 把留言区留言导入 ElasticSearch

  3. Nodejs编程,实现请求与响应。

当我们把 Nodejs 安装完毕,ElasticSearch 配置完成并成功导入数据后,就需要配置 ElasticSearch 的开发包,这个开发包就是本地包。

首先,新建一个项目文件夹 CommentArea, 初始化 Nodejs 应用项目:

[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"
}

执行完毕之后,浏览 CommentArea,会发现多了一个 package.json. 该文件用来管理 nodejs 项目的各类信息,比如名称,版本,启动程序,本地包引用等等。

既然要连接到 ElasticSearch 数据库,那么再正常不过的操作,就是要安装 ElasticSearch 的开发客户端。怎么安装,两种方法:

  • 使用 NPM

  • 指向本地存储的 ElasticSearch 开发客户端

使用 NPM

使用 NPM 是我们最先想到的办法,既然 NPM 是包管理器,ElasticSearch 肯定会定期给 NPM 中心库提供最新的开发客户端,我们唯一要做的事情,就是使用 NPM install 来下载和安装,并且通过 NPM 可以实现全自动安装:

[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 已经装好 ElasticSearch 的开发客户端了呢?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 发生了什么变化,理论上,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",
  "dependencies": {
    "elasticsearch""^16.7.1"
  }
}

果不其然,在这里多了 dependencies 节点,其中包含了 elasticsearch 的引用以及版本。

nodejs 与 ElasticSearch 交互

既然 ElasticSearch 的开发客户端安装完毕,那么肯定要用它来连下 ES,测试下是否能用:

const { Client } = require("@elastic/elasticsearch")
const client = new Client({ node"http://localhost:9200"})


async function run({

    // 首先,模拟部分留言,加载到ES索引comment_area


    // 有位Lenis读者留言:这是个学SQL的好地方

    await client.index(
        {
            index:"comment_area",
            body:{
                reader:"Lenis",
                comment:"this place is great to learn sql"
            }
        }
    )

    //有位Huang读者留言:我想学更多数据分析内容

    await client.index(
        {
            index:"comment_area",
            body:{
                reader:"Huang",
                comment:"i want to learn more on data analysis"
            }
        }
    )

    //有位Jie读者留言:SQL易学难精

    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关键字的留言

    const { body } = await client.search(
        {
            index:"comment_area",
            body:{
                query:{
                    match:{
                        comment:"sql"
                    }
                } 
            }
        }
    )

    //统计有sql关键字留言的条数

    console.log(body.hits.total)


}

run().catch(console.log)

调用 node index.js ,证明可用:

value2, relation: 'eq' }

好了,有用的Demo,骨架到此为止。你们看,是不是没啥难度?



--完--





往期精彩:


本号精华合集(二)

如何写好 5000 行的 SQL 代码

如何提高阅读 SQL 源代码的快感

我在面试数据库工程师候选人时,常问的一些题

零基础 SQL 数据库小白,从入门到精通的学习路线与书单









浏览 26
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报