Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索
2022年6月12日 | by mebius
针对最新的 Elastic Stack 8.0,Nodejs 的客户端也进行了升级。在今天的文章中,我来介绍如何在 Nodejs 中来连接 Elasticsearch 并创建索引及搜索。最新的 Nodejs client 代码可以在 github 地址GitHub – elastic/elasticsearch-js: Official Elasticsearch client library for Node.js找到。
Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索
Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索_哔哩哔哩_bilibili
安装
我们可以通过如下的命令来进行安装:
npm install @npm:@elastic/elasticsearch@
如果我们不指定版本,我们可以通过如下的命令来进行安装。它可以帮我们安装最新的版本:
npm install npm:@elastic/elasticsearch
npm install config
npm install @elastic/elasticsearch
或者:
npm install es8@npm:@elastic/elasticsearch@8.1.0
在上面的命令中,es8 是我们的别名,而 8.1.0 是我们想要安装的版本。如果我们想要安装以前的版本,我们可以使用如下的命令:
npm install es6@npm:@elastic/elasticsearch@6
npm install es7@npm:@elastic/elasticsearch@7
如果你想安装最新的在 Elasticsearch main 分支上的客户端版本,你可以使用如下的命令:
npm install esmain@github:elastic/elasticsearch-js
我们一定要注意的是在 main 分支上的版本可能不是稳定的版本。请注意使用!
我们可以通过如下的命令来检查最新的版本:
$ npm list | grep elasticsearch
└── @elastic/elasticsearch@8.1.0
从上面的展示中,我们可以看到最新的版本是 8.1.0。
快速入门
我们创建一个目录,并在目录中使用如下的命令:
npm init -f
$ pwd
/Users/liuxg/nodejs/elasticsearch-js8
$ npm init -f
$ npm init -f
npm WARN using --force Recommended protections disabled.
Wrote to /Users/liuxg/nodejs/elasticsearch-js8/package.json:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo tgcode"Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
$ ls
package.json
我们可以在 package.json 修改 scripts 部分:
package.json
{
"name": "elasticsearch-js8",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@elastic/elasticsearch": "^8.1.0",
"es8": "npm:@elastic/elasticsearch@^8.1.0"
}
}
如上所示,在 main 中定义的是 index.js。我们来创建一个叫做 index.js 的文件。
Elasticsearch 集群不带有任何安全
我们可以参考文章 “如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch” 来安装 Elasticsearch。在我们的练习中,我将安装 Elasticsearch 8.1.2 版本。因为我们不想带有任何的安全,请参阅我的文章 “Elastic Stack 8.0 安装 – 保护你的 Elastic Stack 现在比以往任何时候都简单” 中的 “如何配置 Elasticsearch 不带安全性” 章节。
连接到 Elasticsearch
我们还是尝试按照之前文章 “Elasticsearch:Elasticsearch 开发入门 – Nodejs” 介绍的那样来试试:
index.js
const es = require('@elastic/elasticsearch');
const client = es.Client({ host: 'http://localhost:9200' });
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
我们使用如下的命令来进行运行:
npm start
我们可以看到如下的错误信息:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
/Users/liuxg/nodejs/elasticsearch-js8/index.js:2
const client = es.Client({ host: 'http://localhost:9200' });
^
TypeError: Class constructor Client cannot be invoked without 'new'
at Object. (/Users/liuxg/nodejs/elasticsearch-js8/index.js:2:19)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
Node.js v17.4.0
这说明了,我们的 Nodejs client API 已经发生改变了。我们需要重新修正我们的代码:
index.js
const { Client } = require('es8');
const client = new Client ( {node: 'http://localhost:9200' });
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
我们运行上面的代码:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
它显示我们的连接是成功的。请注意在上面,我们使用了别名 es8。这个是我们在安装 elasticsearch 包时定以的。
创建索引及搜索
关于 API 的描述可以在地址:elasticsearch-js/src/api/api at main elastic/elasticsearch-js GitHub看到。一旦我们能成功地连接到 Elasticsearch,我们可以使用如下的命令来创建一个索引:
index.js
const { Client } = require('es8');
const client = new Client ( {node: 'http://localhost:9200' });
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
await client.index({
index: INDEX_NAME,
document: {
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
})
// here we are forcing an index refresh, otherwise we will not
// get any result in the consequent search
await client.indices.refresh({ index: INDEX_NAME })
// Let's search!
const result= await client.search({
index: INDEX_NAME,
query: {
match: { first_name : 'nitin' }
}
})
console.log(result.hits.hits)
}
run().catch(console.log)
在上面的代码中,我们使用 index 的方法来写入数据。它们相当于如下的命令:
PUT megacorp/_doc/1
{
"first_name": "nitin",
"last_name": "panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
POST megacorp/_doc
{
"first_name": "Jane",
"last_name": "Smith",
"age": 32,
"about": "I like to collect rock albums",
"interests": [
"music"
]
}
在第一个命令中,我们指定文档的 id,而在第二个命令中,我们让 Elasticsearch 生成一个 id。运行完上面的代码后,我们可以看到如下的输出:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
[
{
_index: 'megacorp',
_id: '1',
_score: 0.6931471,
_source: {
first_name: 'nitin',
last_name: 'panwar',
age: 27,
about: 'Love to play cricket',
interests: [Array]
}
}
]
在上面,我们看到一个搜索结果的输出。在代码中的搜索:
// Let's search!
const result= await client.search({
index: INDEX_NAME,
query: {
match: { first_name : 'nitin' }
}
})
相当于如下的搜索命令:
GET megacorp/_search?filter_path=**.hits
{
"query": {
"match": {
"first_name": "nitin"
}
}
}
我们可以在 Kibana 中查看写入的文档:
上面显示写入的两个文档。其中的一个文档的 id 已经被指定为 1。
我们也可以写一些比较复杂一点的搜索,比如:
index.js
const { Client } = require('es8');
const client = new Client ( {node: 'http://localhost:9200' });
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's search!
const result= await client.search({
index: INDEX_NAME,
query: {
"bool": {
"must": [
{
"match": {
"first_name": "nitin"
}
}
tgcode ],
"should": [
{
"range": {
"age": {
"gte": 40
}
}
}
]
}
}
})
console.log(result.hits.hits)
}
run().catch(console.log)
上面的搜索相当于如下的命令:
GET megacorp/_search?filter_path=**.hits
{
"query": {
"bool": {
"must": [
{
"match": {
"first_name": "nitin"
}
}
],
"should": [
{
"range": {
"age": {
"gte": 40
}
}
}
]
}
}
}
我们也可以获得一个文档:
index.js
const { Client } = require('es8');
const client = new Client ( {node: 'http://localhost:9200' });
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
const result = await client.get({
index: INDEX_NAME,
id: 1
})
console.log(result)
}
run().catch(console.log)
运行上面的代码,我们可以看到:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
{
_index: 'megacorp',
_id: '1',
_version: 1,
_seq_no: 0,
_primary_term: 1,
found: true,
_source: {
first_name: 'nitin',
last_name: 'panwar',
age: 27,
about: 'Love to play cricket',
interests: [ 'sports', 'music' ]
}
}
connection success true
显然,它输出了我们想要的搜索的结果。
我们也可以删除一个文档。在下面的代码中,我们删除 id 为 1 的文档:
index.js
const { Client } = require('es8');
const client = new Client ( {node: 'http://localhost:9200' });
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
const result = await client.delete({
index: INDEX_NAME,
id: 1
})
console.log(result)
}
run().catch(console.log)
运行上面的代码:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
{
_index: 'megacorp',
_id: '1',
_version: 2,
result: 'deleted',
_shards: { total: 2, successful: 1, failed: 0 },
_seq_no: 2,
_primary_term: 1
}
上面显示,我们已经成功地删除了这个文档。我们可以到 Kibana 中搜索这个 id 为 1 的文档。我们会发现该文档不存在:
GET megacorp/_doc/1
{
"_index" : "megacorp",
"_id" : "1",
"found" : false
}
更多 API 的使用请参阅文章elasticsearch-js/src/api/api at main elastic/elasticsearch-js GitHub
带有基本安全的 Elasticsearch 集群(不含 HTTPS)
在有些情况下,我们的集群带有基本安全,但是不含有 HTTPS。那么在这种情况下,我们该如何进行连接呢?我们可以参考文章 “Elastic Stack 8.0 安装 – 保护你的 Elastic Stack 现在比以往任何时候都简单” 中的 “如何配置 Elasticsearch 只带有基本安全” 来进行配置。为了说明问题方便,我把 elastic 超级用户的密码设置为 password。
由于添加了用户安全,我们必须修改我们的代码:
index.js
const { Client } = require('es8');
const client = new Client ( {
node: 'http://localhost:9200',
auth: {
username: "elastic",
password: "password"
}
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = cawait client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(console.log)
在上面,在连接 Elasticsearch 时,我们使用 auth 来定义自己的账号信息:
const client = new Client ( {
node: 'http://localhost:9200',
auth: {
username: "elastic",
password: "password"
}
});
运行上面的代码,我们可以看到如下的结果:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
{
_index: 'megacorp',
_id: '1',
_version: 1,
result: 'created',
_shards: { total: 2, successful: 1, failed: 0 },
_seq_no: 0,
_primary_term: 1
}
从上面的输出结果中,我们可以看出来,我们的连接是成功的。
在实际的使用中,我们甚至可以简化为:
index.js
const { Client } = require('es8');
const client = new Client ( {
node: 'http://elastic:password@localhost:9200'
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(console.log)
在上面,我们把用户信息放到 node 的 url 中。运行上面的代码,我们可以得到同样的结果。
在实际的使用中,我们甚至可以使用 API key 来进行连接。关于如何创建 API key,我们可以参考我之前的文章 “Elasticsearch:创建 API key 接口访问 Elasticsearch”。我们可以创建一个 API key,然后使用如下的方式来访问:
我们把上面生成的 Base64 API key 拷贝到如下的代码中:
index.js
const { Client } = require('es8');
const client = new Client ( {
node: 'http://localhost:9200',
auth: { apiKey: "Zm5SdVM0QUJrdHVZQUpLLWRudDU6Z0pxSW1sdFZSdDJKTmlndXg0eFh1dw==" }
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(console.log)
运行上面的代码,我们可以看到:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
{
_index: 'megacorp',
_id: '1',
_version: 3,
result: 'updated',
_shards: { total: 2, successful: 1, failed: 0 },
_seq_no: 2,
_primary_term: 1
}
它说明我们的连接是成功的。
带有 HTTPS 的 Elasticsearch 集群
在有的时候,我们的集群带有 HTTPS,而且证书是自签名的。这种情况适用于自托管类型的 Elasticsearch 集群。我们可以参考文章 “Elastic Stack 8.0 安装 – 保护你的 Elastic Stack 现在比以往任何时候都简单” 来安装自己的集群。
在 Elasticsearch 启动的过程中,我们需要注意如下的输出:
我们需要记下超级用户 elastic 的密码。我们修改代码如下:
index.js
const { Client } = require('es8');
const fs = require('fs')
const client = new Client ( {
node: 'https://localhost:9200',
auth: {
username: "elastic",
password: "prJ6hMjqVdQwCD8LEH-*"
},
tls: {
ca: fs.readFileSync('/Users/liuxg/test/elasticsearch-8.1.2/config/certs/http_ca.crt'),
rejectUnauthorized: true
}
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(console.log)
请根据自己的配置修改在代码中如下的部分:
const client = new Client ( {
node: 'https://localhost:9200',
auth: {
username: "elastic",
password: "prJ6hMjqVdQwCD8LEH-*"
},
tls: {
ca: fs.readFileSync('/Users/liuxg/test/elasticsearch-8.1.2/config/certs/http_ca.crt'),
rejectUnauthorized: true
}
});
运行我们的代码:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
{
_index: 'megacorp',
_id: '1',
_version: 2,
result: 'updated',
_shards: { total: 2, successful: 1, failed: 0 },
_seq_no: 1,
_primary_term: 1
}
显然我们的连接是成功的。
我们也可以尝试使用 fingerprint 来进行连接。我们使用如下的命令来获得 fingerprint:
openssl x509 -fingerprint -sha256 -in config/certs/http_ca.crt
我们把代码修改如下:
index.js
const { Client } = require('es8');
const fs = require('fs')
const client = new Client ( {
node: 'https://localhost:9200',
auth: {
username: "elastic",
password: "prJ6hMjqVdQwCD8LEH-*"
},
caFingerprint: "E5:E9:FE:62:DC:A6:6F:40:67:3A:55:CF:0E:32:25:AC:1A:3C:04:FD:08:91:27:5D:09:23:B6:B5:84:A8:AE:6A",
tls: {
rejectUnauthorized: false
}
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(console.log)
如果你的证书是签过名的,你可以修改上面的rejectUnauthorized 为 true。
当然,我们也可以使用 API key 来进行访问:
index.js
const { Client } = require('es8');
const fs = require('fs')
const client = new Client ( {
node: 'https://localhost:9200',
auth: {
apiKey: "YUtxS1M0QUJBdU1aNGY4azAwNks6TnRSYllIX2VUNWVXMUllVk9lYUZDZw=="
},
tls: {
ca: fs.readFileSync('/Users/liuxg/test/elasticsearch-8.1.2/config/certs/http_ca.crt'),
rejectUnauthorized: true
}
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(console.log)
在上面我们使用 API key 的方法而不使用用户名及密码的方式来进行访问。针对 API key,我们还有另外一种访问方式:
POST /_security/api_key
{
"name": "liuxg-api-key",
"expiration": "7d"
}
{
"id" : "bqqsS4ABAuMZ4f8k7E6I",
"name" : "liuxg-api-key",
"expiration" : 1651141865609,
"api_key" : "2KVQCwyNTS295mOqPrthrA",
"encoded" : "YnFxc1M0QUJBdU1aNGY4azdFNkk6MktWUUN3eU5UUzI5NW1PcVBydGhyQQ=="
}
index.js
const { Client } = require('es8');
const fs = require('fs')
const client = new Client ( {
node: 'https://localhost:9200',
auth: {
apiKey: {
id: "bqqsS4ABAuMZ4f8k7E6I",
api_key: "2KVQCwyNTS295mOqPrthrA"
}
},
tls: {
ca: fs.readFileSync('/Users/liuxg/test/elasticsearch-8.1.2/config/certs/http_ca.crt'),
rejectUnauthorized: true
}
});
client.ping()
.then(res => console.log('connection success', res))
.catch(err => console.error('wrong connection', err));
const INDEX_NAME = "megacorp";
async function run () {
// Let's start by indexing some data
const result = await client.index({
index: INDEX_NAME,
id: 1,
document: {
"first_name":"nitin",
"last_name":"panwar",
"age": 27,
"about": "Love to play cricket",
"interests": ["sports","music"]
}
})
console.log(result)
}
run().catch(ctgcodeonsole.log)
运行上面的代码:
$ npm start
> elasticsearch-js8@1.0.0 start
> node index.js
connection success true
{
_index: 'megacorp',
_id: '1',
_version: 5,
result: 'updated',
_shards: { total: 2, successful: 1, failed: 0 },
_seq_no: 4,
_primary_term: 1
}
从上面的输出中,我们可以看出来连接是成功的。
参考:
【1】Ingest data with Node.js on Elasticsearch Service | Elasticsearch Service Documentation | Elastic
【2】Introduction | Elasticsearch JavaScript Client [8.1] | Elastic
文章来源于互联网:Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索
在我之前的文章 “Elastic:使用 Elastic Stack 进行异常值检测 – airbnb 数据分析”,我详细地描述了如何在地图中对异常进行可视化。在另外一篇文章 “Elastic:机器学习异常的可视化呈现”,我详述了如何使用 TSVB 来对异常进行…