ES(索引数据库)导入MySQL全量(批量导入)和增量数据Canal增量数据同步利器

news2024/11/18 5:38:22

索引库数据管理

秒杀商品数量庞大,我们要想实现快速检索,不建议直接使用关系型数据库查找。不建议使用Redis缓存所有数据,因为秒杀商品量大,会影响Redis的性能,并且Redis的条件检索能力偏弱。我们可以使用Elasticsearch,它在海量数据存储与检索上,能力卓越,市场使用面广。

查询MySQL数据

我们需要将秒杀商品数据导入到ES索引库中,但秒杀商品数量庞大,所以我们应该分页查询并导入,流程如下:
在这里插入图片描述
1)service总数量查询

​ 我们先在seckill-goods中编写相关方法实现数据查询,因为要用到分页,所以先查询总数量,然后再实现分页集合查询。

在seckill-goods的com.seckill.goods.service.SkuService中添加count方法,用于查询秒杀商品总数量:

/**
 * 总数量加载
 * @return
 */
Integer count();

在seckill-goods的com.seckill.goods.service.impl.SkuServiceImpl中添加count方法,用于实现查询秒杀商品总数量:

/**
 * 总数量加载
 * @return
 */
@Override
public Integer count() {
    Example example = new Example(Sku.class);
    Example.Criteria criteria = example.createCriteria();
    //秒杀剩余商品数量>0
    criteria.andGreaterThan("seckillNum",0);
    //状态为参与秒杀,1:普通商品,2:参与秒杀
    criteria.andEqualTo("status","2");
    //秒杀结束时间>=当前时间
    criteria.andGreaterThanOrEqualTo("seckillEnd",new Date());
    return skuMapper.selectCountByExample(example);
}

在seckill-goods的com.seckill.goods.controller.SkuController中添加count方法,用于实现查询秒杀商品总数量:

/***
 * Sku数量加载
 * @return
 */
@PostMapping(value = "/count" )
public Integer count(){
    return skuService.count();
}

2)service分页集合数据查询

在seckill-goods的com.seckill.goods.service.SkuService中添加list方法,用于查询秒杀商品:

/***
 * 分页加载
 * @param page
 * @param size
 * @return
 */
List<Sku> list(int page, int size);

在seckill-goods的com.seckill.goods.service.impl.SkuServiceImpl中添加list方法,用于实现查询秒杀商品:

/***
 * 分页加载
 * @param page
 * @param size
 * @return
 */
@Override
public List<Sku> list(int page, int size) {
    //分页
    PageHelper.startPage(page,size);

    //条件构建
    Example example = new Example(Sku.class);
    Example.Criteria criteria = example.createCriteria();
    //秒杀剩余商品数量>0
    criteria.andGreaterThan("seckillNum",0);
    //状态为参与秒杀,1:普通商品,2:参与秒杀
    criteria.andEqualTo("status","2");
    //秒杀结束时间>=当前时间
    criteria.andGreaterThanOrEqualTo("seckillEnd",new Date());
    return skuMapper.selectByExample(example);
}

在seckill-goods的com.seckill.goods.controller.SkuController中添加list方法,用于实现查询秒杀商品:

/***
 * Sku分页条件加载
 * @param page
 * @param size
 * @return
 */
@GetMapping(value = "/list/{page}/{size}" )
public List<Sku> list(@PathVariable  int page, @PathVariable  int size){
    //调用SkuService实现分页条件查询Sku
    List<Sku> skus = skuService.list(page, size);
    return skus;
}

3)Feign接口编写

在seckill-goods-api的com.seckill.goods.feign.SkuFeign中编写feign方法,分别调用刚才的count、list方法,代码如下:

/***
 * Sku数量加载
 * @return
 */
@PostMapping(value = "/sku/count" )
Integer count();

/***
 * Sku分页条件加载
 * @param page
 * @param size
 * @return
 */
@GetMapping(value = "/sku/list/{page}/{size}" )
List list(@PathVariable(value ="page") Integer page, @PathVariable(value = "size")Integer size);

集成SpringData Elasticsearch实现索引导入流程:

1.配置Elasticsearch地址信息
2.编写Dao代码,继承ElasticsearchRepository<T,ID>
3.Service中分页调用查询秒杀商品集合
4.分页导入秒杀商品集合数据到Elasticsearch

添加依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

当前项目已经集成好了SpringDataElasticsearch,我们只需要实现相关的操作过程即可。

bootstrap.yml添加es配置:

spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: es-server:9300

将数据添加到索引库,需要先创建一个能体现索引库的JavaBean映射对象,将要保存到索引库的数据赋值给JavaBean,利用API将JavaBean保存到索引库。

我们首先编写一个和索引库中一一对应的实体Bean,代码如下:

@Document(indexName = "goodsindex",type = "skuinfo")
public class SkuInfo implements Serializable {

    //Sku相关的数据
    //商品id,同时也是商品编号
    @Id //唯一标识符,ES中对应的_id
    private String id;

    /***
     * SKU名称
     * type =FieldType.Text:指定当前name属性所对应的域的类型为Text类型,该类型支持分词支持创建索引
     *       FiledType.Keyword:不分词
     * searchAnalyzer="ik_smart":搜索所使用的分词器
     * analyzer = "ik_smart":添加索引所使用的分词器
     */
    @Field(type =FieldType.Text ,searchAnalyzer = "ik_smart",analyzer = "ik_smart",store =false)
    private String name;

    //商品价格,单位为:元
    private Long price;

    //秒杀价
    private Long seckillPrice;

    //商品图片
    private String image;

    //更新时间
    private Date updateTime;

    //类目ID
    private String category1Id;

    //类目ID
    private String category2Id;

    //类目ID
    private String category3Id;

    //类目名称
    @Field(type = FieldType.Keyword)
    private String category1Name;

    //类目名称
    @Field(type = FieldType.Keyword)
    private String category2Name;

    //类目名称
    @Field(type = FieldType.Keyword)
    private String category3Name;

    //品牌名称
    @Field(type = FieldType.Keyword)
    private String brandName;

    //开始时间,用于做搜索
    @Field(type = FieldType.Keyword)
    private String bgtime;

    //品牌ID
    private String brandId;

    private Date seckillBegin;//秒杀开始时间

    private Date seckillEnd;//秒杀结束时间

    private Integer status; //秒杀状态,1普通商品,2秒杀

    //规格
    private String spec;
    
    //..get..set略
    
}

创建dao

public interface SkuInfoMapper extends ElasticsearchRepository<SkuInfo,String> {
}

在seckill-search的com.seckill.search.service.SkuInfoService中编写导入索引,代码如下:

/***
 * 导入所有
 */
void addAll();

在seckill-search的com.seckill.search.service.impl.SkuInfoServiceImpl中编写导入索引,代码如下:

@Autowired
private SkuFeign skuFeign;

/***
 * 使用Feign导入所有
 */
@Override
public void addAll() {
    //从第1页开始,每页处理500条
    int pageNum=1;
    int size=500;
    //查询所有数量
    Integer count = skuFeign.count();
    //总页数
    int totalPage = count%size==0? count/size : (count/size)+1;

    //分页查询,并将所有数据导入到索引库中
    for (int i = 0; i <totalPage ; i++) {
        List list = skuFeign.list(pageNum, size);

        //将数据转换成List<SkuInfo>
        List<SkuInfo> skuInfos =JSON.parseArray( JSON.toJSONString(list) ,SkuInfo.class);

        //规格处理
        for (SkuInfo skuInfo : skuInfos) {
            //获取秒杀时间
            Date seckillBegin = skuInfo.getSeckillBegin();
            if(seckillBegin!=null){
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyymmddhhmmss");
                String bgtime = simpleDateFormat.format(seckillBegin);
                skuInfo.setBgtime(bgtime);
            }
        }
        skuInfoMapper.saveAll(skuInfos);
        //页数递增
        pageNum++;
    }
}

注意:我们可以发现下面这段代码以后在其他地方有可能也会用得着,我们可以把它单独抽取出一个方法来:
在这里插入图片描述
抽取后:
在这里插入图片描述

在seckill-search的com.seckill.search.controller.SearchController中编写导入索引,代码如下:

/***
 * 所有记录导入到搜索引擎中
 */
@GetMapping(value = "/all/add")
public Result addAll(){
    //添加数据到索引库中
    skuInfoService.addAll();
    return new Result(true, StatusCode.OK,"导入所有数据到索引库成功!");
}

4)测试

启动seckill-goods、seckill-search、seckill-gateway,访问刚才编写的批量导入的方法,访问地址:http://localhost:8001/api/search/all/add
在这里插入图片描述

增量导入

增量导入,也就是某个商品设置成秒杀商品的时候,或者发生变更的时候,能实现增量备份(只将修改的数据同步修改索引库),所以我们还需要实现单个商品导入索引库,我们可以在变更方法(增删改)中调用这边同步方法,但随着系统的增加,这种方法容易有漏网之鱼,我们可以采用canal实现数据库增量监听,然后调用seckill-search的单个操作方法。

1)索引操作方法编写

在seckill-search的com.seckill.search.service.SkuInfoService中添加modify方法,代码如下:

/****
 * 单条索引操作
 * @param type: 1:增加,2:修改,3:删除
 * @param skuInfo
 */
void modify(Integer type, SkuInfo skuInfo);

在seckill-search的com.seckill.search.service.impl.SkuInfoServiceImpl中添加modify实现方法,代码如下:

/***
 * 单条索引操作
 * @param type
 * @param skuInfo
 */
@Override
public void modify(Integer type, SkuInfo skuInfo) {
    if(type==1 || type==2){
        //时间转换
        skuInfoConverter(skuInfo);
        //增加数据到索引库
        skuInfoMapper.save(skuInfo);
    }else{
        skuInfoMapper.deleteById(skuInfo.getId());
    }
}

在seckill-search的com.seckill.search.controller.SkuInfoController中添加modify方法,代码如下:

/***
 * 将一条记录导入到搜索引擎中
 */
@PostMapping(value = "/modify/{type}")
public Result add(@PathVariable(value = "type")Integer type, @RequestBody SkuInfo skuInfo){
    //添加数据到索引库中
    skuInfoService.modify(type,skuInfo);
    return new Result(true, StatusCode.OK,"操作一条数据到索引库成功!");
}

2)Feign接口编写

在seckill-search-api中编写Feign接口,实现调用modify方法,代码如下:

@FeignClient(value = "seckill-search")
public interface SkuInfoFeign {

    /***
     * 将一条记录导入到搜索引擎中
     */
    @PostMapping(value = "/search/modify/{type}")
    Result modify(@PathVariable(value = "type")Integer type, @RequestBody SkuInfo skuInfo);
}

商品搜索

根据秒杀页面的需求,多数是查询指定秒杀时段下的秒杀商品,同时还会有分页,当然,如果有复杂的查询,我们Elasticsearch也都满足。我们可以根据多数秒杀需求,实现按照秒杀时段分页查询数据。
编写Dao

public interface SkuInfoMapper extends ElasticsearchRepository<SkuInfo,String> {

    /***
     * 根据bgtime分页查询
     * @param time
     * @param pageable
     * @return
     */
    Page<SkuInfo> findByBgtime(String time, Pageable pageable);
}

编写Servicecom.seckill.search.service.SkuInfoService创建搜索方法,代码如下:

/***
 * 搜索
 */
Page<SkuInfo> searchPage(Map<String,String> searchMap);

编写Servicecom.seckill.search.service.impl.SkuInfoServiceImpl创建搜索实现方法,代码如下:

/***
 * 搜索实现
 * @param searchMap
 * @return
 */
@Override
public Page<SkuInfo> searchPage(Map<String, String> searchMap) {
    //根据开始时间查询   findByBgtime(Dao)
    return skuInfoMapper.findByBgtime(searchMap.get("starttime"), PageRequest.of(pageNumber(searchMap)-1,20));
}

/***
 * 获取当期页
 * @param searchMap
 * @return
 */
public int pageNumber(Map<String, String> searchMap){
    try {
        return Integer.parseInt( searchMap.get("pageNum") );
    } catch (NumberFormatException e) {
        return 1;
    }
}

编写Servicecom.seckill.search.controller.SearchController创建搜索方法调用,代码如下:

/***
 * 秒杀分页查询
 * pageNum:当前页
 * starttime:秒杀活动开始时间
 */
@GetMapping
public Page search(@RequestParam(required = false) Map<String,String> searchMap){
    if(searchMap==null){
        return null;
    }
    return skuInfoService.searchPage(searchMap);
}

Canal增量数据同步利器

Canal介绍

canal主要用途是基于 MySQL 数据库增量日志解析,并能提供增量数据订阅和消费,应用场景十分丰富。

github地址:https://github.com/alibaba/canal

版本下载地址:https://github.com/alibaba/canal/releases

文档地址:https://github.com/alibaba/canal/wiki/Docker-QuickStart

Canal应用场景

1.电商场景下商品、用户实时更新同步到至Elasticsearch、solr等搜索引擎;
2.价格、库存发生变更实时同步到redis;
3.数据库异地备份、数据同步;
4.代替使用轮询数据库方式来监控数据库变更,有效改善轮询耗费数据库资源。
在这里插入图片描述

MySQL主从复制原理

1.MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
2.MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
3.MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据

Canal工作原理

1.canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
2.MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
3.canal 解析 binary log 对象(原始为 byte 流)
在这里插入图片描述

Canal安装

参考文档:https://github.com/alibaba/canal/wiki/QuickStart

MySQL Bin-log开启

1)MySQL开启bin-log

a.进入mysql容器

docker exec -it -u root mysql /bin/bash

b.开启mysql的binlog

cd /etc/mysql/mysql.conf.d

在mysqld.cnf最下面添加如下配置
# 开启 binlog
log-bin=/var/lib/mysql/mysql-bin
# 选择 ROW 模式
binlog-format=ROW
# 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
server-id=12345

c.创建账号并授权

授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant:

create user canal@'%' IDENTIFIED by 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT,SUPER ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

d.重启mysql

docker restart mysql

开启bin-log后,我们可以用sql语句查看下:

show variables like '%log_bin%'

效果如下:
在这里插入图片描述

Canal安装

1)拉取镜像

docker pull canal/canal-server:v1.1.1

2)安装容器

a.安装canal-server容器

docker run -p 11111:11111 --name canal -d docker.io/canal/canal-server

b.配置canal-server

修改/home/admin/canal-server/conf/canal.properties,将它的id属性修改成和mysql数据库中server-id不同的值,如下图:
在这里插入图片描述
c.修改/home/admin/canal-server/conf/example/instance.properties,配置要监听的数据库服务地址和监听数据变化的数据库以及表,修改如下:
在这里插入图片描述
在这里插入图片描述
指定监听数据库表的配置如下canal.instance.filter.regex:

mysql 数据解析关注的表,Perl正则表达式.
多个正则之间以逗号(,)分隔,转义符需要双斜杠(\\) 
常见例子:
1.  所有表:.*   or  .*\\..*
2.  canal schema下所有表: canal\\..*
3.  canal下的以canal打头的表:canal\\.canal.*
4.  canal schema下的一张表:canal.test1
5.  多个规则组合使用:canal\\..*,mysql.test1,mysql.test2 (逗号分隔)
注意:此过滤条件只针对row模式的数据有效(ps. mixed/statement因为不解析sql,所以无法准确提取tableName进行过滤)

重启canal:

docker restart canal
Canal微服务

​ 我们搭建一个微服务,用于读取canal监听到的变更日志,微服务名字叫seckill-canal。该项目我们需要引入canal-spring-boot-autoconfigure包,并且需要实现EntryHandler接口,该接口中有3个方法,分别为insert、update、delete,这三个方法用于监听数据增删改变化。

参考地址:https://github.com/NormanGyllenhaal/canal-client

1)pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>seckill-service</artifactId>
        <groupId>com.seckill</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>seckill-canal</artifactId>

    <dependencies>
        <!--web-->
        <dependency>
            <groupId>com.seckill</groupId>
            <artifactId>seckill-web</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!--esAPI-->
        <dependency>
            <groupId>com.seckill</groupId>
            <artifactId>seckill-search-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!--goodsAPI-->
        <dependency>
            <groupId>com.seckill</groupId>
            <artifactId>seckill-goods-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <!--canal-->
        <dependency>
            <groupId>top.javatool</groupId>
            <artifactId>canal-spring-boot-autoconfigure</artifactId>
            <version>1.2.1-RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 指定该Main Class为全局的唯一入口 -->
                    <mainClass>com.seckill.CanalApplication</mainClass>
                    <layout>ZIP</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

bootstrap.yml配置

server:
  port: 18088
spring:
  application:
    name: seckill-canal
  cloud:
    nacos:
      config:
        file-extension: yaml
        server-addr: nacos-server:8848
      discovery:
        #Nacos的注册地址
        server-addr: nacos-server:8848
#超时配置
ribbon:
  ReadTimeout: 3000000
#Canal配置
canal:
  server: canal-server:11111
  destination: example
#日志
logging:
  level:
    root: error

2)创建com.seckill.handler.SkuHandler实现EntryHandler接口,代码如下:

@Component
@CanalTable(value = "tb_sku")
public class SkuHandler implements EntryHandler<Sku> {

    /***
     * 增加数据
     * @param sku
     */
    @Override
    public void insert(Sku sku) {
        System.out.println("===========insert:"+sku);
    }

    /***
     * 修改数据
     * @param before
     * @param after
     */
    @Override
    public void update(Sku before, Sku after) {
        System.out.println("===========update-before:"+before);
        System.out.println("===========update-after:"+after);
    }

    /***
     * 删除数据
     * @param sku
     */
    @Override
    public void delete(Sku sku) {
        System.out.println("===========delete:"+sku);
    }
}

3)创建启动类

@SpringBootApplication
public class CanalApplication {

    public static void main(String[] args) {
        SpringApplication.run(CanalApplication.class,args);
    }
}

程序启动后,修改tb_sku数据,可以看到控制会打印修改前后的数据:
在这里插入图片描述

索引库同步

当tb_sku秒杀商品发生变化时,我们应该同时变更索引库中的索引数据,比如秒杀商品增加,则需要同步增加秒杀商品的索引,如果有秒杀商品删除,则需要同步移除秒杀商品。

修改seckill-canal中的com.seckill.handler.SkuHandler的增删改方法,代码如下:

@Component
@CanalTable(value = "tb_sku")
public class SkuHandler implements EntryHandler<Sku> {

    @Autowired
    private SkuInfoFeign skuInfoFeign;

    /***
     * 增加数据
     * @param sku
     */
    @Override
    public void insert(Sku sku) {
        //将Sku转换成SkuInfo
        SkuInfo skuInfo = JSON.parseObject( JSON.toJSONString(sku) ,SkuInfo.class);
        //同步索引
        skuInfoFeign.modify(1,skuInfo);
    }

    /***
     * 修改数据
     * @param before
     * @param after
     */
    @Override
    public void update(Sku before, Sku after) {
        int type=2;
        //将Sku转换成SkuInfo
        SkuInfo skuInfo = JSON.parseObject( JSON.toJSONString(after) ,SkuInfo.class);
        if(skuInfo.getStatus()==1 || after.getSeckillNum()<=0){
            //商品变成了普通商品,或者商品库存为0,则需要删除索引数据
            type=3;
        }
        //同步索引
        skuInfoFeign.modify(type,skuInfo);
    }

    /***
     * 删除数据
     * @param sku
     */
    @Override
    public void delete(Sku sku) {
        //将Sku转换成SkuInfo
        SkuInfo skuInfo = JSON.parseObject( JSON.toJSONString(sku) ,SkuInfo.class);
        //同步索引
        skuInfoFeign.modify(3,skuInfo);
    }
}

开启Feign功能:@EnableFeignClients(basePackages = {“com.seckill.search.feign”})
在这里插入图片描述
此时对数据库中tb_sku表进行增删改的时候,会同步到索引库中。

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

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

相关文章

Linux:NAT等相关问题

目录 1&#xff1a;NAT背景 2&#xff1a;NAT IP转换过程 3&#xff1a;NATP 4&#xff1a;正向代理 5&#xff1a;反向代理 6&#xff1a;NAT和代理服务器 应用场景 实现方法 1&#xff1a;NAT背景 IPv4地址耗尽&#xff1a;随着互联网的迅速发展&#xff0c;连接到…

[Leetcode 105][Medium] 从前序与中序遍历序列构造二叉树-递归

目录 一、题目描述 二、整体思路 三、代码 一、题目描述 题目地址 二、整体思路 前序遍历得到的是[根结点|左子树|右子树]&#xff0c;中序遍历得到的是[左子树|根结点|右子树] 那么可以设立一个递归函数&#xff0c;作用是利用前序遍历的数组和中序遍历的数组构建一个节点…

汇川技术|Inoproshop软件菜单[在线、调试]

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 现如今学习资源是容易获取了&#xff0c;像我网盘里堆了7T的资料&#xff0c;有很多还没看过&#xff0c;总是见到了就收藏起来&#xff0c;但是真的看不过来啊。有时间和精力的小伙伴可以找自己感兴趣的看起来。 本…

景商场双目客流量摄像机,具有100°宽视角,识别范围广

在当今竞争激烈的商业环境中&#xff0c;商场管理者们一直在寻求更有效的方法来了解顾客行为、优化运营策略。商场双目客流量摄像机的出现&#xff0c;为商场管理带来了新的机遇。 一、功能强大 商场双目客流量摄像机具有多项强大功能。首先&#xff0c;它拥有 100 宽视角&…

雷达水文监测站

雷达水文监测站是一种利用雷达技术进行水文监测的设备&#xff0c;其功能主要包括以下几个方面&#xff1a; 水位监测&#xff1a;雷达水文监测站可以实时监测水体的水位变化&#xff0c;通过测量水面到雷达发射器的距离来计算水位。 流量监测&#xff1a;根据水位的变化&…

西门子一个PLC两个HMI分别显示不同报警内容

当前项目为一个PLC带两个HMI&#xff0c;功能上两个站完全分离&#xff0c;但是为了避免重复绘制HMI&#xff0c;先将两个站点报警链接到同一个HMI上&#xff0c;同时又需要指定站点的HMI单独显示该站点的报警&#xff1b;否则会出现如下情况&#xff0c;两个站都显示全部的报警…

传输大咖33 | 适合企业内外网文件交换系统是怎样的?

企业的内外网文件交换是企业日常运营的重要环节。然而&#xff0c;随着技术的发展&#xff0c;企业的文件数据量日益增长&#xff0c;文件的格式也越来越复杂多样。传统的内外网文件交换方式也逐渐显露出不足之处&#xff0c;对于企业来说&#xff0c;寻求更加高效、安全、可靠…

YOLOv9改进策略【损失函数篇】| 利用MPDIoU,加强边界框回归的准确性

一、背景 目标检测和实例分割中的关键问题&#xff1a; 现有的大多数边界框回归损失函数在不同的预测结果下可能具有相同的值&#xff0c;这降低了边界框回归的收敛速度和准确性。 现有损失函数的不足&#xff1a; 现有的基于 ℓ n \ell_n ℓn​范数的损失函数简单但对各种尺度…

Word文件密码忘记,该如何才能编辑Word文件呢?

Word文件打开之后&#xff0c;发现编辑功能都是灰色的&#xff0c;无法使用&#xff0c;无法编辑&#xff0c;遇到这种情况&#xff0c;是因为Word文件设置了限制编辑导致的。一般情况下&#xff0c;我们只需要输入Word密码&#xff0c;将限制编辑取消就可以正常编辑文件了&…

LLM大模型:生成式人工智能完全指南,240页pdf

《你最后一本需要的AI书籍。我们保证&#xff01;》 AI技术发展如此迅速&#xff0c;这本书可能已经过时了&#xff01;但别担心——《生成性AI完全过时指南》依然是任何想将生成性AI从玩具变成工具的人必读的书籍。无论未来如何变化&#xff0c;它都能教你如何充分利用AI。你…

FL Studio24.1.1.4239中文高级版破解补丁+永久免费激活码许可证

FL Studio 24.1.1.4239中文版&#xff0c;音乐制作人的“瑞士军刀” 在音乐制作的世界中&#xff0c;有一款软件被誉为“瑞士军刀”&#xff0c;那就是FL Studio 24.1.1.4239中文版。它不仅功能强大&#xff0c;而且界面友好&#xff0c;让音乐制作变得简单又有趣。今天&#…

大模型如何赚钱,杀手级应用是什么、创业机会在哪里?

除了通义大模型外&#xff0c;MiniMax、月之暗面、智谱AI、猎户星空、零一万物、百川智能六家大模型厂商已经与钉钉达成合作。目前&#xff0c;钉钉生态伙伴总数超过5600家&#xff0c;其中AI 生态伙伴已经超过100家&#xff1b;钉钉AI每天调用量超1000万次。 在下午的圆桌对话…

八种dll文件丢失怎么恢复的步骤分享,超全面介绍dll文件几解决方法

在使用Windows操作系统的过程中&#xff0c;我们时常会遇到程序运行错误提示&#xff0c;其中“DLL文件丢失”是一类非常典型的问题。这类错误不仅令人困扰&#xff0c;还可能阻碍软件或系统功能的正常使用。动态链接库&#xff08;DLL&#xff09;文件是Windows系统中的一个关…

LeetCode 精选 75 回顾

目录 一、数组 / 字符串 1.交替合并字符串 &#xff08;简单&#xff09; 2.字符串的最大公因子 &#xff08;简单&#xff09; 3.拥有最多糖果的孩子&#xff08;简单&#xff09; 4.种花问题&#xff08;简单&#xff09; 5.反转字符串中的元音字母&#xff08;简单&a…

基于大语言模型的医疗问答系统的设计与研究

目录 研究背景及意义 国内外研究现状 研究内容 研究方案与技术路线 大语言模型的基本原理 大语言模型的部署 大语言模型微调 大语言模型提示工程&#xff08;Prompt&#xff09; 大语言模型RAG技术 LangChain 多模态大语言模型 研究背景及意义 大语言模型&#xff0…

网络安全售前入门03——审计类产品了解

目录 1.前言 2.堡垒机介绍 2.1产品架构功能 2.2应用场景 2.3部署形式 2.4产品价值 2.5选型依据 3.日志审计 3.1产品架构功能 3.2应用场景 3.3部署形式 3.4产品价值 3.5选型依据 后续 1.前言 为方便初接触网络安全售前工作的小伙伴了解网安行业情况,我制作一系统…

CSS文本样式(一)

一、font-family 1、font-family属性 font-family​ &#xff1a;属性指定元素的​字体​&#xff0c;语法格式如下&#xff1a; ​font-family​: 字体1,字体2,...; 有两种字体系列名称&#xff1a; ​字体系列​&#xff1a;特定的字体系列&#xff08;如Times New Rom…

Mac上免费使用Typora保姆级教程 简单 2024可用

一、官网安装正版软件 Typora官网--点击进入Typora官网下载正版软件 二、找到软件文件 进入访达&#xff0c;commandshiftG打开路径搜索&#xff0c;输入 /Applications/Typora.app/Contents/Resources/TypeMark 进入Typora文件夹 打开这个文件 三、修改字段 然后搜索字段…

Ubuntu2004编译VLC-QT(记录)(根据官方步骤来)

来到VLC-QT的github官方地址--VLC-QT&#xff08;点击前面的&#xff09; 下载官方源码&#xff0c;也可以git clone拉取 2&#xff1a;解压源码之后&#xff0c;进入文件夹 创建文件夹“build”用于存放待会编译产生的相关文件&#xff0c;执行 mkdir buildcd build 回到VLC…

【Redis】Redis 持久化 -- RDB AOF

文章目录 1 持久化介绍2 RDB2.1 RDB 介绍2.2 触发方式2.3 流程介绍2.4 RDB 文件2.5 RDB 优缺点 3 AOF3.1 AOF 介绍3.2 缓冲区刷新策略3.3 AOF 重写机制3.3.1 重写机制介绍3.3.2 混合持久化3.3.3 重写触发方式3.3.4 AOF 重写流程 3.4 AOF 优缺点 4 启动时数据恢复 1 持久化介绍 …