使用 Node.js 和 Azure Function App 自动更新 Elasticsearch 索引

news2025/1/17 21:17:48

作者:来自 Elastic Jessica Garson

维护最新数据至关重要,尤其是在处理频繁变化的动态数据集时。这篇博文将指导你使用 Node.js 加载数据,并通过定期更新确保数据保持最新。我们将利用 Azure Function Apps 的功能来自动执行这些更新,从而确保你的数据集始终是最新且可靠的。

对于这篇博文,我们将使用 Near Earth Object Web 服务 (NeoWs),这是一种 RESTful Web 服务,提供有关近地小行星的详细信息。通过将 NeoWs 与作为 Azure 无服务器函数集成的 Node.js 服务集成,此示例将为你提供一个强大的框架来有效处理管理动态数据的复杂性。这种方法将帮助你最大限度地降低使用过时信息的风险,并最大限度地提高数据的准确性和实用性。

先决条件

  • 此示例使用 Elasticsearch 版本 8.13;如果你是 Elasticsearch 新手,请查看我们的 Elasticsearch 快速入门。任何 8.0 版本都适用于此博客文章。
  • 下载最新的 NPM 和 Node.js 版本。本教程使用 Node v21.6.1 和 npm 10.5.0。
  • NASA API 的 API 密钥。
  • 具有创建 Function App 权限的有效 Azure 帐户。
  • 访问 Azure 门户或 Azure CLI

本地设置

在开始索引和本地加载数据之前,设置环境至关重要。首先,创建一个目录并初始化它。然后,下载必要的软件包并创建一个 .env 文件来存储你的配置设置。此初步设置可确保你的本地环境已准备好有效处理数据。

mkdir Introduction-to-Data-Loading-in-Elasticsearch-with-Nodejs
cd Introduction-to-Data-Loading-in-Elasticsearch-with-Nodejs
npm init

你将使用 Elasticsearch nodejs 客户端连接到 Elastic,使用 Axios 连接到 NASA API,使用 dotenv 解析你的凭据(secrets)。你需要运行以下命令下载所需的软件包:

npm install @elastic/elasticsearch axios dotenv

下载所需的软件包后,你可以在项目目录的根目录中创建一个 .env 文件。.env 文件允许你在本地保护你的凭据。查看示例 .env 文件以了解更多信息。要了解有关连接到 Elasticsearch 的更多信息,请务必查看有关该主题的文档。

要创建 .env 文件,你可以在项目根目录中使用此命令:

touch .env

在你的 .env 中,请确保输入以下内容。请确保添加完整的端点:

ELASTICSEARCH_ENDPOINT="https://...."
ELASTICSEARCH_API_KEY="YOUR_ELASTICSEARCh_API_KEY"
NASA_API_KEY="YOUR_NASA_API_KEY"

你还需要创建一个新的 JavaScript 文件:

touch loading_data_into_a_index.js

创建索引并加载数据

现在你已经设置了正确的文件结构并下载了所需的包,你可以创建一个脚本来创建索引并将数据加载到索引中。如果你在此过程中遇到困难,请务必查看本节中创建的文件的完整版本。

在文件 loading_data_into_a_index.js 中,配置 dotenv 包以使用存储在 .env 文件中的密钥和令牌。你还应该导入 Elasticsearch 客户端以连接到 Elasticsearch 和 Axios 并发出 HTTP 请求。

require('dotenv').config();

const { Client } = require('@elastic/elasticsearch');
const axios = require('axios');

由于你的密钥和令牌当前存储为环境变量,你将需要检索它们并创建客户端来向 Elasticsearch 进行身份验证。

const elasticsearchEndpoint = process.env.ELASTICSEARCH_ENDPOINT;
const elasticsearchApiKey = process.env.ELASTICSEARCH_API_KEY;
const nasaApiKey = process.env.NASA_API_KEY;

const client = new Client({
  node: elasticsearchEndpoint,
  auth: {
    apiKey: elasticsearchApiKey
  }
});

你可以开发一个函数来异步检索 NASA 的 NEO(Near Earth Object - 近地天体)Web 服务中的数据。首先,你需要为 NASA API 请求配置基本 URL,并创建今天和上周的日期对象以建立查询周期。将这些日期格式化为 API 请求所需的 YYYY-MM-DD 格式后,将日期设置为查询参数并向 NASA API 执行 GET 请求。此外,该函数还包括错误处理机制,以便在出现任何问题时帮助进行调试。

async function fetchNasaData() {
  const url = "https://api.nasa.gov/neo/rest/v1/feed";
  const today = new Date();
  const lastWeek = new Date(today);
  lastWeek.setDate(today.getDate() - 7);

  const startDate = lastWeek.toISOString().split('T')[0];
  const endDate = today.toISOString().split('T')[0];
  const params = {
    api_key: nasaApiKey,
    start_date: startDate,
    end_date: endDate,
  };

  try {
    const response = await axios.get(url, { params });
    return response.data;
  } catch (error) {
    console.error('Error fetching data from NASA:', error);
    return null;
  }
}

现在,你可以创建一个函数,将 NASA API 中的原始数据转换为结构化格式。由于你返回的数据目前嵌套在复杂的 JSON 响应中。更直接的对象数组使处理数据变得更容易。

function createStructuredData(response) {
  const allObjects = [];
  const nearEarthObjects = response.near_earth_objects;

  Object.keys(nearEarthObjects).forEach(date => {
    nearEarthObjects[date].forEach(obj => {
      const simplifiedObject = {
        close_approach_date: date,
        name: obj.name,
        id: obj.id,
        miss_distance_km: obj.close_approach_data.length > 0 ? obj.close_approach_data[0].miss_distance.kilometers : null,
      };

      allObjects.push(simplifiedObject);
    });
  });

  return allObjects;
}

你将需要创建一个索引来存储来自 API 的数据。Elasticsearch 中的索引是你可以将数据存储在文档中的地方。在此函数中,你将检查索引是否存在,并在需要时创建一个新索引。你还将为索引指定正确的字段映射。此函数还将数据作为文档加载到索引中,并将 NASA 数据中的 id 字段映射到 Elasticsearch 中的 _id 字段。

async function indexDataIntoElasticsearch(data) {
  const indexExists = await client.indices.exists({ index: 'nasa-node-js' });
  if (!indexExists.body) {
    await client.indices.create({
      index: 'nasa-node-js',
      body: {
        mappings: {
          properties: {
            close_approach_date: { type: 'date' },
            name: { type: 'text' },
            miss_distance_km: { type: 'float' },
          },
        },
      },
    });
  }

  const body = data.flatMap(doc => [{ index: { _index: 'nasa-node-js', _id: doc.id } }, doc]);
  await client.bulk({ refresh: false, body });
}

你需要创建一个主函数来获取、构造和索引数据。此函数还将打印出正在上传的记录数,并记录数据是否已编入索引、是否没有要编入索引的数据,或者是否无法从 NASA API 获取数据。创建 run 函数后,你需要调用该函数并捕获可能出现的任何错误。

async function run() {
  const rawData = await fetchNasaData();
  if (rawData) {
    const structuredData = createStructuredData(rawData);
    console.log(`Number of records being uploaded: ${structuredData.length}`);
    if (structuredData.length > 0) {
      await indexDataIntoElasticsearch(structuredData);
      console.log('Data indexed successfully.');
    } else {
      console.log('No data to index.');
    }
  } else {
    console.log('Failed to fetch data from NASA.');
  }
}

run().catch(console.error);

你现在可以通过运行以下命令从命令行运行该文件:

node loading_data_into_a_index.js

要确认你的索引已成功加载,你可以通过执行以下 API 调用来检查 Elastic Dev Tools:

GET /nasa-node-js/_search

使用 Azure 函数应用程序保持数据更新

现在你已成功将数据加载到本地索引中,但这些数据很快就会过时。为确保你的信息保持最新,你可以设置 Azure 函数应用程序以自动每天获取新数据并将其上传到 Elasticsearch 索引。

第一步是在 Azure 门户中配置你的函数应用程序。Azure 快速入门指南是入门的有用资源。

设置函数后,你可以确保已为 ELASTICSEARCH_ENDPOINT、ELASTICSEARCH_API_KEY 和 NASA_API_KEY 设置环境变量。在函数应用程序中,环境变量称为应用程序设置(Application settings)。在函数应用程序中,单击左侧面板中 “Configuration” 下的 “Settings” 选项。在 “Application settings” 选项卡下,单击“+ New application setting”。

你还需要确保安装了所需的库。如果你转到 Azure 门户上的终端,可以通过输入以下内容来安装必要的软件包:

npm install @elastic/elasticsearch axios

你正在安装的软件包看起来应该与之前的安装非常相似,只是你将使用 moment 来解析日期,并且你不再需要加载 env 文件,因为你只需将 secrets 设置为应用程序设置即可。

你可以单击 create 的位置以在函数应用程序中创建新函数,选择名为 “Timer trigger”” 的模板。现在你将拥有一个名为 function.json 的文件。你需要将其调整为如下所示,以便每天上午 10 点运行此应用程序。

{
    "bindings": [
      {
        "name": "myTimer",
        "type": "timerTrigger",
        "direction": "in",
        "schedule": "0 0 10 * * *"
      }
    ]
  }

你还需要上传 package.json 文件并确保其显示如下:

{
  "name": "introduction-to-data-loading-in-elasticsearch-with-nodejs",
  "version": "1.0.0",
  "description": "A simple script for loading data in Elasticsearch",
  "main": "loading_data_into_a_index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/JessicaGarson/Introduction-to-Data-Loading-in-Elasticsearch-with-Nodejs.git"
  },
  "author": "Jessica Garson",
  "license": "Apache-2.0",
  "bugs": {
    "url": "https://github.com/JessicaGarson/Introduction-to-Data-Loading-in-Elasticsearch-with-Nodejs/issues"
  },
  "homepage": "https://github.com/JessicaGarson/Introduction-to-Data-Loading-in-Elasticsearch-with-Nodejs#readme",
  "dependencies": {
    "@elastic/elasticsearch": "^8.12.0",
    "axios": "^0.21.1"
  }
}

下一步是创建一个 index.js 文件。此脚本旨在每天自动更新数据。它通过每天系统地获取和解析新数据,然后无缝地更新数据集来实现这一点。Elasticsearch 可以使用相同的方法来提取时间序列或不可变数据,例如 webhook 响应。此方法可确保信息保持最新和准确,反映最新的可用数据。你也可以查看完整代码。

你在本地运行的脚本与此脚本之间的主要区别如下:

  • 你不再需要加载 .env 文件,因为你已经设置了环境变量
  • 还有不同的日志记录,更多旨在创建更可持续的脚本
  • 你可以根据最近的收盘价日期保持索引更新
  • 有一个 Azure 函数应用程序的入口点

你首先需要设置库并向 Elasticsearch 进行身份验证,如下所示:

const elasticsearchEndpoint = process.env.ELASTICSEARCH_ENDPOINT;
const elasticsearchApiKey = process.env.ELASTICSEARCH_API_KEY;
const nasaApiKey = process.env.NASA_API_KEY;

const client = new Client({
 node: elasticsearchEndpoint,
 auth: {
   apiKey: elasticsearchApiKey
 }
});

之后,你将需要从 Elasticsearch 获取最新的更新日期,并配置备份方法以便在出现任何问题时获取过去一天的数据。

async function getLastUpdateDate() {
  try {
    const response = await client.search({
      index: 'nasa-node-js',
      body: {
        size: 1,
        sort: [{ close_approach_date: { order: 'desc' } }],
        _source: ['close_approach_date']
      }
    });

    if (response.body && response.body.hits && response.body.hits.hits.length > 0) {
      return response.body.hits.hits[0]._source.close_approach_date;
    } else {
      // Default to one day ago if no records found
      const today = new Date();
      const lastWeek = new Date(today);
      lastWeek.setDate(today.getDate() - 1);
      return lastWeek.toISOString().split('T')[0];
    }
  } catch (error) {
    console.error('Error fetching last update date from Elasticsearch:', error);
    throw error;
  }
}

以下函数连接到 NASA 的 NEO(近地天体)Web 服务以获取数据,使你的索引保持更新。还有一些额外的错误处理功能,可以捕获可能出现的任何 API 错误。

async function fetchNasaData(startDate) {

  const url = "https://api.nasa.gov/neo/rest/v1/feed";
  const today = new Date();

  const endDate = today.toISOString().split('T')[0];

  const params = {
    api_key: nasaApiKey,
    start_date: startDate,
    end_date: endDate,
  };

  try {
    // Perform the GET request to the NASA API with query parameters
    const response = await axios.get(url, { params });
    return response.data;
  } catch (error) {
    // Log any errors encountered during the request
    console.error('Error fetching data from NASA:', error);
    return null;
  }
}

现在,你将需要创建一个函数,通过迭代每个日期的对象来组织数据。

function createStructuredData(response) {
  const allObjects = [];
  const nearEarthObjects = response.near_earth_objects;

  Object.keys(nearEarthObjects).forEach(date => {
    nearEarthObjects[date].forEach(obj => {
      const simplifiedObject = {
        close_approach_date: date,
        name: obj.name,
        id: obj.id,
        miss_distance_km: obj.close_approach_data.length > 0 ? obj.close_approach_data[0].miss_distance.kilometers : null,
      };

      allObjects.push(simplifiedObject);
    });
  });

  return allObjects;
}

现在,你需要使用批量(bulk)索引操作将数据加载到 Elasticsearch 中。此功能应与上一节中的功能类似。

async function indexDataIntoElasticsearch(data) {
  const body = data.flatMap(doc => [{ index: { _index: 'nasa-node-js', _id: doc.id } }, doc]);
  await client.bulk({ refresh: false, body });
}

最后,你需要为将根据你设置的计时器运行的函数创建一个入口点。此函数类似于主函数​​,因为它调用文件中先前创建的函数。还有一些额外的日志记录,例如打印记录数并通知你数据是否已正确编入索引。

module.exports = async function (context, myTimer) {
  try {
    const lastUpdateDate = await getLastUpdateDate();
    context.log(`Last update date from Elasticsearch: ${lastUpdateDate}`);

    const rawData = await fetchNasaData(lastUpdateDate);
    if (rawData) {
      const structuredData = createStructuredData(rawData);
      context.log(`Number of records being uploaded: ${structuredData.length}`);
      
      if (structuredData.length > 0) {

        const flatFileData = JSON.stringify(structuredData, null, 2);
        context.log('Flat file data:', flatFileData);

        await indexDataIntoElasticsearch(structuredData);
        context.log('Data indexed successfully.');
      } else {
        context.log('No data to index.');
      }
    } else {
      context.log('Failed to fetch data from NASA.');
    }
  } catch (error) {
    context.log('Error in run process:', error);
  }

结论

使用 Node.js 和 Azure 的 Function App,你应该能够确保你的索引定期更新。通过结合使用 Node.js 的功能和 Azure 的 Function App,你可以有效地维护索引的定期更新。这种强大的组合提供了一个简化的自动化流程,减少了定期更新索引所需的手动工作量。此示例的完整代码可在 Search Labs GitHub 上找到。如果你基于此博客构建了任何内容,或者你对我们的论坛和社区 Slack 频道有疑问,请告诉我们。

准备好自己尝试一下了吗?开始免费试用。
想要获得 Elastic 认证吗?了解下一次 Elasticsearch 工程师培训何时举行!

原文:Elasticsearch index updates: Automatically update your index using Node.js and an Azure Function App — Elastic Search Labs

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

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

相关文章

Vue中引入elementUI中的container组件失效

1.不用修改官网中任何css或者html 2.按需引入,不是只是引入官网的就可以 import Vue from vue import Router from vue-router import HelloWorld from /components/HelloWorld import First from /components/views/First import Second from /components/views/…

操作失败——后端

控制台观察,页面发送的保存菜品的请求 返回的response显示: ---------- 我开始查看明明感觉都挺正常,没啥错误,就是查不出来。结果后面电脑关机重启后,隔一天看,就突然可以了。我觉着可能是浏览器的缓存没…

基本算法——位运算

a^b 原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目描述 运行代码 #include<iostream> using namespace std; long long a,b,c,t1; int main() {cin>>a>>b>>c;for(;b;b/2){if(b&1)tt*a%c;aa*a%c;}cout<<t%c; } 代码思路…

HTML5+CSS3+JS小实例:网格图库

实例:网格图库 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0&…

俄罗斯ozon平台计算器,ozon定价计算器

在数字化飞速发展的今天&#xff0c;电商平台已成为商家们展示产品、吸引顾客的重要窗口。而在俄罗斯这一广阔的市场中&#xff0c;Ozon平台以其独特的优势&#xff0c;成为了众多电商卖家的首选。然而&#xff0c;想要在Ozon平台上脱颖而出&#xff0c;除了优质的产品和服务外…

C语言(结构体)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸各位能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎~~ &#x1f4a5;个人主页&#xff1a;小羊在奋斗 &#x1f4a5;所属专栏&#xff1a;C语言 本系列文章为个人学习笔记&#xff0c;在这里撰写成文一…

基于数据帧进行SQL查询

本教程将通过一个具体的案例来演示如何在Spark SQL中基于数据帧进行SQL查询。我们将从创建临时视图开始&#xff0c;然后使用spark对象执行SQL查询&#xff0c;包括投影、选择、统计和排序等操作。 具体步骤如下&#xff1a; 基于数据帧创建临时视图&#xff1a; 命令格式&…

MySQL中所有常见知识点汇总

存储引擎 这一张是关于整个存储引擎的汇总知识了。 MySQL体系结构 这里是MySQL的体系结构图&#xff1a; 一般将MySQL分为server层和存储引擎两个部分。 其实MySQL体系结构主要分为下面这几个部分&#xff1a; 连接器&#xff1a;负责跟客户端建立连 接、获取权限、维持和管理…

MFC 教程-文本框失去焦点处理

【1】增加窗口的消息处理函数 void CTESTMFCDlg::OnKillFocus(CWnd* pNewWnd) {//CDialogEx::OnKillFocus(pNewWnd);//首先使用true将数据从控件传入成员变量中UpdateData(true);//校验成员变量m_data中的数据是否符合要求&#xff0c;如果不符合&#xff0c;修改后将它显示在控…

windows10 安装子linux系统(WSL安装方式)

在 windows 10 平台采用了WSL安装方式安装linux子系统 1 查找自己想要安装的linux子系统 wsl --list --online 2 在线安装 个人用Debian比较多&#xff0c;这里选择Debian&#xff0c;如下图&#xff1a; wsl --install -d Debian 安装完成&#xff0c;如下&#xff1a; 相关…

【kubernetes】探索k8s集群的pod控制器详解(Deployment、StatefulSet、DaemonSet、Job、CronJob)

目录 一、Pod控制器及其功用 二、pod控制器有多种类型 2.1ReplicaSet 2.1.1ReplicaSet主要三个组件组成 2.2Deployment 2.3DaemonSet 2.4StatefulSet 2.5Job 2.6Cronjob 三、Pod与控制器之间的关系 3.1Deployment 3.2SatefulSet 3.2.1StatefulSet三个组件 3.2.2为…

人事管理系统有哪些优势?5大人事管理系统大盘点!

本人研究企业数字化转型10余年&#xff0c;为企业软件选型、数字化提供咨询服务&#xff01;目前重点研究低代码数字化转型玩法&#xff0c;力争为各家企业探索出一条更具性价比的数字化方式。 人事管理系统有哪些优势&#xff1f;如何选择&#xff1f;又该怎样部署&#xff1…

从分布式训练到大模型训练

要了解大模型训练难&#xff0c;我们得先看看从传统的分布式训练&#xff0c;到大模型的出现&#xff0c;需要大规模分布式训练的原因。接着第二点去了解下大规模训练的挑战。 从分布式训练到大规模训练 常见的训练方式是单机单卡&#xff0c;也就是一台服务器配置1块AI芯片&a…

分享一个 ASP.NET WebForm 使用 Form Authentication 的例子

前言 前些天一个朋友说他们客户的网站出了点故障&#xff0c;让我帮忙看看&#xff0c;这个网站还是用 ASP.NET WebForm 做的&#xff0c;很久以前的技术了&#xff0c;不过很多客户就是这样&#xff0c;只要网站还能稳定地运行&#xff0c;一般就不会去折腾升级&#xff0c;_…

搭建基于Django的博客系统增加广告轮播图(三)

上一篇&#xff1a;ChatGPT搭建博客Django的web网页添加用户系统&#xff08;二&#xff09; 下一篇&#xff1a;搭建基于Django的博客系统数据库迁移从Sqlite3到MySQL&#xff08;四&#xff09; 功能概述 增加轮播图显示广告信息。 需求详细描述 1. 增加轮播图显示广告信…

Vue04-模版语法

一、插值语法 作用&#xff1a;将指定的值放在指定的位置。 二、指令语法 效果&#xff1a; 将href中的跳转地址&#xff0c;交给Vue实例管理&#xff1a; Vue的指令&#xff0c;以v-xxxx开头&#xff0c;以表示它们是 Vue 提供的特殊 attribute。 2-1、v-bind命令 可以给标签…

C盘清理攻略!!!详细步骤

c盘爆满怎么清&#xff0c;往下看 一、清缓存文件键盘winr打开运行窗口&#xff0c;输入&#xff1a;%temp% 二、清理安装包文件键盘winr打开运行窗口&#xff0c;输入&#xff1a;softwaredistribution 三、清理软件解压临时文件键盘winr打开运行窗口&#xff0c;输入&#xf…

使用matplotlib绘制折线条形复合图

使用matplotlib绘制折线条形复合图 介绍效果代码 介绍 在数据可视化中&#xff0c;复合图形是一种非常有用的工具&#xff0c;可以同时显示多种数据类型的关系。在本篇博客中&#xff0c;我们将探讨如何使用 matplotlib 库来绘制包含折线图和条形图的复合图。 效果 代码 imp…

[数据集][目标检测]脑肿瘤检测数据集VOC+YOLO格式9787张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;9787 标注数量(xml文件个数)&#xff1a;9787 标注数量(txt文件个数)&#xff1a;9787 标注…

代理IP类型有哪些?定义与区别

您应该对代理有了一定的了解。但是&#xff0c;代理服务器也有不同的类型。就其来源而言&#xff0c;最常见的代理服务器类型是住宅代理和数据中心代理&#xff1a; 1、住宅代理 住宅代理是 ISP 向房主提供的 IP 地址。它是与物理位置关联的真实 IP 地址&#xff0c;因此允许…