Node.js 操作 Elasticsearch (ES) 的指南
h5打开以查看
一、核心概念与安装
1. 官方客户端
Elasticsearch 官方提供了 @elastic/elasticsearch
Node.js 客户端,这是目前最推荐、最权威的库。
2. 安装
使用 npm 或 yarn 进行安装:
bash
npm install @elastic/elasticsearch # 或 yarn add @elastic/elasticsearch
二、连接 Elasticsearch 客户端
你需要获取 Elasticsearch 集群的地址和认证信息(如果启用了安全特性)来创建客户端实例。
基本连接(无安全认证)
javascript
const { Client } = require('@elastic/elasticsearch');const client = new Client({node: 'http://localhost:9200', // ES 节点的地址,默认端口是 9200// 如果集群有多个节点,可以放入一个数组// nodes: ['http://node1:9200', 'http://node2:9200'], });// 测试连接 async function checkConnection() {try {const health = await client.cluster.health();console.log('Elasticsearch 集群健康状态:', health.status);} catch (error) {console.error('连接 Elasticsearch 失败:', error.message);} }checkConnection();
带安全认证的连接(API Key/用户名密码/Cloud ID)
使用 API Key (推荐)
javascript
const client = new Client({node: 'https://your-es-cluster.com:9200',auth: {apiKey: 'your-base64-encoded-api-key' // 例如: 'a2V5LWlkOmFwaS1rZXk='} });
使用用户名和密码
javascript
const client = new Client({node: 'https://your-es-cluster.com:9200',auth: {username: 'elastic', // 或其他用户名password: 'your-password'} });
连接 Elastic Cloud
javascript
const client = new Client({cloud: {id: 'your-cloud-id-from-elastic-cloud',},auth: {username: 'elastic',password: 'your-password'} });
三、基本操作 (CRUD)
我们以一个 products
索引为例,文档类型为 _doc
。
1. 创建索引 (Create Index)
通常不需要手动创建,在插入第一条数据时会自动创建。但也可以显式创建以指定映射。
javascript
async function createIndex() {await client.indices.create({index: 'products',body: {mappings: {properties: {name: { type: 'text' },price: { type: 'float' },description: { type: 'text' },createdAt: { type: 'date' }}}}});console.log('索引创建成功'); } // createIndex().catch(console.error);
2. 索引文档 (Index - Create/Replace)
index
方法会自动创建或全量替换文档。如果指定 id
已存在,则替换。
javascript
async function indexProduct() {const response = await client.index({index: 'products',id: '1', // 如果不指定 id,ES 会自动生成一个body: {name: 'iPhone 13',price: 799.99,description: 'A great phone from Apple.',createdAt: new Date()}});console.log('文档索引成功:', response.body._id); } // indexProduct().catch(console.error);
3. 创建文档 (Create - 必须不存在)
create
方法要求文档 ID 必须不存在,否则会失败。
javascript
async function createProduct() {const response = await client.create({index: 'products',id: '2', // 如果 id=2 已存在,此操作会报错body: {name: 'Samsung Galaxy',price: 699.99,description: 'A powerful Android phone.'}});console.log('文档创建成功:', response.body._id); }
4. 读取文档 (Read)
javascript
async function getProduct() {try {const response = await client.get({index: 'products',id: '1'});console.log('找到文档:', response.body._source);} catch (error) {if (error.meta.statusCode === 404) {console.log('文档不存在');} else {throw error;}} } // getProduct().catch(console.error);
5. 更新文档 (Update)
使用 update
进行部分更新,性能更好。
javascript
async function updateProduct() {const response = await client.update({index: 'products',id: '1',body: {doc: { // 要更新的字段放在 `doc` 里price: 749.99 // 只更新价格字段}}});console.log('文档更新成功'); } // updateProduct().catch(console.error);
6. 删除文档 (Delete)
javascript
async function deleteProduct() {const response = await client.delete({index: 'products',id: '2'});console.log('文档删除成功'); } // deleteProduct().catch(console.error);
四、搜索操作 (Search)
这是 Elasticsearch 最强大的功能。
1. 简单搜索 (Match Query)
javascript
async function searchProducts() {const response = await client.search({index: 'products',body: {query: {match: { name: 'iPhone' // 在 `name` 字段中搜索 "iPhone"}},// 高亮显示匹配内容highlight: {fields: {name: {}}},// 排序sort: [{ price: { order: 'desc' } }],// 分页from: 0,size: 10}});console.log(`共找到 ${response.body.hits.total.value} 条结果:`);response.body.hits.hits.forEach(hit => {console.log(`- ${hit._source.name} ($${hit._source.price})`);// 如果有高亮结果if (hit.highlight) {console.log(' 高亮:', hit.highlight.name);}}); } // searchProducts().catch(console.error);
2. 布尔搜索 (Bool Query)
组合多个查询条件(must=AND, should=OR, must_not=NOT)。
javascript
async function boolSearch() {const response = await client.search({index: 'products',body: {query: {bool: {must: [ // 必须同时满足{ match: { description: 'phone' } }],filter: [ // 过滤,不贡献得分{ range: { price: { gte: 500, lte: 800 } } }],must_not: [ // 必须不满足{ match: { name: 'Samsung' } }]}}}});// ... 处理结果 }
3. 聚合分析 (Aggregations)
javascript
async function runAggregation() {const response = await client.search({index: 'products',body: {aggs: { // 定义聚合avg_price: { // 平均价格聚合avg: { field: 'price' }},price_ranges: { // 范围聚合range: {field: 'price',ranges: [{ to: 500 },{ from: 500, to: 800 },{ from: 800 }]}}},size: 0 // 不返回原始命中结果,只返回聚合结果}});console.log('平均价格:', response.body.aggregations.avg_price.value);console.log('价格分布:', response.body.aggregations.price_ranges.buckets); } // runAggregation().catch(console.error);
五、批量操作 (Bulk API)
对于大量数据的导入或更新,使用 Bulk API 可以极大提升效率。
javascript
async function bulkIndex() {const body = [];const dataset = [{ id: 100, name: 'Product A', price: 100 },{ id: 101, name: 'Product B', price: 200 },// ... 更多数据];// 构建 Bulk 请求体dataset.forEach(doc => {body.push({ index: { _index: 'products', _id: doc.id } }); // 操作定义body.push(doc); // 文档源数据});const { body: bulkResponse } = await client.bulk({ body, refresh: true });if (bulkResponse.errors) {console.error('批量操作中有错误:', bulkResponse.errors);} else {console.log('批量操作成功');} } // bulkIndex().catch(console.error);
六、最佳实践与错误处理
-
单例模式: 在整个应用中,通常只需要一个 Elasticsearch 客户端实例。请重用这个实例。
-
异步/await: 客户端所有 API 都返回 Promise,强烈建议使用
async/await
或.then().catch()
处理。 -
错误处理: 一定要用
try...catch
包裹操作,并检查错误状态码。 -
关闭连接: 在应用退出时,优雅地关闭客户端。
javascript
// 例如,在 Express 应用关闭时 process.on('SIGTERM', async () => {await client.close();process.exit(0); });
-
使用最新版本: 确保客户端版本与 Elasticsearch 服务器版本兼容(通常主版本号相同即可,如 8.x 客户端连接 8.x 服务端)。
这份指南涵盖了 Node.js 操作 Elasticsearch 的绝大多数常见场景
h5打开以查看