在 JavaScript 中正确使用 Elasticsearch,第二部分

作者:来自 Elastic Jeffrey Rengifo

回顾生产环境中的最佳实践,并讲解如何在无服务器环境中运行 Elasticsearch Node.js 客户端。

想获得 Elastic 认证?查看下一期 Elasticsearch Engineer 培训的时间!

Elasticsearch 拥有大量新功能,能帮助你为你的使用场景构建最佳搜索解决方案。深入查看我们的示例笔记本,了解更多信息,开始免费云试用,或立即在本地机器上试用 Elastic。


这是我们 Elasticsearch in JavaScript 系列的第二部分。在第一部分中,我们学习了如何正确设置环境、配置 Node.js 客户端、索引数据以及进行搜索。在第二部分中,我们将学习如何实现生产环境中的最佳实践,并在无服务器环境中运行 Elasticsearch Node.js 客户端。

我们将回顾

  • 生产环境最佳实践
    • 错误处理
    • 测试
  • 无服务器环境
    • 在 Elastic Serverless 上运行客户端
    • 在函数即服务环境中运行客户端

你可以在这里查看包含示例的源代码。

生产环境最佳实践

错误处理

Elasticsearch 的 Node.js 客户端的一个有用功能是,它会暴露出可能出现的 Elasticsearch 错误对象,这样你就可以用不同的方式进行验证和处理。

要查看所有错误对象,运行以下命令:

const { errors } = require('@elastic/elasticsearch')
console.log(errors)

让我们回到搜索示例,处理一些可能出现的错误:

app.get("/search/lexic", async (req, res) => {....} catch (error) {if (error instanceof errors.ResponseError) {let errorMessage ="Response error!, query malformed or server down, contact the administrator!";if (error.body.error.type === "parsing_exception") {errorMessage = "Query malformed, make sure mappings are set correctly";}res.status(error.meta.statusCode).json({erroStatus: error.meta.statusCode,success: false,results: null,error: errorMessage,});}res.status(500).json({success: false,results: null,error: error.message,});}
});

特别是 ResponseError,会在响应为 4xx 或 5xx 时出现,意味着请求不正确或服务器不可用。

我们可以通过生成错误的查询来测试这种类型的错误,比如尝试在 text 类型字段上执行 term 查询:

默认错误:

{"success": false,"results": null,"error": "parsing_exception\n\tRoot causes:\n\t\tparsing_exception: [terms] query does not support [visit_details]"
}

自定义错误:

{"erroStatus": 400,"success": false,"results": null,"error": "Response error!, query malformed or server down; contact the administrator!"
}

我们也可以以特定方式捕捉和处理每种类型的错误。例如,我们可以在出现 TimeoutError 时添加重试逻辑。

app.get("/search/semantic", async (req, res) => {try {...} catch (error) {if (error instanceof errors.TimeoutError) {// Retry logic...res.status(error.meta.statusCode).json({erroStatus: error.meta.statusCode,success: false,results: null,error:"The request took more than 10s after 3 retries. Try again later.",});}}
});

测试

测试是保障应用稳定性的关键。为了在与 Elasticsearch 隔离的情况下测试代码,我们可以在创建集群时使用库 elasticsearch-js-mock。

这个库允许我们实例化一个与真实客户端非常相似的客户端,但它会根据我们的配置进行响应,只替换客户端的 HTTP 层为模拟层,其他部分保持与原始客户端一致。

我们将安装 mocks 库和用于自动化测试的 AVA。

npm install @elastic/elasticsearch-mocknpm install --save-dev ava

我们将配置 package.json 文件来运行测试。确保它如下所示:

"type": "module","scripts": {"test": "ava"},"devDependencies": {"ava": "^5.0.0"}

现在让我们创建一个 test.js 文件并安装我们的模拟客户端:

const { Client } = require('@elastic/elasticsearch')
const Mock = require('@elastic/elasticsearch-mock')const mock = new Mock()
const client = new Client({node: 'http://localhost:9200',Connection: mock.getConnection()
})

现在,添加一个语义搜索的模拟:

function createSemanticSearchMock(query, indexName) {mock.add({method: "POST",path: `/${indexName}/_search`,body: {query: {semantic: {field: "semantic_field",query: query,},},},},() => {return {hits: {total: { value: 2, relation: "eq" },hits: [{_id: "1",_score: 0.9,_source: {owner_name: "Alice Johnson",pet_name: "Buddy",species: "Dog",breed: "Golden Retriever",vaccination_history: ["Rabies", "Parvovirus", "Distemper"],visit_details:"Annual check-up and nail trimming. Healthy and active.",},},{_id: "2",_score: 0.7,_source: {owner_name: "Daniel Kim",pet_name: "Mochi",species: "Rabbit",breed: "Mixed",vaccination_history: [],visit_details:"Nail trimming and general health check. No issues.",},},],},};});
}

现在,我们可以为代码创建一个测试,确保 Elasticsearch 部分始终返回相同的结果:

import test from 'ava';test("performSemanticSearch must return formatted results correctly", async (t) => {const indexName = "vet-visits";const query = "Which pets had nail trimming?";createSemanticSearchMock(query, indexName);async function performSemanticSearch(esClient, q, indexName = "vet-visits") {try {const result = await esClient.search({index: indexName,body: {query: {semantic: {field: "semantic_field",query: q,},},},});return {success: true,results: result.hits.hits,};} catch (error) {if (error instanceof errors.TimeoutError) {return {success: false,results: null,error: error.body.error.reason,};}return {success: false,results: null,error: error.message,};}}const result = await performSemanticSearch(esClient, query, indexName);t.true(result.success, "The search must be successful");t.true(Array.isArray(result.results), "The results must be an array");if (result.results.length > 0) {t.true("_source" in result.results[0],"Each result must have a _source property");t.true("pet_name" in result.results[0]._source,"Results must include the pet_name field");t.true("visit_details" in result.results[0]._source,"Results must include the visit_details field");}
});

让我们运行测试。

npm run test

完成!从现在起,我们可以 100% 专注于代码本身进行测试,而不受外部因素影响。

无服务器环境

在 Elastic Serverless 上运行客户端

我们之前讲过在 Cloud 或本地运行 Elasticsearch;不过,Node.js 客户端也支持连接到 Elastic Cloud Serverless。

Elastic Cloud Serverless 允许你创建项目,无需担心基础设施,因为 Elastic 会内部处理,你只需关注要索引的数据及其保留时长。

从使用角度看,Serverless 将计算和存储解耦,为搜索和索引提供自动扩展功能,这样你只需扩展实际需要的资源。

客户端对连接 Serverless 做了以下适配:

  • 关闭嗅探(sniffing)功能,忽略所有与嗅探相关的选项
  • 忽略配置中除第一个节点外的所有节点,忽略任何节点过滤和选择选项
  • 启用压缩和 TLSv1_2_method(与配置 Elastic Cloud 时相同)
  • 为所有请求添加 elastic-api-version HTTP 头
  • 默认使用 CloudConnectionPool,而非 WeightedConnectionPool
  • 关闭内置的 content-typeaccept 头,使用标准 MIME 类型

连接无服务器项目时,需要使用参数 serverMode: serverless

const { Client } = require('@elastic/elasticsearch')
const client = new Client({node: 'ELASTICSEARCH_ENDPOINT',auth: { apiKey: 'ELASTICSEARCH_API_KEY' },serverMode: "serverless",
});

在函数即服务(function-as-a-service)环境中运行客户端

在示例中,我们使用了 Node.js 服务器,但你也可以使用函数即服务环境连接,比如 AWS Lambda、GCP Run 等函数。

'use strict'const { Client } = require('@elastic/elasticsearch')const client = new Client({// client initialisation
})exports.handler = async function (event, context) {// use the client
}

另一个例子是连接到像 Vercel 这样的无服务器服务。你可以查看这个完整示例,了解如何操作,但搜索端点中最相关的部分如下:

const response = await client.search({index: INDEX,// You could directly send from the browser// the Elasticsearch's query DSL, but it will// expose you to the risk that a malicious user// could overload your cluster by crafting// expensive queries.query: {match: { field: req.body.text },},},{headers: {Authorization: `ApiKey ${token}`,},}
);

该端点位于 /api 文件夹中,从服务器端运行,这样客户端只控制对应搜索词的 “text” 参数。

使用函数即服务的意义在于,与 24/7 运行的服务器不同,函数只在运行时启动机器,完成后机器进入休眠状态,减少资源消耗。

如果应用请求不多,这种配置很方便;否则成本可能较高。你还需考虑函数的生命周期和运行时间(有时仅几秒)。

总结

本文中,我们学习了如何处理错误,这在生产环境中至关重要。还介绍了如何在模拟 Elasticsearch 服务的情况下测试应用,这样测试更可靠,不受集群状态影响,能专注于代码。

最后,我们演示了如何通过配置 Elastic Cloud Serverless 和 Vercel 应用,搭建完全无服务器的架构。

原文:Elasticsearch in JavaScript the proper way, part II - Elasticsearch Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/906360.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年网站安全防御全解析:应对DDoS与CC攻击的智能策略

2025年,随着AI技术与物联网设备的深度融合,DDoS与CC攻击的规模与复杂度持续升级。攻击者不仅利用T级流量洪泛冲击带宽,还通过生成式AI伪造用户行为,绕过传统防御规则。如何在保障业务高可用的同时抵御混合型攻击?本文将…

window 安装 wsl + cuda + Docker

WSL 部分参考这里安装: Windows安装WSL2 Ubuntu环境 - 知乎 如果出现错误: WslRegisterDistribution failed with error: 0x800701bc 需要运行:https://crayon-shin-chan.blog.csdn.net/article/details/122994190 wsl --update wsl --shu…

《MambaLLIE:基于隐式Retinex感知的低光照增强框架与全局-局部状态空间建模》学习笔记

Paper:2405.16105 Github:GitHub - wengjiangwei/MambaLLIE 目录 摘要 一、介绍 二、相关工作 2.1 低光图像增强 2.2 视觉空间状态模型 三、方法 3.1 预备知识 3.2 整体流程 3.3 全局优先-局部次之状态空间块 四、实验 4.1 基准数据集与实施细节 4.2 对比实验 4…

微信小程序:封装request请求、解决请求路径问题

一、创建文件 1、创建请求文件 创建工具类文件request.js,目的是用于发送请求 二、js接口封装 1、写入接口路径 创建一个变量BASE_URL专门存储api请求地址 2、获取全局的token变量 从缓存中取出token的数据 3、执行请求 (1)方法中接收传递的参数 function request(url,…

【单机版OCR】清华TH-OCR v9.0免费版

今天向大家介绍一款非常好用的单机版OCR图文识别软件,它不仅功能多,识别能力强,而且还是免费使用的。OCR软件为什么要使用单机版,懂得都懂,因为如果使用在线识别的OCR软件,用户需要将文档上传互联网服务器的…

开源情报搜集系统:科研创新的强大引擎

一、引言 在当今全球化和信息化高度发展的时代,科研活动面临着前所未有的机遇与挑战。一方面,知识的更新换代速度极快,科研成果如雨后春笋般不断涌现;另一方面,科研竞争日益激烈,如何在众多科研团队中脱颖…

产品生命周期不同阶段的营销策略

产品生命周期的不同阶段(导入期、成长期、成熟期、衰退期)需要匹配差异化的营销策略。以下是各阶段的营销重点及具体策略: 1. 导入期(Introduction Stage) 核心目标:建立市场认知,快速触达目标…

Mujoco 学习系列(二)基础功能与xml使用

这篇文章是 Mujoco 学习系列第二篇,主要介绍一些基础功能与 xmI 使用,重点在于如何编写与读懂 xml 文件。 运行这篇博客前请先确保正确安装 Mujoco 并通过了基本功能与GUI的验证,即至少完整下面这个博客的 第二章节 内容: Mujoc…

面向SDV的在环测试深度解析——仿真中间件SIL KIT应用篇

1.引言 在汽车行业向软件定义汽车(SDV)转型的过程中,传统硬件在环(HIL)测试方案因难以适应新的技术架构与需求,其局限性日益凸显。传统HIL对硬件依赖性强,扩展性差,更换ECU或传感器…

windows使用anaconda安装pytorch cuda版本

Windows安装PytorchCUDA环境_使用conda安装pytorch cuda10.2版本-CSDN博客

Axure中使用动态面板实现图标拖动交换位置

要在Axure中实现图标拖动交换位置的功能,可以通过动态面板结合交互事件来实现。 实现步骤 准备图标元素 将每个图标转换为动态面板(方便拖动和交互)。 设置拖动交互 选中图标动态面板 → 添加“拖动时”交互 → 选择“移动”当前动态面板&am…

从零开始的嵌入式学习day24

标准IO 头文件需求&#xff1a; #include <stdio.h>1.fopen和fclose (1)fopen fopen的函数功能是打开一个文件。 首先看看fopen的函数声明&#xff1a; FILE *fopen(const char *path, const char *mode);第一个参数path是文件地址&#xff0c;传入的是不可变的字符…

抓包分析工具与流量监控软件

目录 一、抓包分析工具&#xff1a;定位问题的“放大镜” 1.1 工作原理简述 1.2 主流工具盘点 1.3 抓包的实战应用 二、流量监控软件&#xff1a;网络全景的“雷达系统” 2.1 功能特征 2.2 常用工具概览 2.3 实战应用场景 五、结语&#xff1a;深入可见&#xff0c;安…

DRIVEGPT4: 通过大语言模型实现可解释的端到端自动驾驶

《DriveGPT4: Interpretable End-to-End Autonomous Driving via Large Language Model》 2024年10月发表&#xff0c;来自香港大学、浙江大学、华为和悉尼大学。 多模态大型语言模型&#xff08;MLLM&#xff09;已成为研究界关注的一个突出领域&#xff0c;因为它们擅长处理…

Vue3 Form 表单限制输入小写字母、数字和下划线

方案一&#xff1a;Element Plus 表单验证 <template><el-form :model"form" :rules"rules" ref"formRef" label-width"120px"><el-form-item label"用户名" prop"username"><el-input v-m…

23、电网数据管理与智能分析 - 负载预测模拟 - /能源管理组件/grid-data-smart-analysis

76个工业组件库示例汇总 电网数据管理与智能分析组件 1. 组件概述 本组件旨在模拟一个城市配电网的运行状态&#xff0c;重点关注数据管理、可视化以及基于模拟数据的智能分析&#xff0c;特别是负载预测功能。用户可以通过界面交互式地探索电网拓扑、查看节点状态、控制时间…

单片机复用功能重映射Remap功能

目录 一、查看“DS5319 stm32f10x中等密度mcu数据手册&#xff08;英文&#xff09;”手册 二、查看“RM0008 STM32F10xxx参考手册&#xff08;中文&#xff09;”手册 三、重映射&#xff08;Remap&#xff09;功能程序编写 自己学习过程中容易遗忘的知识点&#xff0c;记录…

链表面试题9之环形链表进阶

那么上一题我们已经知道了双指针的变法以及拓展的用法&#xff0c;那么这里我们直接难度升级。 想回去复习的这里放个链接&#xff1a;链表的面试题8之环形链表-CSDN博客 题目链接&#xff1a;142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 我们来看这道题目主要…

游戏引擎学习第299天:改进排序键 第二部分

回顾并为当天内容做准备 我们会现场编写完整的游戏代码。回顾上周发现自己对游戏中正确的排序规则并没有清晰的理解。主要原因是我们更擅长三维游戏开发&#xff0c;缺乏二维游戏和二维游戏技术的经验&#xff0c;对于二维精灵排序、模拟三维效果的最佳方案等没有太多技巧和经…

Redis从入门到实战 - 高级篇(中)

一、多级缓存 1. 传统缓存的问题 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈Redis缓存失效时&#xff0c;会…