Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索

Posted Elastic 中国社区官方博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索相关的知识,希望对你有一定的参考价值。

针对最新的 Elastic Stack 8.0,Nodejs 的客户端也进行了升级。在今天的文章中,我来介绍如何在 Nodejs 中来连接 Elasticsearch 并创建索引及搜索。最新的 Nodejs client 代码可以在 github 地址 GitHub - elastic/elasticsearch-js: Official Elasticsearch client library for Node.js 找到。

安装

我们可以通过如下的命令来进行安装:

npm install <alias>@npm:@elastic/elasticsearch@<version>

如果我们不指定版本,我们可以通过如下的命令来进行安装。它可以帮我们安装最新的版本:

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 WARN using --force Recommended protections disabled.
Wrote to /Users/liuxg/nodejs/elasticsearch-js8/package.json:


  "name": "elasticsearch-js8",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": 
    "test": "echo \\"Error: no test specified\\" && exit 1"
  ,
  "repository": 
    "type": "git",
    "url": "git+https://github.com/liu-xiao-guo/elasticsearch-js.git"
  ,
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": 
    "url": "https://github.com/liu-xiao-guo/elasticsearch-js/issues"
  ,
  "homepage": "https://github.com/liu-xiao-guo/elasticsearch-js#readme"



$ ls
package.json

我们可以在 package.json 修改 scripts 部分:

package.json


  "name": "elasticsearch-js8",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": 
    "start": "node index.js"
  ,
  "repository": 
    "type": "git",
    "url": "git+https://github.com/liu-xiao-guo/elasticsearch-js.git"
  ,
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": 
    "url": "https://github.com/liu-xiao-guo/elasticsearch-js/issues"
  ,
  "homepage": "https://github.com/liu-xiao-guo/elasticsearch-js#readme"

如上所示,在 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.<anonymous> (/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"
            
          
        ],
        "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",c
      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",c
      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(console.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 来创建索引并搜索的主要内容,如果未能解决你的问题,请参考以下文章

如何配置elasticsearch testcontainers 使用最新的ES

NodeJ中的密码术(SHA-1?)

最新版本elasticsearch本地搭建入门篇

Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索

“nvm ls”不显示任何已安装的 NodeJ

Elasticsearch:使用最新的 Python client 8.0 来创建索引并搜索