通过logstash同步elasticsearch数据

1 概述

logstash是一个对数据进行抽取、转换、输出的工具,能对接多种数据源和目标数据。本文介绍通过它来同步elasticsearch的数据。


2 环境

实验仅仅需要一台logstash机器和两台elasticsearch机器(elasticsearch v7.1.0)。本文用docker来模拟,使用docker-compose来启动elasticsearch容器。
elasticsearch机器A是192.168.243.128:9200。
elasticsearch机器B是192.168.243.128:19200。


2.1 安装elasticsearch机器A

2.1.1 编写docker-compose.yml

version: '2.2'
services:cerebro:image: lmenezes/cerebro:0.8.3container_name: cerebroports:- "9000:9000"command:- -Dhosts.0.host=http://elasticsearch:9200kibana:image: docker.elastic.co/kibana/kibana:7.1.0container_name: kibana7environment:- I18N_LOCALE=zh-CN- XPACK_GRAPH_ENABLED=true- TIMELION_ENABLED=true- XPACK_MONITORING_COLLECTION_ENABLED="true"ports:- "5601:5601"elasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0container_name: es7_01environment:- cluster.name=xttblog- node.name=es7_01- bootstrap.memory_lock=true- "ES_JAVA_OPTS=-Xms512m -Xmx512m"- discovery.seed_hosts=es7_01- cluster.initial_master_nodes=es7_01,es7_02ulimits:memlock:soft: -1hard: -1volumes:- es7data1:/usr/share/elasticsearch/dataports:- 9200:9200elasticsearch2:image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0container_name: es7_02environment:- cluster.name=xttblog- node.name=es7_02- bootstrap.memory_lock=true- "ES_JAVA_OPTS=-Xms512m -Xmx512m"- discovery.seed_hosts=es7_01- cluster.initial_master_nodes=es7_01,es7_02ulimits:memlock:soft: -1hard: -1volumes:- es7data2:/usr/share/elasticsearch/data
volumes:es7data1:driver: locales7data2:driver: local

2.1.2 修改vm.max_map_count

cat >> /etc/sysctl.conf << EOF
vm.max_map_count = 2621440
EOF
sysctl -p

2.1.3 启动

docker-compose up -d 

2.1.3 导入样例数据

localhost:5601,用于访问kibana并导入样例数据
localhost:9000,用于访问cerebro

2.2 安装elasticsearch机器B

2.2.1 编写docker-compose.yml

version: '2.2'
services:cerebro:image: lmenezes/cerebro:0.8.3container_name: cerebro-2ports:- "19000:9000"command:- -Dhosts.0.host=http://elasticsearch:9200kibana:image: docker.elastic.co/kibana/kibana:7.1.0container_name: kibana7-2environment:- I18N_LOCALE=zh-CN- XPACK_GRAPH_ENABLED=true- TIMELION_ENABLED=true- XPACK_MONITORING_COLLECTION_ENABLED="true"ports:- "15601:5601"elasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0container_name: es7_03environment:- cluster.name=xttblog- node.name=es7_03- bootstrap.memory_lock=true- "ES_JAVA_OPTS=-Xms512m -Xmx512m"- discovery.seed_hosts=es7_03- cluster.initial_master_nodes=es7_03,es7_04ulimits:memlock:soft: -1hard: -1volumes:- es7data3:/usr/share/elasticsearch/dataports:- 19200:9200elasticsearch2:image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0container_name: es7_04environment:- cluster.name=xttblog- node.name=es7_04- bootstrap.memory_lock=true- "ES_JAVA_OPTS=-Xms512m -Xmx512m"- discovery.seed_hosts=es7_03- cluster.initial_master_nodes=es7_03,es7_04ulimits:memlock:soft: -1hard: -1volumes:- es7data4:/usr/share/elasticsearch/data
volumes:es7data3:driver: locales7data4:driver: local

2.2.2 修改vm.max_map_count

cat >> /etc/sysctl.conf << EOF
vm.max_map_count = 2621440
EOF
sysctl -p

2.2.3 启动

docker-compose up -d 

2.2 logstash机器上准备python环境

在centos7机器上执行如下命令,可安装python环境:

yum install python2
yum install python-pip

由于python脚本需要导入requests模块哈yaml模块,因此需要执行如下命令在机器上安装python模块:

pip install pyyaml
pip install requests

2.2 logstash机器上准备python脚本

2.2.1 准备migrateConfig.yaml

本文件用于描述源端和目标端是谁,是否开启SSL连接。
一般只需要修改src_ip、dest_ip。

cat > /tmp/migrateConfig.yaml << EOF
es_cluster_new:# 源集群的名称clustername: es_cluster_new# 源Elasticsearch集群的访问地址,加上“http://”。src_ip: http://x.x.x.x:9200# 访问源Elasticsearch集群的用户名和密码,如果为非安全集群则设置为""。src_username: ""src_password: ""# 目标Elasticsearch集群的访问地址,加上“http://”。dest_ip: http://x.x.x.x:9200# 访问目标Elasticsearch集群的用户名和密码,如果为非安全集群则设置为""。dest_username: ""dest_password: ""# only_mapping 可以不定义,默认值为false,需要搭配“migrateMapping.py”使用,表示是否只处理这个文件中mapping地址的索引。#  当设置成false时,则迁移源集群中除“.kibana”和“.*”之外的所有索引数据。#  当设置成true时,则只迁移源集群中和下面mapping的key一致的索引数据;迁移过程中会将索引名称与下面的mapping匹配,如果匹配一致,则使用mapping的value作为目标集群的索引名称;如果匹配不到,则使用源集群原始的索引名称。only_mapping: false# 当only_mapping = true时,mapping用于设置要迁移的索引,key为源集群的索引名字,value为目标集群的索引名字。mapping:test_index_1: test_index_1# only_compare_index 可以不定义,默认值为false,需要搭配“checkIndices.py”使用,当设置为false会比较所有的索引和文档数量,当设置为true只比较索引数量。only_compare_index: false  
EOF

2.2.1 准备migrateTemplate.py

用于迁移索引模板,此文件不需要修改,直接复制。

cat > /tmp/migrateTemplate.py << EOF
# -*- coding:UTF-8 -*-
import sys
import yaml
import requests
import json
import osdef printDividingLine():print("<=============================================================>")def loadConfig(argv):if argv is None or len(argv) != 2:config_yaml = "migrateConfig.yaml"else:config_yaml = argv[1]config_file = open(config_yaml)# config = yaml.load(config_file, Loader=yaml.FullLoader)return yaml.load(config_file)def put_template_to_target(url, template, cluster, template_name, dest_auth=None):headers = {'Content-Type': 'application/json'}create_resp = requests.put(url, headers=headers, data=json.dumps(template), auth=dest_auth, verify=False)if not os.path.exists("templateLogs"):os.makedirs("templateLogs")if create_resp.status_code != 200:print("create template " + url + " failed with response: " + str(create_resp) + ", source template is " + template_name)print(create_resp.text)filename = "templateLogs/" + str(cluster) + "#" + template_namewith open(filename + ".json", "w") as f:json.dump(template, f)return Falseelse:return Truedef main(argv):requests.packages.urllib3.disable_warnings()print("begin to migration template!")config = loadConfig(argv)src_clusters = config.keys()print("process cluster name:")for name in src_clusters:print(name)print("cluster total number:" + str(src_clusters.__len__()))for name, value in config.items():printDividingLine()source_user = value["src_username"]source_passwd = value["src_password"]source_auth = Noneif source_user != "":source_auth = (source_user, source_passwd)dest_user = value["dest_username"]dest_passwd = value["dest_password"]dest_auth = Noneif dest_user != "":dest_auth = (dest_user, dest_passwd)print("start to process cluster name:" + name)source_url = value["src_ip"] + "/_template"response = requests.get(source_url, auth=source_auth, verify=False)if response.status_code != 200:print("*** get all template failed. resp statusCode:" + str(response.status_code) + " response is " + response.text)continueall_template = response.json()migrate_itemplate = []for template in all_template.keys():if template.startswith(".") or template == "logstash":continueif "index_patterns" in all_template[template]:for t in all_template[template]["index_patterns"]:# if "kibana" in template:if t.startswith("."):continuemigrate_itemplate.append(template)for template in migrate_itemplate:dest_index_url = value["dest_ip"] + "/_template/" + templateresult = put_template_to_target(dest_index_url, all_template[template], name, template, dest_auth)if result is True:print('[success] delete success, cluster: %-10s, template %-10s ' % (str(name), str(template)))else:print('[failure] delete failure, cluster: %-10s, template %-10s ' % (str(name), str(template)))if __name__ == '__main__':main(sys.argv)EOF

2.2.1 准备migrateMapping.py

脚本用于迁移索的表结构,此文件不需要修改,直接复制。

cat > /tmp/migrateMapping.py << EOF
# -*- coding:UTF-8 -*-
import sys
import yaml
import requests
import re
import json
import osdef printDividingLine():print("<=============================================================>")def loadConfig(argv):if argv is None or len(argv) != 2:config_yaml = "migrateConfig.yaml"else:config_yaml = argv[1]config_file = open(config_yaml)# config = yaml.load(config_file, Loader=yaml.FullLoader)return yaml.load(config_file)def get_cluster_version(url, auth=None):response = requests.get(url, auth=auth)if response.status_code != 200:print("*** get ElasticSearch message failed. resp statusCode:" + str(response.status_code) + " response is " + response.text)return Falsecluster = response.json()version = cluster["version"]["number"]return Truedef process_mapping(index_mapping, dest_index):# remove unnecessary keysdel index_mapping["settings"]["index"]["provided_name"]del index_mapping["settings"]["index"]["uuid"]del index_mapping["settings"]["index"]["creation_date"]del index_mapping["settings"]["index"]["version"]if "lifecycle" in index_mapping["settings"]["index"]:del index_mapping["settings"]["index"]["lifecycle"]# check aliasaliases = index_mapping["aliases"]for alias in list(aliases.keys()):if alias == dest_index:print("source index " + dest_index + " alias " + alias + " is the same as dest_index name, will remove this alias.")del index_mapping["aliases"][alias]# if index_mapping["settings"]["index"].has_key("lifecycle"):if "lifecycle" in index_mapping["settings"]["index"]:lifecycle = index_mapping["settings"]["index"]["lifecycle"]opendistro = {"opendistro": {"index_state_management":{"policy_id": lifecycle["name"],"rollover_alias": lifecycle["rollover_alias"]}}}index_mapping["settings"].update(opendistro)# index_mapping["settings"]["opendistro"]["index_state_management"]["rollover_alias"] = lifecycle["rollover_alias"]del index_mapping["settings"]["index"]["lifecycle"]# replace synonyms_pathif "analysis" in index_mapping["settings"]["index"]:analysis = index_mapping["settings"]["index"]["analysis"]if "filter" in analysis:filter = analysis["filter"]if "my_synonym_filter" in filter:my_synonym_filter = filter["my_synonym_filter"]if "synonyms_path" in my_synonym_filter:index_mapping["settings"]["index"]["analysis"]["filter"]["my_synonym_filter"]["synonyms_path"] = "/rds/datastore/elasticsearch/v7.10.2/package/elasticsearch-7.10.2/plugins/analysis-dynamic-synonym/config/synonyms.txt"return index_mappingdef getAlias(source, source_auth):# get all indicesresponse = requests.get(source + "/_alias", auth=source_auth)if response.status_code != 200:print("*** get all index failed. resp statusCode:" + str(response.status_code) + " response is " + response.text)exit()all_index = response.json()system_index = []create_index = []for index in list(all_index.keys()):if (index.startswith(".")):system_index.append(index)else:create_index.append(index)return system_index, create_indexdef put_mapping_to_target(url, mapping, cluster, source_index, dest_auth=None):headers = {'Content-Type': 'application/json'}create_resp = requests.put(url, headers=headers, data=json.dumps(mapping), auth=dest_auth, verify=False)if not os.path.exists("mappingLogs"):os.makedirs("mappingLogs")if create_resp.status_code != 200:print("create index " + url + " failed with response: " + str(create_resp) +", source index is " + str(source_index))print(create_resp.text)filename = "mappingLogs/" + str(cluster) + "#" + str(source_index)with open(filename + ".json", "w") as f:json.dump(mapping, f)return Falseelse:return Truedef main(argv):requests.packages.urllib3.disable_warnings()print("begin to migrate index mapping!")config = loadConfig(argv)src_clusters = config.keys()print("begin to process cluster name :")for name in src_clusters:print(name)print("cluster count:" + str(src_clusters.__len__()))for name, value in config.items():printDividingLine()source = value["src_ip"]source_user = value["src_username"]source_passwd = value["src_password"]source_auth = Noneif source_user != "":source_auth = (source_user, source_passwd)dest = value["dest_ip"]dest_user = value["dest_username"]dest_passwd = value["dest_password"]dest_auth = Noneif dest_user != "":dest_auth = (dest_user, dest_passwd)print("start to process cluster:   " + name)# only deal with mapping listif 'only_mapping' in value and value["only_mapping"]:for source_index, dest_index in value["mapping"].iteritems():print("start to process source index" + source_index + ", target index: " + dest_index)source_url = source + "/" + source_indexresponse = requests.get(source_url, auth=source_auth)if response.status_code != 200:print("*** get ElasticSearch message failed. resp statusCode:" + str(response.status_code) + " response is " + response.text)continuemapping = response.json()index_mapping = process_mapping(mapping[source_index], dest_index)dest_url = dest + "/" + dest_indexresult = put_mapping_to_target(dest_url, index_mapping, name, source_index, dest_auth)if result is False:print("cluster name:" + name + ", " + source_index + ":failure")continueprint("cluster name:" + name + ", " + source_index + ":success")else:# get all indicessystem_index, create_index = getAlias(source, source_auth)success_index = 0for index in create_index:source_url = source + "/" + indexindex_response = requests.get(source_url, auth=source_auth)if index_response.status_code != 200:print("*** get ElasticSearch message failed. resp statusCode:" + str(index_response.status_code) + " response is " + index_response.text)continuemapping = index_response.json()dest_index = indexif 'mapping' in value:if index in value["mapping"].keys():dest_index = value["mapping"][index]index_mapping = process_mapping(mapping[index], dest_index)dest_url = dest + "/" + dest_indexresult = put_mapping_to_target(dest_url, index_mapping, name, index, dest_auth)if result is False:print("[failure]: migrate mapping cluster name: " + name + ", " + index)continueprint("[success]: migrate mapping cluster name: " + name + ", " + index)success_index = success_index + 1print("create index mapping success total: " + str(success_index))if __name__ == '__main__':main(sys.argv)EOF

3 同步数据

3.1 同步元数据

python /tmp/migrateTemplate.py
python /tmp/migrateMapping.py

3.2 同步实际数据

准备logstash.conf文件,放在/tmp/目录中即可。需要在logstash.conf指定源端和目标端,待同步数据的索引有哪些。
实际需要改动字段是input.elasticsearch.hosts 、input.elasticsearch.index,output.elasticsearch.hosts。

vim /tmp/logstash.conf,输入以下内容:

input{elasticsearch{# 源Elasticsearch的访问地址,不需要添加协议,添加HTTPS协议会导致报错。hosts =>  ["192.168.243.128:9200"]# 访问源集群的用户名和密码,非安全集群无需配置。# user => "css_logstash"# password => "*****"# 配置待迁移的索引信息,多个索引以逗号隔开,可以使用通配符设置,例如“index*”。index => "kibana_sample_data_flights,kibana_sample_data_ecommerce"docinfo => trueslices => 3size => 3000# 当源集群是HTTPS访问方式时,则设置ssl => false。# ssl => false}}# 移除一些logstash增加的字段。filter {mutate {remove_field => ["@metadata", "@version"]}}output{elasticsearch{# 目标Elasticsearch集群的访问地址hosts =>  ["192.168.243.128:19200"]# 访问目标集群的用户名和密码,非安全集群无需配置。# user => "css_logstash"# password => "*****"# 配置目标集群的索引,以下配置为索引名称和源端保持一致,保持默认。index => "%{[@metadata][_index]}"document_type => "%{[@metadata][_type]}"document_id => "%{[@metadata][_id]}"# 当目标集群是HTTPS访问方式时,则需额外配置以下信息。# 配置集群HTTPS访问证书,CSS集群保持以下不变。     #cacert => "/rds/datastore/logstash/v7.10.0/package/logstash-7.10.0/extend/certs/CloudSearchService.cer" # 是否开启HTTPS通信,HTTPS访问集群则设置为true。#ssl => true# 是否验证服务端Elasticsearch证书,设置为false表示不验证证书。#ssl_certificate_verification => false}}

执行如下命令来启动logstash进程,进程执行完后会自动退出:

docker run -it --rm -v /tmp/logstash.conf:/tmp/logstash.conf docker.elastic.co/logstash/logstash:7.1.0 logstash -f /tmp/logstash.conf

在这里插入图片描述

4 小结

logstash可用于同步elasticsearch的数据,不仅可以进行全量同步,其实还能进行增量同步(数据带时间字段,用该字段进行query即可抽取出增量的数据),虽然本文没演示增量同步。

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

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

相关文章

css 样式简单学习(一)

目录 1. css 介绍 1.1 css 样式 1.2 css代码风格 1.2.1 书写格式 1.2.2 样式大小写​编辑 1.2.3 空格规范 2. 基础选择器 2.1 选择器的作用​编辑 2.2 选择器的分类 2.3 基础选择器 2.3.1 标签选择器​编辑 2.3.2 类选择器​编辑 2.3.3 类选择器-多类名​编辑 2.…

简单题88. 合并两个有序数组 (Python)20240920

问题描述&#xff1a; python&#xff1a; class Solution(object):def merge(self, nums1, m, nums2, n):""":type nums1: List[int]:type m: int:type nums2: List[int]:type n: int:rtype: None Do not return anything, modify nums1 in-place instead.&qu…

选址模型 | 基于混沌模拟退火粒子群优化算法的电动汽车充电站选址与定容(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于混沌模拟退火粒子群优化算法的电动汽车充电站选址与定容&#xff08;Matlab&#xff09; 问题建模&#xff1a;首先&#xff0c;需要将电动汽车充电站选址与定容问题进行数学建模&#xff0c;确定目标函数和约束…

React18入门教程

React介绍 React由Meta公司开发&#xff0c;是一个用于 构建Web和原生交互界面的库 React的优势 相较于传统基于DOM开发的优势 组件化的开发方式 不错的性能 相较于其它前端框架的优势 丰富的生态 跨平台支持 React的市场情况 全球最流行&#xff0c;大厂必备 开发环境…

【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL24

边沿检测 有一个缓慢变化的1bit信号a&#xff0c;编写一个程序检测a信号的上升沿给出指示信号rise&#xff0c;当a信号出现下降沿时给出指示信号down。 注&#xff1a;rise,down应为单脉冲信号&#xff0c;在相应边沿出现时的下一个时钟为高&#xff0c;之后恢复到0&#xff0…

密集行人数据集 CrowdHumanvoc和yolo两种格式,yolo可以直接使用train val test已经划分好有yolov8训练200轮模型

密集行人数据集 CrowdHuman voc和yolo两种格式&#xff0c;yolo可以直接使用 train val test已经划分好 有yolov8训练200轮模型。 CrowdHuman 密集行人检测数据集 数据集描述 CrowdHuman数据集是一个专为密集行人检测设计的数据集&#xff0c;旨在解决行人密集场景下的检测挑…

关于实时数仓的几点技术分享

一、实时数仓建设背景 业务需求的变化&#xff1a;随着互联网和移动互联网的快速发展&#xff0c;企业的业务需求变得越来越复杂和多样化&#xff0c;对数据处理的速度和质量要求也越来越高。传统的T1数据处理模式已经无法满足企业的需求&#xff0c;实时数据处理成为了一种必…

什么是 IP 地址信誉?5 种改进方法

IP 地址声誉是营销中广泛使用的概念。它衡量 IP 地址的质量&#xff0c;这意味着您的电子邮件进入垃圾邮件或被完全阻止发送的可能性。 由于每个人都使用专用电子邮件提供商而不是直接通过 IP 地址进行通信&#xff0c;因此&#xff0c;这些服务可以跟踪和衡量发件人的行为质量…

表情包创作、取图小程序端(带流量主)

小程序永久免费&#xff0c;无任何广告&#xff0c;无任何违规功能&#xff01; 小程序具备以下功能有&#xff1a; 支持创作者加入 支持在线制作表情包 使用说明 表情包必备工具&#xff0c;一款专属于你的制作表情包工具&#xff0c;斗图必备神器

Linux下进程通信与FIFO操作详解

Linux下进程通信与FIFO操作详解 一、命名管道(FIFO)概述1.1 命名管道的特点1.2 创建命名管道二、命名管道的操作2.1 打开命名管道2.2 读写命名管道2.3 关闭命名管道三、命名管道的使用实例3.1 命名管道的创建和通信过程3.1.1 发送方(writer)3.1.2 接收方(reader)3.2 运行…

python 爬虫 selenium 笔记

todo 阅读并熟悉 Xpath, 这个与 Selenium 密切相关、 selenium selenium 加入无图模式&#xff0c;速度快很多。 from selenium import webdriver from selenium.webdriver.chrome.options import Options# selenium 无图模式&#xff0c;速度快很多。 option Options() o…

Qt/C++事件过滤器与控件响应重写的使用、场景的不同

在Qt/C中&#xff0c;事件过滤器和控件响应重写是两种用于捕获和处理鼠标、键盘等事件的机制&#xff0c;它们的用途和使用场景不同&#xff0c;各有优劣。下面详细介绍它们的区别、各自适用的场景、以及混合使用的场景和注意事项。 1. 事件过滤器&#xff08;Event Filter&…

全能OCR神器GOT-OCR2.0整合包部署教程

项目地址:https://github.com/Ucas-HaoranWei/GOT-OCR2.0 整合包下载&#xff1a;https://pan.quark.cn/s/3757da820e65 显卡建议使用RTX 30以上的 ①先安装NVIDIA显卡驱动&#xff1a; https://www.nvidia.cn/drivers/lookup/ 输入显卡型号搜索就行 ②安装CUDA 工具包 cu…

Django 聚合查询

文章目录 一、聚合查询二、使用步骤1.准备工作2.具体使用3.分组查询&#xff08;annotate&#xff09;1.定义2.使用3.具体案例 4.F() 查询1.定义2.使用 5.Q() 查询1.定义2.查询 一、聚合查询 使用聚合查询前要先从 django.db.models 引入 Avg、Max、Min、Count、Sum&#xff0…

力扣 2529.正整数和负整数的最大计数

文章目录 题目介绍解法 题目介绍 解法 采用红蓝染色体法&#xff0c;具体介绍参考 红蓝染色体法 通过红蓝染色体法可以找到第一个大于大于target的位置&#xff0c;使所以本题可以找第一个大于0的位置&#xff0c;即负整数的个数&#xff1b;数组长度 - 第一个大于1的位置即正…

【踩坑】装了显卡,如何让显示器从主板和显卡HDMI都输出

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 背景介绍 装了显卡后&#xff0c;开机默认是从显卡的HDMI输出&#xff0c;但这很不方便。如何让视频仍然从主板输出&#xff1f;或者说让显卡HDMI和主板…

切线空间:unity中shader切线空间,切线矩阵,TBN矩阵 ,法线贴图深度剖析

unity中shader切线空间 看了网上各种解释&#xff0c;各种推理。直接脑袋大。感觉复杂的高大上。当深入了解后&#xff0c;才发是各种扯淡。 一切从模型法向量开始 在shader中&#xff0c;大部分的光照计算都是与法向量有关。通过法向量和其他向量能计算出模型在光线照射下的…

MyBatis-Plus分页查询、分组查询

目录 准备工作1. 实体类2. Mapper类3. 分页插件4. 数据 分页查询1. 使用条件构造器2. 使用自定义sql 分组查询1. 分组结果类2. 自定义sql3. 测试类 准备工作 1. 实体类 对地址字段address使用字段类型转换器&#xff0c;将List转为字符串数组保存在数据库中 package com.exa…

【CSS Tricks】一种基于AV1视频格式的现代图像格式-AVIF

引言 AV1图像文件格式&#xff08;英语&#xff1a;AV1 Image File Format&#xff0c;简称AVIF&#xff09;是由开放媒体联盟&#xff08;AOM&#xff09;开发&#xff0c;采用AV1视讯编码技术压缩图像的一种图像文件格式&#xff0c;能用来储存一般的图像和动态图像。AVIF和苹…

torch.embedding 报错 IndexError: index out of range in self

文章目录 1. 报错2. 原因3. 解决方法 1. 报错 torch.embedding 报错&#xff1a; IndexError: index out of range in self2. 原因 首先看下正常情况&#xff1a; import torch import torch.nn.functional as Finputs torch.tensor([[1, 2, 4, 5], [4, 3, 2, 9]]) embedd…