在SpringBoot项目中使用多线程(配合线程池)加快从MySQL导入数据到ElasticSearch的速度

news2024/9/19 17:39:16

文章目录

  • 1. 准备工作
    • 1.1 索引库
    • 1.2 建表
    • 1.3 实体类
      • 1.3.1 item.java
      • 1.3.2 itemDocument.java
    • 1.4 编写配置文件
    • 1.5 编写 Mapper 类和 Service 类
  • 2. 没有使用多线程的情况
    • 2.1 编码
    • 2.2 测试结果
  • 3. 使用多线程(配合线程池)的情况
    • 3.1 自定义类,实现 Runnable 接口
    • 3.2 编码(结合线程池)
    • 3.3 测试
  • 4. 对比及分析

1. 准备工作

测试环境:

  • JDK 17.0.7
  • SpringBoot 3.0.2
  • MySQL 8.0.34
  • ElasticSearch 7.17.18

本次测试主要利用的是 Mybatis Plus、PageHelper、fastjson2

MybatisPlus 的 Maven 依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

PageHelper 的 Maven 依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>2.1.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

fastjson2的 Maven 依赖

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.50</version>
</dependency>

1.1 索引库

创建一个名为 shopping_mall 的索引库

{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "price": {
        "type": "integer"
      },
      "image": {
        "type": "keyword",
        "index": false
      },
      "category": {
        "type": "keyword"
      },
      "brand": {
        "type": "keyword"
      },
      "sold": {
        "type": "integer"
      },
      "commentCount": {
        "type": "integer",
        "index": false
      },
      "isAD": {
        "type": "boolean"
      },
      "updateTime": {
        "type": "date"
      }
    }
  }
}

1.2 建表

表名为 item,表结构如下(由于表中有 88476 条数据,无法在这里展示,需要具体的数据可以私聊我获取 SQL 文件)

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 80034 (8.0.34)
 Source Host           : localhost:3306
 Source Schema         : blog

 Target Server Type    : MySQL
 Target Server Version : 80034 (8.0.34)
 File Encoding         : 65001

 Date: 25/08/2024 01:59:24
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for item
-- ----------------------------
DROP TABLE IF EXISTS `item`;
CREATE TABLE `item`  (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '商品id',
  `name` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'SKU名称',
  `price` int NOT NULL DEFAULT 0 COMMENT '价格(分)',
  `stock` int UNSIGNED NOT NULL COMMENT '库存数量',
  `image` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '商品图片',
  `category` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '类目名称',
  `brand` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '品牌名称',
  `spec` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '规格',
  `sold` int NULL DEFAULT 0 COMMENT '销量',
  `comment_count` int NULL DEFAULT 0 COMMENT '评论数',
  `isAD` tinyint(1) NULL DEFAULT 0 COMMENT '是否是推广广告,true/false',
  `status` int NULL DEFAULT 2 COMMENT '商品状态 1-正常,2-下架,3-删除',
  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `creater` bigint NULL DEFAULT NULL COMMENT '创建人',
  `updater` bigint NULL DEFAULT NULL COMMENT '修改人',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `status`(`status` ASC) USING BTREE,
  INDEX `updated`(`update_time` ASC) USING BTREE,
  INDEX `category`(`category` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 100002672305 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '商品表' ROW_FORMAT = COMPACT;

SET FOREIGN_KEY_CHECKS = 1;

1.3 实体类

1.3.1 item.java

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;

@TableName("item")
public class Item implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /**
     * 商品id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * SKU名称
     */
    private String name;

    /**
     * 价格(分)
     */
    private Integer price;

    /**
     * 库存数量
     */
    private Integer stock;

    /**
     * 商品图片
     */
    private String image;

    /**
     * 类目名称
     */
    private String category;

    /**
     * 品牌名称
     */
    private String brand;

    /**
     * 规格
     */
    private String spec;

    /**
     * 销量
     */
    private Integer sold;

    /**
     * 评论数
     */
    private Integer commentCount;

    /**
     * 是否是推广广告,true/false
     */
    @TableField("isAD")
    private Boolean isAD;

    /**
     * 商品状态 1-正常,2-下架,3-删除
     */
    private Integer status;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;

    /**
     * 创建人
     */
    private Long creater;

    /**
     * 修改人
     */
    private Long updater;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getSpec() {
        return spec;
    }

    public void setSpec(String spec) {
        this.spec = spec;
    }

    public Integer getSold() {
        return sold;
    }

    public void setSold(Integer sold) {
        this.sold = sold;
    }

    public Integer getCommentCount() {
        return commentCount;
    }

    public void setCommentCount(Integer commentCount) {
        this.commentCount = commentCount;
    }

    public Boolean getIsAD() {
        return isAD;
    }

    public void setIsAD(Boolean AD) {
        isAD = AD;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public LocalDateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }

    public Long getCreater() {
        return creater;
    }

    public void setCreater(Long creater) {
        this.creater = creater;
    }

    public Long getUpdater() {
        return updater;
    }

    public void setUpdater(Long updater) {
        this.updater = updater;
    }

    @Override
    public String toString() {
        return "Item{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                ", image='" + image + '\'' +
                ", category='" + category + '\'' +
                ", brand='" + brand + '\'' +
                ", spec='" + spec + '\'' +
                ", sold=" + sold +
                ", commentCount=" + commentCount +
                ", isAD=" + isAD +
                ", status=" + status +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                ", creater=" + creater +
                ", updater=" + updater +
                '}';
    }

}

1.3.2 itemDocument.java

import java.time.LocalDateTime;

/**
 * 索引库实体类
 */
public class ItemDocument {
    
    private Long id;

    private String name;

    private Integer price;

    private Integer stock;

    private String image;

    private String category;

    private String brand;

    private Integer sold;

    private Integer commentCount;

    private Boolean isAD;

    private LocalDateTime updateTime;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Integer getSold() {
        return sold;
    }

    public void setSold(Integer sold) {
        this.sold = sold;
    }

    public Integer getCommentCount() {
        return commentCount;
    }

    public void setCommentCount(Integer commentCount) {
        this.commentCount = commentCount;
    }

    public Boolean getIsAD() {
        return isAD;
    }

    public void setIsAD(Boolean AD) {
        isAD = AD;
    }

    public LocalDateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }

    @Override
    public String toString() {
        return "ItemDocument{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                ", image='" + image + '\'' +
                ", category='" + category + '\'' +
                ", brand='" + brand + '\'' +
                ", sold=" + sold +
                ", commentCount=" + commentCount +
                ", isAD=" + isAD +
                ", updateTime=" + updateTime +
                '}';
    }

}

1.4 编写配置文件

编写配置文件前,先导入 MySQL 连接驱动的 Maven 依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

application.yaml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

编写完配置文件后,在项目的启动类上添加 @MapperScan 注解,指定 Mapper 所在的包

@MapperScan("cn.edu.scau.mapper")

1.5 编写 Mapper 类和 Service 类

ItemMapper.java

import cn.edu.scau.pojo.Item;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface ItemMapper extends BaseMapper<Item> {

}

ItemService.java

import cn.edu.scau.pojo.Item;
import com.baomidou.mybatisplus.extension.service.IService;

public interface ItemService extends IService<Item> {

}

ItemServiceImpl.java

import cn.edu.scau.mapper.ItemMapper;
import cn.edu.scau.pojo.Item;
import cn.edu.scau.service.ItemService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;


@Service
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements ItemService {

}

完成上述工作后,编写一个测试类,检查 ItemServiceImpl 类能否正常工作

import cn.edu.scau.service.ItemService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ItemServiceTests {

    @Autowired
    private ItemService itemService;

    @Test
    public void test() {
        System.out.println(itemService.getById(317578L));
    }

}

2. 没有使用多线程的情况

我们先来测试一下没有使用多线程的情况

2.1 编码

import cn.edu.scau.pojo.Item;
import cn.edu.scau.pojo.ItemDocument;
import cn.edu.scau.service.ItemService;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;


@SpringBootTest
public class BulkInsertDocumentTests {

    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private ItemService itemService;

    @Test
    public void testBulkInsertDocument() throws Exception {
        int pageNumber = 1;
        int pageSize = 500;
        while (true) {
            // 1.准备文档数据
            QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(Item::getStatus, 1);
            PageHelper.startPage(pageNumber, pageSize);
            List<Item> itemList = itemService.list(queryWrapper);

            if (itemList == null || itemList.isEmpty()) {
                return;
            }

            // 2.准备 BulkRequest 对象
            BulkRequest bulkRequest = new BulkRequest();

            // 3.准备请求参数
            ItemDocument itemDocument;
            for (Item item : itemList) {
                itemDocument = new ItemDocument();
                BeanUtils.copyProperties(item, itemDocument);
                bulkRequest.add(new IndexRequest("shopping_mall")
                        .id(item.getId().toString())
                        .source(JSON.toJSONString(itemDocument), XContentType.JSON));
            }

            // 4.发送请求
            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            // 5.翻页
            pageNumber++;
        }
    }

    @BeforeEach
    public void setUp() {
        restHighLevelClient = new RestHighLevelClient(RestClient.builder(
                new HttpHost("127.0.0.1", 9200, "http")
        ));
    }

    @AfterEach
    public void tearDown() throws Exception {
        restHighLevelClient.close();
    }

}

2.2 测试结果

GET /shopping_mall/_count

共有 88475 条数据

  1. 第一次导入耗时 36 秒 954 毫秒
  2. 第二次导入耗时 38 秒 454 毫秒
  3. 第三次导入耗时 38 秒 910 毫秒
  4. 第四次导入耗时 40 秒 671毫秒
  5. 第五次导入耗时 38 秒 958毫秒
  6. 第六次导入耗时 38 秒 470毫秒

3. 使用多线程(配合线程池)的情况

3.1 自定义类,实现 Runnable 接口

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

public class InsertDocumentThread implements Runnable {

    private final RestHighLevelClient restHighLevelClient;

    private final BulkRequest bulkRequest;

    private final CountDownLatch countDownLatch;

    public InsertDocumentThread(RestHighLevelClient restHighLevelClient, BulkRequest bulkRequest, CountDownLatch countDownLatch) {
        this.restHighLevelClient = restHighLevelClient;
        this.bulkRequest = bulkRequest;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            countDownLatch.countDown();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

3.2 编码(结合线程池)

@Test
public void testBulkInsertDocumentWithMultipleThread() {
    int availableProcessors = Runtime.getRuntime().availableProcessors();
    LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>(1000);
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            2 * availableProcessors,
            4 * availableProcessors,
            100,
            TimeUnit.SECONDS,
            linkedBlockingQueue,
            Thread::new,
            new ThreadPoolExecutor.DiscardPolicy()
    );

    int pageNumber = 1;
    int pageSize = 500;
    long count = itemService.count() % pageSize == 0 ? itemService.count() / pageSize : itemService.count() / pageSize + 1;
    CountDownLatch countDownLatch = new CountDownLatch((int) count);

    long start = System.currentTimeMillis();
    while (true) {
        // 1.准备文档数据
        QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Item::getStatus, 1);
        PageHelper.startPage(pageNumber, pageSize);
        List<Item> itemList = itemService.list(queryWrapper);

        if (itemList == null || itemList.isEmpty()) {
            break;
        }

        // 2.准备 BulkRequest 对象
        BulkRequest bulkRequest = new BulkRequest();

        // 3.准备请求参数
        ItemDocument itemDocument;
        for (Item item : itemList) {
            itemDocument = new ItemDocument();
            BeanUtils.copyProperties(item, itemDocument);
            bulkRequest.add(new IndexRequest("shopping_mall")
                    .id(item.getId().toString())
                    .source(JSON.toJSONString(itemDocument), XContentType.JSON));
        }

        // 4.发送请求
        InsertDocumentThread insertDocumentThread = new InsertDocumentThread(restHighLevelClient, bulkRequest, countDownLatch);
        threadPoolExecutor.submit(insertDocumentThread);

        // 5.翻页
        pageNumber++;
    }

    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    long end = System.currentTimeMillis();
    System.out.println("耗时:" + (end - start) / 1000 + "秒 " + (end - start) % 1000 + " 毫秒");
}

3.3 测试

DELETE /shopping_mall

我们先删除 shopping_mall 索引库,再次进行批量导入操作


GET /shopping_mall/_count

共导入 88475 条数据

  1. 第一次导入耗时 30秒 657 毫秒
  2. 第二次导入耗时 35 秒 200 毫秒
  3. 第三次导入耗时 32 秒 265 毫秒
  4. 第四次导入耗时 34 秒 11 毫秒
  5. 第五次导入耗时 30 秒 778 毫秒
  6. 第六次导入耗时 32 秒 861 毫秒

4. 对比及分析

在这里插入图片描述

通过对比可以发现,使用多线程从 MySQL 批量导入数据到 ElasticSearch,虽然速度提升了一点,但是不多,可能是因为以下原因:

  1. 服务器的 CPU 核心数:我在做测试时,数据库用的是本地的,但 ElasticSearch 用的是云服务器,云服务器的 CPU 配置是 2 核,这也可能是导致使用多线程批量导入数据速度提升不明显的原因
  2. I/O 密集型操作:Elasticsearch 的索引操作通常是 I/O 密集型的,这意味着瓶颈可能在于网络延迟和 Elasticsearch 服务器的响应时间,而不是 CPU 的处理能力,在这种情况下,增加线程数可能不会显著提高性能,因为 I/O 操作无法并行执行得更快
  3. 网络带宽限制:网络带宽可能是瓶颈(我使用的云服务器的带宽是 6M),特别是在批量插入大量数据时

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

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

相关文章

EM-7肽;EM-7-NH2;CAS:289632-61-7

【EM-7 简介】 EM-7&#xff0c;也被称为EM-7-NH2&#xff0c;其化学名称为[D-Glu5,D-Trp7,9,10]-Substance P (5-11)&#xff0c;分子式为C57H66N12O10S&#xff0c;分子量为1111.273。 【中文名称】(D-谷氨酰 5,D-色氨酰 7,9,10)-物质 P (5-11) 【英文名称】(D-Glu5,D-Trp7…

openlayers+vite+vue3实现规划某一特定行政区(二)

在前一期实现离线地图初始化的基础上&#xff0c;本文中主要阐述如何实现规划某一特定行政区&#xff0c;并展示其行政区的区县名称。 提示&#xff1a;因前文中阐述了如何实现离线地图的初始化&#xff0c;所以在此不再进行书写并详解初始化的过程和流程&#xff0c;如有不明…

Task-Embedded Control Networks for Few-Shot Imitation Learning

发表时间&#xff1a;CoRL 2018 论文链接&#xff1a;https://readpaper.com/pdf-annotate/note?pdfId4500197057754718210&noteId2424798567891365120 作者单位&#xff1a;Imperial College London Motivation&#xff1a;就像人类一样&#xff0c;机器人应该能够利用来…

力扣经典题目之->另一颗树的子树(subRoot是否是root的子树)

一&#xff1a;题目 本题需要用到力扣经典题目之-&#xff1e;相同的树&#xff08;递归判断两颗二叉树是否相同&#xff09;-CSDN博客 中的isSameTree&#xff0c;直接cv即可。 二&#xff1a;代码 三&#xff1a;解释 第一个函数&#xff1a; 力扣经典题目之-&#xff1e;相…

模型 分形理论

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。自相似&#xff0c;无限细节。 1 分形理论的应用 1.1 字节跳动的分形创新增长引擎 字节跳动作为一家全球领先的科技公司&#xff0c;其快速的发展和创新能力在业界引起了广泛关注。公司通过分形创新…

大数据-105 Spark GraphX 基本概述 与 架构基础 概念详解 核心数据结构

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

使用myAGV、Jetson Nano主板和3D摄像头,实现了RTAB-Map的三维建图功能!

引言 在现代机器人技术中&#xff0c;高精度的环境感知与建图是实现自主导航的关键。本文将展示如何使用myAGV Jetson Nano移动平台搭载Jetson Nano BO1主板&#xff0c;结合RTAB-Map和3D相机&#xff0c;实现更加立体和细致的环境建图。myAGV Jetson Nano具备SLAM雷达导航功能…

es的简易dsl语句

数据模式为文档&#xff0c;_doc格式数据&#xff0c;也就是json 数据 es根据_id查询数据 GET /index_name/_doc/document_id es根据_id删除数据 DELETE /index_name/_doc/document_id es查询mapping结构 GET /index_name/_mappings es查询index下所有数据&#xff08;突破100…

9、LLaMA-Factory项目微调介绍

1、LLaMA Factory 介绍 LLaMA Factory是一个在GitHub上开源的项目&#xff0c;该项目给自身的定位是&#xff1a;提供一个易于使用的大语言模型&#xff08;LLM&#xff09;微调框架&#xff0c;支持LLaMA、Baichuan、Qwen、ChatGLM等架构的大模型。更细致的看&#xff0c;该项…

UG NX二次开发(C++)-获取曲面的相切曲面

文章目录 1、前言2、创建一个三维模型3、获取相切曲面的方法3、测试结果1、前言 最近一段时间,QQ群中的群友总问我一个问题,那就是如何获取曲面的相切曲面,我今天就把这个方法写出来,以帮助读者。 在UG二次开发中,查询了帮助文档,没有找到获取相切曲面的函数。所以采用N…

「C++系列」继承

文章目录 一、继承1. 基本概念2. 继承类型①公有继承&#xff08;Public Inheritance&#xff09;②私有继承&#xff08;Private Inheritance&#xff09;③保护继承&#xff08;Protected Inheritance&#xff09; 3. 继承的语法4. 构造函数和析构函数①构造函数案例②析构函…

单链表的问题(2)

1.对于一个链表&#xff0c;请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法&#xff0c;判断其是否为回文结构。 给定一个链表的头指针A&#xff0c;请返回一个bool值&#xff0c;代表其是否为回文结构。保证链表长度小于等于900。 这个我们可以运用双指针来解决这个…

爆改YOLOv8|利用全新的聚焦式线性注意力模块Focused Linear Attention 改进yolov8(v1)

1&#xff0c;本文介绍 全新的聚焦线性注意力模块&#xff08;Focused Linear Attention&#xff09;是一种旨在提高计算效率和准确性的注意力机制。传统的自注意力机制在处理长序列数据时通常计算复杂度较高&#xff0c;限制了其在大规模数据上的应用。聚焦线性注意力模块则通…

EmguCV学习笔记 C# 7.1 角点检测

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

Excel中让第一行始终显示

要在Excel中让第一行始终显示&#xff0c;你可以使用冻结窗格功能。具体步骤如下&#xff1a; 打开需要设置第一行一直显示的工作表。将光标定位在工作表内任意一个单元格内。选择“视图”菜单&#xff0c;单击工具栏中的“冻结窗格”命令。在弹出的下拉菜单中选择“冻结首行”…

字母的大小写转换(tolower、toupper、transform)

字母的大小写转换&#xff08;tolower、toupper、transform&#xff09; 1. tolower&#xff08;&#xff09;、toupper&#xff08;&#xff09;函数 &#xff08;这个在之前的一篇文章 “字符串中需要掌握的函数总结&#xff08;1&#xff09;”中有较为详细的介绍。&#…

时利和:如何提升工装夹具的加工质量?

在机械加工领域&#xff0c;工装夹具起着至关重要的作用。它不仅能够提高生产效率&#xff0c;还能保证加工精度&#xff0c;确保产品质量的稳定性。那么&#xff0c;如何提升工装夹具的加工质量呢?以下是时利和整理分享的几个关键因素。 一、精准的设计 工装夹具的设计是决定…

使用物联网卡访问萤石云的常见问题

使用物联网卡接入萤石开放平台时经常遇到各种问题&#xff0c;这边总结了常见的一些 用的是哪家运营商的卡&#xff1f; 电信 移动 联通&#xff08;申请的时候可以自主选择&#xff09; 卡有什么限制&#xff1f; 定向流量卡&#xff0c;只能访问萤石云平台&#xff0c;只能…

完美解决Jenkins重启后自动杀掉衍生进程(子进程)问题

完美解决Jenkins重启后自动杀掉衍生进程(子进程)问题 本文中使用的Jenkins版本为Version 2.452.3 先罗列一下前置问题&#xff1a;Jenkins任务构建完成自动杀掉衍生进程 用过Jenkins的都知道&#xff0c;Jenkins任务构建完成后&#xff0c;是会自动杀掉衍生进程&#xff0c;这…

安卓AppBarLayout与ViewPager2里的fragment里的webview滑动冲突

今天开发遇见一个头痛的问题&#xff0c;就是AppBarLayout和webview会存在一个冲突问题。如图下 问题出现在webview推到顶端的时候&#xff0c;AppBarLayout并不会跟着响应伸缩&#xff0c;解决办法是 在 webview 包 一个 父的 NestedScrollView 就能解决了。 运行效果入下 更改…