当前位置: 首页 > news >正文

JavaScript 中使用 Elasticsearch 的正确方式,第一部分

作者:来自 Elastic  Jeffrey Rengifo

讲解如何用 JavaScript 创建一个可用于生产环境的 Elasticsearch 后端。

想获得 Elastic 认证?看看下一期 Elasticsearch 工程师培训什么时候开始吧!

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


这是一个系列文章的第一篇,讲解如何在 JavaScript 中使用 Elasticsearch。在这个系列中,你将学习在 JavaScript 环境中使用 Elasticsearch 的基础知识,并了解创建搜索应用时最相关的功能和最佳实践。到最后,你将掌握使用 JavaScript 运行 Elasticsearch 所需的一切。

在第一部分中,我们将介绍:

  • 环境设置
    • 前端、后端还是无服务器架构?
    • 连接客户端
  • 文档索引
    • Elasticsearch 客户端
    • 语义映射
    • 批量助手
  • 数据搜索
    • 词法查询
    • 语义查询
    • 混合查询

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

什么是 Elasticsearch Node.js 客户端?

Elasticsearch Node.js 客户端是一个 JavaScript 库,它将 Elasticsearch API 的 HTTP REST 调用封装成 JavaScript,使处理变得更简单,还提供了一些助手功能,方便执行像批量索引文档这样的任务。

更多阅读,请参阅文章 “Elasticsearch:使用最新的 Nodejs client 8.x 来创建索引并搜索”。

环境

前端、后端,还是无服务器?

为了使用 JavaScript 客户端创建搜索应用,我们至少需要两个组件:一个 Elasticsearch 集群和一个运行客户端的 JavaScript 运行时。

JavaScript 客户端支持所有 Elasticsearch 解决方案(云端、本地部署和无服务器),它在内部处理了各种差异,因此你不需要担心使用哪一种。

不过,JavaScript 运行时必须运行在服务器上,不能直接在浏览器中运行。

这是因为如果从浏览器直接调用 Elasticsearch,用户可能会获取敏感信息,比如集群的 API 密钥、主机地址或查询本身。Elasticsearch 建议绝不要将集群直接暴露在互联网上,而是使用一个中间层来屏蔽这些信息,让用户只能看到参数。你可以在这里相关内容。

我们建议使用这样的架构:

在这种情况下,客户端只会发送搜索词和一个用于你服务器的认证密钥,而你的服务器将完全控制查询内容以及与 Elasticsearch 的通信。

连接客户端

首先按照这些步骤创建一个 API 密钥。

根据前面的示例,我们将创建一个简单的 Express 服务器,并通过一个 Node.js 服务器中的客户端与它连接。

我们将使用 NPM 初始化项目,并安装 Elasticsearch 客户端和 Express。Express 是一个在 Node.js 中搭建服务器的库。通过使用 Express,我们可以通过 HTTP 与后端进行交互。

让我们来初始化项目:

npm init -y

安装依赖项:

npm install @elastic/elasticsearch express split2 dotenv

让我为你拆解说明:

  • @elastic/elasticsearch:这是官方的 Node.js 客户端

  • express:允许我们快速搭建一个轻量级的 Node.js 服务器,用来暴露 Elasticsearch

  • split2:将文本按行拆分成流,便于我们逐行处理 ndjson 文件

  • dotenv:允许我们通过 .env 文件管理环境变量

在项目根目录创建一个 .env 文件,并添加以下内容:

ELASTICSEARCH_ENDPOINT="Your Elasticsearch endpoint"
ELASTICSEARCH_API_KEY="Your Elasticssearch API"

这样,我们可以使用 dotenv 包导入这些变量。

创建一个 server.js 文件:

const express = require("express");
const bodyParser = require("body-parser");
const { Client } = require("@elastic/elasticsearch");require("dotenv").config(); //environment variables setupconst ELASTICSEARCH_ENDPOINT = process.env.ELASTICSEARCH_ENDPOINT;
const ELASTICSEARCH_API_KEY = process.env.ELASTICSEARCH_API_KEY;
const PORT = 3000;const app = express();app.listen(PORT, () => {console.log("Server running on port", PORT);
});
app.use(bodyParser.json());let esClient = new Client({node: ELASTICSEARCH_ENDPOINT,auth: { apiKey: ELASTICSEARCH_API_KEY },  
});app.get("/ping", async (req, res) => {try {const result = await esClient.info();res.status(200).json({success: true,clusterInfo: result,});} catch (error) {console.error("Error getting Elasticsearch info:", error);res.status(500).json({success: false,clusterInfo: null,error: error.message,});}
});

这段代码搭建了一个基础的 Express.js 服务器,监听 3000 端口,并使用 API 密钥连接到 Elasticsearch 集群进行认证。它包含一个 /ping 端点,通过 GET 请求访问时,会使用 Elasticsearch 客户端的 .info() 方法查询集群的基本信息。

如果查询成功,会以 JSON 格式返回集群信息;否则返回错误信息。服务器还使用了 body-parser 中间件来处理 JSON 请求体。

运行该文件启动服务器:

node server.js

答案应该是这样的:

Server running on port 3000

现在,让我们访问 /ping 端点来检查 Elasticsearch 集群的状态。

curl http://localhost:3000/ping
{"success": true,"clusterInfo": {"name": "instance-0000000000","cluster_name": "61b7e19eec204d59855f5e019acd2689","cluster_uuid": "BIfvfLM0RJWRK_bDCY5ldg","version": {"number": "9.0.0","build_flavor": "default","build_type": "docker","build_hash": "112859b85d50de2a7e63f73c8fc70b99eea24291","build_date": "2025-04-08T15:13:46.049795831Z","build_snapshot": false,"lucene_version": "10.1.0","minimum_wire_compatibility_version": "8.18.0","minimum_index_compatibility_version": "8.0.0"},"tagline": "You Know, for Search"}
}

索引文档

连接成功后,我们可以使用像 semantic_text(语义搜索)和 text(全文查询)这样的映射来索引文档。通过这两种字段类型,我们还可以进行混合搜索(hybrid search)。

我们将创建一个新的 load.js 文件来生成映射并上传文档。

Elasticsearch 客户端

我们首先需要实例化并认证客户端:

const { Client } = require("@elastic/elasticsearch");const ELASTICSEARCH_ENDPOINT = "cluster/project_endpoint";
const ELASTICSEARCH_API_KEY = "apiKey";const esClient = new Client({node: ELASTICSEARCH_ENDPOINT,auth: { apiKey: ELASTICSEARCH_API_KEY },
});

语义映射 - semantic mappings

我们将创建一个包含兽医医院数据的索引。存储的信息包括主人、宠物和就诊详情。

需要进行全文搜索的数据,如姓名和描述,将存为 text 类型。类别数据,如动物的种类或品种,将存为 keyword 类型。

此外,我们会将所有字段的值复制到一个 semantic_text 字段,以便也能针对这些信息进行语义搜索。

const INDEX_NAME = "vet-visits";const createMappings = async (indexName, mapping) => {try {const body = await esClient.indices.create({index: indexName,body: {mappings: mapping,},});console.log("Index created successfully:", body);} catch (error) {console.error("Error creating mapping:", error);}
};await createMappings(INDEX_NAME, {properties: {owner_name: {type: "text",copy_to: "semantic_field",},pet_name: {type: "text",copy_to: "semantic_field",},species: {type: "keyword",copy_to: "semantic_field",},breed: {type: "keyword",copy_to: "semantic_field",},vaccination_history: {type: "keyword",copy_to: "semantic_field",},visit_details: {type: "text",copy_to: "semantic_field",},semantic_field: {type: "semantic_text",},},
});

批量助手 - bulk helper

客户端的另一个优势是可以使用批量助手(bulk helper)批量索引。批量助手方便处理并发、重试以及每个文档成功或失败时的处理方式。

这个助手的一个吸引人功能是支持流式处理。它允许你逐行发送文件,而不是将整个文件存入内存后一次性发送给 Elasticsearch。

要上传数据到 Elasticsearch,请在项目根目录创建一个名为 data.ndjson 的文件,并添加以下信息(或者,你也可以从这里下载包含数据集的文件):

{"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."}
{"owner_name":"Marco Rivera","pet_name":"Milo","species":"Cat","breed":"Siamese","vaccination_history":["Rabies","Feline Leukemia"],"visit_details":"Slight eye irritation, prescribed eye drops."}
{"owner_name":"Sandra Lee","pet_name":"Pickles","species":"Guinea Pig","breed":"Mixed","vaccination_history":[],"visit_details":"Loss of appetite, recommended dietary changes."}
{"owner_name":"Jake Thompson","pet_name":"Luna","species":"Dog","breed":"Labrador Mix","vaccination_history":["Rabies","Bordetella"],"visit_details":"Mild ear infection, cleaning and antibiotics given."}
{"owner_name":"Emily Chen","pet_name":"Ziggy","species":"Cat","breed":"Mixed","vaccination_history":["Rabies","Feline Calicivirus"],"visit_details":"Vaccination update and routine physical."}
{"owner_name":"Tomás Herrera","pet_name":"Rex","species":"Dog","breed":"German Shepherd","vaccination_history":["Rabies","Parvovirus","Leptospirosis"],"visit_details":"Follow-up for previous leg strain, improving well."}
{"owner_name":"Nina Park","pet_name":"Coco","species":"Ferret","breed":"Mixed","vaccination_history":["Rabies"],"visit_details":"Slight weight loss; advised new diet."}
{"owner_name":"Leo Martínez","pet_name":"Simba","species":"Cat","breed":"Maine Coon","vaccination_history":["Rabies","Feline Panleukopenia"],"visit_details":"Dental cleaning. Minor tartar buildup removed."}
{"owner_name":"Rachel Green","pet_name":"Rocky","species":"Dog","breed":"Bulldog Mix","vaccination_history":["Rabies","Parvovirus"],"visit_details":"Skin rash, antihistamines prescribed."}
{"owner_name":"Daniel Kim","pet_name":"Mochi","species":"Rabbit","breed":"Mixed","vaccination_history":[],"visit_details":"Nail trimming and general health check. No issues."}

我们使用 split2 来流式读取文件的每一行,同时批量助手将它们发送到 Elasticsearch。

const { createReadStream } = require("fs");
const split = require("split2");const indexData = async (filePath, indexName) => {try {console.log(`Indexing data from ${filePath} into ${indexName}...`);const result = await esClient.helpers.bulk({datasource: createReadStream(filePath).pipe(split()),onDocument: () => {return {index: { _index: indexName },};},onDrop(doc) {console.error("Error processing document:", doc);},});console.log("Bulk indexing successful elements:", result.items.length);} catch (error) {console.error("Error indexing data:", error);throw error;}
};await indexData("./data.ndjson", INDEX_NAME);

上面的代码逐行读取 .ndjson 文件,并使用 helpers.bulk 方法批量将每个 JSON 对象索引到指定的 Elasticsearch 索引中。它通过 createReadStream 和 split2 流式读取文件,为每个文档设置索引元数据,并记录处理失败的文档。完成后,会输出成功索引的条目数量。

除了使用 indexData 函数,你也可以通过 Kibana 的 UI 直接上传文件,使用上传数据文件的界面。

我们运行该文件,将文档上传到 Elasticsearch 集群。

node load.js

Creating mappings for index vet-visits...
Index created successfully: { acknowledged: true, shards_acknowledged: true, index: 'vet-visits' }
Indexing data from ./data.ndjson into vet-visits...
Bulk indexing completed. Total documents: 10, Failed: 0

搜索数据

回到我们的 server.js 文件,我们将创建不同的端点来执行词法搜索、语义搜索或混合搜索。

简而言之,这些搜索类型不是互斥的,而是取决于你需要回答的问题类型。

Query typeUse caseExample question
词汇搜索

问题中的词或词根很可能出现在索引文档中。问题和文档之间的词元相似度。

I’m looking for a blue sport t-shirt.
语义搜索

问题中的词不太可能出现在文档中。问题和文档之间的概念相似度。

I’m looking for clothing for cold weather.
混合搜索

问题包含词法和/或语义成分。问题和文档之间的词元相似度和语义相似度。

I’m looking for an S size dress for a beach wedding.

问题的词汇部分很可能是标题、描述或类别名称的一部分,而语义部分是与这些字段相关的概念。Blue 很可能是类别名称或描述的一部分,而 beach wedding 可能不是,但可以与 linen clothing 在语义上相关。

Lexical query (/search/lexic?q=<query_term>)

词法搜索,也叫全文搜索,指的是基于词元相似度的搜索;也就是说,经过分析后,包含搜索词元的文档会被返回。

你可以在这里查看我们的词法搜索实操教程。

app.get("/search/lexic", async (req, res) => {const { q } = req.query;const INDEX_NAME = "vet-visits";try {const result = await esClient.search({index: INDEX_NAME,size: 5,body: {query: {multi_match: {query: q,fields: ["owner_name", "pet_name", "visit_details"],},},},});res.status(200).json({success: true,results: result.hits.hits});} catch (error) {console.error("Error performing search:", error);res.status(500).json({success: false,results: null,error: error.message,});}
});

我们用 “nail trimming” 测试。

curl http://localhost:3000/search/lexic?q=nail%20trimming

答案:

{"success": true,"results": [{"_index": "vet-visits","_id": "-RY6RJYBLe2GoFQ6-9n9","_score": 2.7075968,"_source": {"pet_name": "Mochi","owner_name": "Daniel Kim","species": "Rabbit","visit_details": "Nail trimming and general health check. No issues.","breed": "Mixed","vaccination_history": []}},{"_index": "vet-visits","_id": "8BY6RJYBLe2GoFQ6-9n9","_score": 2.560356,"_source": {"pet_name": "Buddy","owner_name": "Alice Johnson","species": "Dog","visit_details": "Annual check-up and nail trimming. Healthy and active.","breed": "Golden Retriever","vaccination_history": ["Rabies","Parvovirus","Distemper"]}}]
}

Semantic query (/search/semantic?q=<query_term>)

语义搜索不同于词法搜索,它通过向量搜索找到与搜索词含义相似的结果。

你可以在这里查看我们的语义搜索实操教程。

app.get("/search/semantic", async (req, res) => {const { q } = req.query;const INDEX_NAME = "vet-visits";try {const result = await esClient.search({index: INDEX_NAME,size: 5,body: {query: {semantic: {field: "semantic_field",query: q},},},});res.status(200).json({success: true,results: result.hits.hits,});} catch (error) {console.error("Error performing search:", error);res.status(500).json({success: false,results: null,error: error.message,});}
});

我们用 “Who got a pedicure?” 测试。

curl http://localhost:3000/search/semantic?q=Who%20got%20a%20pedicure?

答案:

{"success": true,"results": [{"_index": "vet-visits","_id": "-RY6RJYBLe2GoFQ6-9n9","_score": 4.861466,"_source": {"owner_name": "Daniel Kim","pet_name": "Mochi","species": "Rabbit","breed": "Mixed","vaccination_history": [],"visit_details": "Nail trimming and general health check. No issues."}},{"_index": "vet-visits","_id": "8BY6RJYBLe2GoFQ6-9n9","_score": 4.7152824,"_source": {"pet_name": "Buddy","owner_name": "Alice Johnson","species": "Dog","visit_details": "Annual check-up and nail trimming. Healthy and active.","breed": "Golden Retriever","vaccination_history": ["Rabies","Parvovirus","Distemper"]}},{"_index": "vet-visits","_id": "9RY6RJYBLe2GoFQ6-9n9","_score": 1.6717153,"_source": {"pet_name": "Rex","owner_name": "Tomás Herrera","species": "Dog","visit_details": "Follow-up for previous leg strain, improving well.","breed": "German Shepherd","vaccination_history": ["Rabies","Parvovirus","Leptospirosis"]}},{"_index": "vet-visits","_id": "9xY6RJYBLe2GoFQ6-9n9","_score": 1.5600781,"_source": {"pet_name": "Simba","owner_name": "Leo Martínez","species": "Cat","visit_details": "Dental cleaning. Minor tartar buildup removed.","breed": "Maine Coon","vaccination_history": ["Rabies","Feline Panleukopenia"]}},{"_index": "vet-visits","_id": "-BY6RJYBLe2GoFQ6-9n9","_score": 1.2696637,"_source": {"pet_name": "Rocky","owner_name": "Rachel Green","species": "Dog","visit_details": "Skin rash, antihistamines prescribed.","breed": "Bulldog Mix","vaccination_history": ["Rabies","Parvovirus"]}}]
}

Hybrid query (/search/hybrid?q=<query_term>)

混合搜索允许我们结合语义搜索和词法搜索,从而兼得两者优势:既有基于词元搜索的精准度,也有语义搜索的意义接近性。

app.get("/search/hybrid", async (req, res) => {const { q } = req.query;const INDEX_NAME = "vet-visits";try {const result = await esClient.search({index: INDEX_NAME,body: {retriever: {rrf: {retrievers: [{standard: {query: {bool: {must: {multi_match: {query: q,fields: ["owner_name", "pet_name", "visit_details"],},},},},},},{standard: {query: {bool: {must: {semantic: {field: "semantic_field",query: q,},},},},},},],},},size: 5,},});res.status(200).json({success: true,results: result.hits.hits,});} catch (error) {console.error("Error performing search:", error);res.status(500).json({success: false,results: null,error: error.message,});}
});

我们用 “Who got a pedicure or dental treatment?” 测试。

curl http://localhost:3000/search/hybrid?q=who%20got%20a%20pedicure%20or%20dental%20treatment

答案:

{"success": true,"results": [{"_index": "vet-visits","_id": "9xY6RJYBLe2GoFQ6-9n9","_score": 0.032522473,"_source": {"pet_name": "Simba","owner_name": "Leo Martínez","species": "Cat","visit_details": "Dental cleaning. Minor tartar buildup removed.","breed": "Maine Coon","vaccination_history": ["Rabies","Feline Panleukopenia"]}},{"_index": "vet-visits","_id": "-RY6RJYBLe2GoFQ6-9n9","_score": 0.016393442,"_source": {"pet_name": "Mochi","owner_name": "Daniel Kim","species": "Rabbit","visit_details": "Nail trimming and general health check. No issues.","breed": "Mixed","vaccination_history": []}},{"_index": "vet-visits","_id": "8BY6RJYBLe2GoFQ6-9n9","_score": 0.015873017,"_source": {"pet_name": "Buddy","owner_name": "Alice Johnson","species": "Dog","visit_details": "Annual check-up and nail trimming. Healthy and active.","breed": "Golden Retriever","vaccination_history": ["Rabies","Parvovirus","Distemper"]}},{"_index": "vet-visits","_id": "9RY6RJYBLe2GoFQ6-9n9","_score": 0.015625,"_source": {"pet_name": "Rex","owner_name": "Tomás Herrera","species": "Dog","visit_details": "Follow-up for previous leg strain, improving well.","breed": "German Shepherd","vaccination_history": ["Rabies","Parvovirus","Leptospirosis"]}},{"_index": "vet-visits","_id": "8xY6RJYBLe2GoFQ6-9n9","_score": 0.015384615,"_source": {"pet_name": "Luna","owner_name": "Jake Thompson","species": "Dog","visit_details": "Mild ear infection, cleaning and antibiotics given.","breed": "Labrador Mix","vaccination_history": ["Rabies","Bordetella"]}}]
}

总结

在本系列的第一部分中,我们讲解了如何搭建环境并创建带有不同搜索端点的服务器,以按照客户端/服务器的最佳实践查询 Elasticsearch 文档。敬请期待第二部分,你将学习生产环境的最佳实践以及如何在无服务器环境中运行 Elasticsearch Node.js 客户端。

原文:https://www.elastic.co/search-labs/blog/how-to-use-elasticsearch-in-javascript-part-i

相关文章:

JavaScript 中使用 Elasticsearch 的正确方式,第一部分

作者&#xff1a;来自 Elastic Jeffrey Rengifo 讲解如何用 JavaScript 创建一个可用于生产环境的 Elasticsearch 后端。 想获得 Elastic 认证&#xff1f;看看下一期 Elasticsearch 工程师培训什么时候开始吧&#xff01; Elasticsearch 拥有大量新功能&#xff0c;能帮助你…...

每日一道leetcode(增加版)

901. 股票价格跨度 - 力扣&#xff08;LeetCode&#xff09; 题目 设计一个算法收集某些股票的每日报价&#xff0c;并返回该股票当日价格的 跨度 。 当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数&#xff08;从今天开始往回数&#xff0c;包括今…...

排序复习/下(C语言版)

目录 1.快速排序&#xff08;hoare法&#xff09; 单趟&#xff1a; 整体&#xff1a; 代码优化&#xff1a; ​编辑三数取中代码&#xff1a; 小区间优化代码&#xff1a; hoare法疑问解答&#xff1a; 2.快速排序&#xff08;挖坑法&#xff09; 3.快速排序&#x…...

Vue百日学习计划Day33-35天详细计划-Gemini版

总目标: 在 Day 33-35 理解 Vue 组件从创建到销毁的完整生命周期&#xff0c;熟练掌握 Composition API 中主要的生命周期钩子&#xff0c;并知道在不同阶段执行哪些操作。 所需资源: Vue 3 官方文档 (生命周期钩子): https://cn.vuejs.org/guide/essentials/lifecycle.html你…...

Apidog MCP服务器,连接API规范和AI编码助手的桥梁

#作者&#xff1a;曹付江 文章目录 1.了解 MCP2.什么是 Apidog MCP 服务器&#xff1f;3.Apidog MCP 服务器如何工作4.利用人工智能改变开发工作流程5.设置 Apidog MCP 服务器&#xff1a; 分步指南5.高级功能和提示5.1 使用 OpenAPI 规范5.2.多个项目配置5.3.安全最佳实践5.4…...

统计客户端使用情况,使用es存储数据,实现去重以及计数

这篇文件的重点在tshark、filebeat、和logstash。 需求&#xff1a;统计客户使用的客户端版本 实现工具&#xff1a;tshark 1.10.14&#xff0c;filebeat 8.17.0&#xff0c;logstash 8.17.0&#xff0c;elasticsearch 8.17.0&#xff0c;kibana 8.17.0 总体设计&#xff1a…...

Git基础面试题

git的rm命令与系统的rm命令有什么区别 git rm 和系统的 rm (在 Windows 上是 del) 命令都用于删除文件&#xff0c;但它们在 Git 仓库的上下文中作用有所不同&#xff1a; 系统 rm (或 del) 命令&#xff1a; 作用&#xff1a; 直接从文件系统中删除文件。Git 的感知&#xff…...

conda 的常用命令

好的&#xff0c;下面为你介绍conda的常用命令&#xff1a; 环境管理 # 创建新环境 conda create -n env_name python3.8# 激活环境 conda activate env_name# 查看所有环境 conda env list# 复制环境 conda create -n new_env --clone old_env# 删除环境 conda remove -n en…...

PLC双人舞:profinet转ethernet ip网关奏响施耐德与AB的协奏曲

PLC双人舞&#xff1a;ethernet ip转profinet网关奏响施耐德与AB的协奏曲 案例分析&#xff1a;施耐德PLC与AB PLC的互联互通 在现代工业自动化中&#xff0c;设备之间的互联互通至关重要。本案例旨在展示如何通过北京倍讯科技的EtherNet/IP转Modbus网关&#xff0c;将施耐德P…...

百度OCR:证件识别

目录 一、编写目的 二、准备工作 2.1 OCR密钥 三、代码实现 3.1 配置文件 3.2 请求接收封装 3.3 请求响应封装 3.4 服务类参数初始化 3.5 服务类实现 3.6 解析结果 3.7 定义Web接口 四 测试效果 五、总结 欢迎来到盹猫&#x1f431;的博客 本篇文章主要介绍了 [百…...

纯前端实现图文识别 OCR

Tesseract.js Tesseract.js 是一个基于 Google Tesseract OCR 引擎的 JavaScript 库&#xff0c;利用 WebAssembly 技术将的 OCR 引擎带到了浏览器中。它完全运行在客户端&#xff0c;无需依赖服务器&#xff0c;适合处理中小型图片的文字识别。 基本使用 以下示例展示了如何…...

2025.05.01【Barplot】柱状图的多样性绘制

Custom color A few examples showing how to custom barplot color. Horizontal barchart It makes sense to make your barchart horizontal: group labels are now much easier to read 文章目录 Custom colorHorizontal barchart 探索Barplot的奥秘Barplot基础什么是Barp…...

在资源受限环境下,移动端如何实现流畅动画?如何在内存、CPU、GPU、网络等多种限制条件下,依然保持动画高帧率、低延迟、不卡顿?

在日常生活中&#xff0c;移动设备已经成为不可或缺的工具。从社交、购物到游戏、教育&#xff0c;几乎所有的应用场景都依赖于移动终端的计算和显示能力。然而&#xff0c;随着用户体验的不断提升需求&#xff0c;动画成为了界面交互中不可忽视的一环。动画不仅提升了视觉吸引…...

HJ10 字符个数统计【牛客网】

文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 HJ10 字符个数统计 一、题目描述 二、测试用例 三、解题思路 基本思路&#xff1a;   建立字符串的散列表&#xff0c;然后统计不同字符个数具体思路&#xff1a;   遍历字符串的字…...

关键点检测算法-RTMPose

一、网络框架&#xff08;top-down模式&#xff09; 二、各部分内容 1、骨干网络 对于网络而言&#xff0c;CXPset太大&#xff0c;可以换成starnet 2、一个卷积层 7x7的卷积核对性能提升最大 3、一个全连接层 将一维关键点表示扩展到由超参数控制的所需维度。 4、一个用…...

云原生安全:错误策略S3存储桶ACL设置为Everyone:FullControl

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 ——从基础到实践的深度解析 1. 基础概念 S3存储桶与ACL Amazon S3(Simple Storage Service)是AWS提供的对象存储服务,支持存储和检索任意规模的数据。ACL(访问控制列表…...

Axure疑难杂症:垂直菜单展开与收回(4大核心问题与专家级解决方案)

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!如有帮助请订阅专栏! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:垂直菜单展开与收回 主要内容:超长菜单实现、展开与收回bug解释、Axure9版本限制等问题解…...

图漾相机错误码解析(待补充)

文章目录 1.相机错误码汇总2.常见报错码2.1 -1001报错2.1.1 没有找到相机2.1.2 SDK没有进行初始化 2.2 -1005报错2.2.1 跨网段打开相机2.2.2 旧版本SDK在软触发失败后提示的报错2.2.3 相机初始化上电时报错2.2.4 USB相机被占用 2.3 -1009报错2.3.1 相机本身不支持改属性 2.4 -1…...

SpringBoot 中文转拼音 Pinyin4j库 拼音转换 单据管理 客户管理

介绍 在客户管理系统中部分客户的名字会有生僻字为了沟通时候不叫错客户的名称&#xff0c;因此决定将客户名称的拼音一起返回给前端&#xff0c;也可以直接交给前端去处理。这里介绍后端的做法 Pinyin4j 是一个用于将汉字转换为拼音的 Java 库。在需要对中文文本进行拼音转换…...

使用 Whisper 生成视频字幕:从提取音频到批量处理

生成视频字幕是许多视频处理任务的核心需求。本文将指导你使用 OpenAI 的 Whisper 模型为视频文件&#xff08;如电视剧《Normal People》或电影《花样年华》&#xff09;生成字幕&#xff08;SRT 格式&#xff09;。我们将从提取音频开始&#xff0c;逐步实现字幕生成&#xf…...

Kotlin Compose Button 实现长按监听并实现动画效果

想要实现长按按钮开始录音&#xff0c;松开发送的功能。发现 Button 这个控件如果去监听这些按下&#xff0c;松开&#xff0c;长按等事件&#xff0c;发现是不会触发的&#xff0c;究其原因是 Button 已经提前消耗了这些事件所以导致&#xff0c;这些监听无法被触发。因此为了…...

SQL练习——(15/81)

目录 1.计算次日留存率 2.多条件查询 方法1&#xff1a;子查询 方法2&#xff1a;窗口函数实现 3.条件查询——自连接相关 1.计算次日留存率 550. 游戏玩法分析 IV - 力扣&#xff08;LeetCode&#xff09; 错误查询1&#xff1a;&#xff08;没有考虑从首次登录日期开始…...

数据中心 智慧机房解决方案

该文档介绍数据中心智慧机房解决方案,涵盖模块化数据中心(机柜式、微模块),具备低成本快速部署、标准化建设等特点;监控管理系统(DCIM)可实现设施、资产、容量、能效管理;节能解决方案含精密空调节能控制柜,节能率高达 30%;还有7X24 小时云值守运维服务。方案亮点包括…...

网络-MOXA设备基本操作

修改本机IP和网络设备同网段&#xff0c;输入设备IP地址进入登录界面&#xff0c;交换机没有密码&#xff0c;路由器密码为moxa 修改设备IP地址 交换机 路由器 环网 启用Turbo Ring协议&#xff1a;在设备的网络管理界面中&#xff0c;找到环网配置选项&#xff0c;启用Turb…...

Docker构建 Dify 应用定时任务助手

概述 Dify 定时任务管理工具是一个基于 GitHub Actions 的自动化解决方案&#xff0c;用于实现 Dify Workflow 的定时执行和状态监控。无需再为缺乏定时任务支持而感到困扰&#xff0c;本工具可以帮助设置自动执行任务并获取实时通知&#xff0c;优化你的工作效率。 注意&…...

前端测试策略:单元测试到 E2E 测试

引言 在现代前端开发中&#xff0c;测试已成为确保应用质量和可靠性的关键环节。随着前端应用复杂度的不断提高&#xff0c;仅依靠手动测试已经远远不够。一个全面的前端测试策略应该包含多个层次的测试&#xff0c;从最小粒度的单元测试到模拟真实用户行为的端到端(E2E)测试。…...

Web漏洞扫描服务的特点与优势:守护数字时代的安全防线

在数字化浪潮中&#xff0c;Web应用程序的安全性已成为企业业务连续性和用户信任的核心要素。随着网络攻击手段的不断升级&#xff0c;Web漏洞扫描服务作为一种主动防御工具&#xff0c;逐渐成为企业安全体系的标配。本文将从特点与优势两方面&#xff0c;解析其价值与应用场景…...

大中型水闸安全监测系统解决方案

一、系统概述 水闸是重要的水利基础设施&#xff0c;具有防洪、挡潮、排涝、灌溉、供水、生态、航运和水力发电等综合功能&#xff0c;在国家水网构建、支撑经济社会高质量发展等方面具有十分重要的作用。我国水闸工程面广量大&#xff0c;据2021年统计数据&#xff0c;我国已建…...

紫光同创FPGA实现AD9238数据采集转UDP网络传输,分享PDS工程源码和技术支持和QT上位机

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目紫光同创FPGA相关方案推荐我这里已有的以太网方案本方案在Xilinx系列FPGA的应用方案 3、设计思路框架工程设计原理框图AD输入源AD9238数据采集AD9238数据缓存控制模块…...

ffmpeg 把一个视频复制3次

1. 起因&#xff0c; 目的: 前面我写过&#xff0c;使用 python 把一个视频复制3次但是速度太慢了&#xff0c;我想试试看能否改进。而且我想换一种新的视频处理思路&#xff0c;并试试看速度如何。 2. 先看效果 效果就是能行&#xff0c;而且速度也快。 3. 过程: 代码 1…...

仿腾讯会议——添加音频

1、实现开启或关闭音频 2、 定义信号 3、实现开始暂停音频 4、实现信号槽连接 5、回收资源 6、初始化音频视频 7、 完成为每个人创建播放音频的对象 8、发送音频 使用的是对象ba&#xff0c;这样跨线程不会立刻回收&#xff0c;如果使用引用&#xff0c;跨线程会被直接回收掉&a…...

从零训练一个大模型:DeepSeek 的技术路线与实践

从零训练一个大模型&#xff1a;DeepSeek 的技术路线与实践 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 从零训练一个大模型&#xff1a;DeepSeek 的技术路线与实践摘要引言技术路线对比1. 模型架构&#xff1a…...

interface接口和defer场景分析

接口 接口这里主要两点&#xff1a; 设计业务结构时采用依赖倒转&#xff1a;业务层向下依赖抽象层&#xff0c;实现层向上依赖抽象层。 相比于之前&#xff1a; 之后&#xff1a; 注意struct中嵌套interface和不嵌套interface的区别&#xff1a; type Myinterface interfac…...

【数据结构篇】排序1(插入排序与选择排序)

注&#xff1a;本文以排升序为例 常见的排序算法&#xff1a; 目录&#xff1a; 一 直接插入排序&#xff1a; 1.1 基本思想&#xff1a; 1.2 代码&#xff1a; 1.3 复杂度&#xff1a; 二 希尔排序&#xff08;直接插入排序的优化&#xff09;&#xff1a; 2.1 基本思想…...

FastAPI自定义异常处理:优雅转换Pydantic校验错误

FastAPI自定义异常处理:优雅转换Pydantic校验错误 背景需求 当使用FastAPI开发API服务时,Pydantic的自动校验异常默认会返回如下格式的422响应: {"detail": [{"type": "missing","loc": ["body", "user", &…...

C++--内存管理

内存管理 1. C/C内存分布 在C语言阶段&#xff0c;常说局部变量存储在栈区&#xff0c;动态内存中的数据存储在堆区&#xff0c;静态变量存储在静态区&#xff08;数据段&#xff09;&#xff0c;常量存储在常量区&#xff08;代码段&#xff09;&#xff0c;其实这里所说的栈…...

YOLOV3 深度解析:目标检测的高效利器

在计算机视觉领域&#xff0c;目标检测一直是一个重要且热门的研究方向&#xff0c;广泛应用于安防监控、自动驾驶、机器人视觉等诸多场景。YOLO&#xff08;You Only Look Once&#xff09;系列算法凭借其出色的实时性和较高的检测精度&#xff0c;在目标检测领域占据着重要地…...

select * from 按时间倒序排序

在SQL中&#xff0c;如果你想要根据时间字段来倒序排序查询结果&#xff0c;你可以使用ORDER BY子句&#xff0c;并结合DESC关键字来实现这个目的。这里有几个常见的场景和示例&#xff0c;假设我们有一个表events&#xff0c;里面包含一个时间戳字段event_time。 示例1&#…...

数据结构-DAY06

一、树的概念 1.链表是数的一部分&#xff08;斜树&#xff09; 2.树的查找速度很快 3.层序&#xff1a;前序&#xff1a;根左右 中序&#xff1a;左根右 后序&#xff1a; 左右根 4.树的存储&#xff1a;顺序结构&#xff0c;链式结构 5.特点&#xff1a; 1&#xf…...

JavaWeb:SpringBoot处理全局异常(RestControllerAdvice)

问题 GlobalExceptionHandler 小结...

免费私有化部署! PawSQL社区版,超越EverSQL的企业级SQL优化工具面向个人开发者开放使用了

1. 概览 1.1 快速了解 PawSQL PawSQL是专注于数据库性能优化的企业级工具&#xff0c;解决方案覆盖SQL开发、测试、运维的整个流程&#xff0c;提供智能SQL审核、查询重写优化及自动化巡检功能&#xff0c;支持MySQL、PostgreSQL、Oracle、SQL Server等主流数据库及达梦、金仓…...

buuctf RSA之旅

BUUCTF-RSA的成长之路 rsarsaRSA1RSA3RSA2RSARSAROLLDangerous RSA[GUET-CTF2019]BabyRSArsa2RSA5[NCTF2019]childRSA[HDCTF2019]bbbbbbrsaRSA4[BJDCTF2020]rsa_output[BJDCTF2020]RSA[WUSTCTF2020]babyrsa[ACTF新生赛2020]crypto-rsa0[ACTF新生赛2020]crypto-rsa3[GWCTF 2019]…...

javascript 编程基础(2)javascript与Node.js

文章目录 一、Node.js 与 JavaScript1、基本概念1.1、JavaScript&#xff1a;动态脚本语言1.2、Node.js&#xff1a;JavaScript 运行时环境 2、核心区别3、执行环境差异3.1、浏览器中的JavaScript3.2、Node.js中的JavaScript 4、共同点5、为什么需要Node.js&#xff1f; 一、No…...

IDEA+AI 深度融合:重构高效开发的未来模式

在 Java 开发领域&#xff0c;IntelliJ IDEA&#xff08;以下简称 IDEA&#xff09;作为最受欢迎的集成开发环境之一&#xff0c;一直是开发者的得力工具。而飞算 JavaAI 凭借强大的人工智能技术&#xff0c;为 Java 开发带来了全新的效率提升可能。当 IDEA 与飞算 JavaAI 深度…...

深度学习中常见损失函数激活函数

损失函数 一、分类任务损失函数 二、回归任务损失函数 三、生成对抗网络&#xff08;GAN&#xff09;损失函数 四、其他专用损失函数 五、损失函数选择原则 任务类型&#xff1a;分类用交叉熵&#xff0c;回归用MSE/MAE。 数据分布&#xff1a;类别不平衡时选择Focal Loss或…...

入职软件开发与实施工程师了后........

时隔几个月没有创作的我又回来了&#xff0c;这几个月很忙&#xff0c;我一直在找工作&#xff0c;在自考&#xff08;顺便还处理了一下分手的事&#xff09;&#xff0c;到处奔波&#xff0c;心力交瘁。可能我骨子里比较傲吧。我不愿意着急谋生&#xff0c;做我不愿意做的普通…...

告别Spring AI!我的Java轻量AI框架实践(支持多模型接入|注解式MCP架构|附开源地址)

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 1. 开发初衷 \quad 大家好&#xff0c;我是犬余&#xff0c;之前&#xff0c;为了体验一下MCP架构的JAVA实现&#xff0c;犬余使用了Spring AI框…...

【软考-架构】15、软件架构的演化和维护

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 软件架构演化和定义面向对象软件架构演化软件架构演化方式的分类软件架构演化原则软件架构演化评估方法大型网站架构演化软件架构维护 软件架构演化和定义 软件架构生命周…...

编译Qt5.15.16并启用pdf模块

编译Qt5.15.16并启用pdf模块 标题1.目录设置 -q-bulid –qt-everywhere-src-5.15.16 –bulid cd bulid 必须&#xff0c;否则会提示Project ERROR: You cannot configure qt separately within a top-level build. create .qmake.stash and .qmake.super in build folder …...

spring中的EnvironmentPostProcessor接口详解

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 EnvironmentPostProcessor 是 Spring Boot 提供的一个关键扩展接口&#xff0c;允许开发者在 Spring 应用环境初始化后、应用上下文创建前&…...