flink重温笔记(十四): flink 高级特性和新特性(3)——数据类型及 Avro 序列化

news2024/11/16 21:51:54

Flink学习笔记

前言:今天是学习 flink 的第 14 天啦!学习了 flink 高级特性和新特性之数据类型及 avro 序列化,主要是解决大数据领域数据规范化写入和规范化读取的问题,avro 数据结构可以节约存储空间,本文中结合企业真实应用场景,即 kafka 的读取和写入采用自定义序列化,结合自己实验猜想和代码实践,总结了很多自己的理解和想法,希望和大家多多交流!

Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊!

喜欢我的博客的话,记得点个红心❤️和小关小注哦!您的支持是我创作的动力!"


文章目录

  • Flink学习笔记
    • 四、Flink 高级特性和新特性
      • 4. 数据类型及序列化
        • 4.1 数据类型
        • 4.2 POJO 类型细节
        • 4.3 Avro优点介绍
        • 4.4 定义Avro Json格式
        • 4.5 使用 Java 自定义序列化到 Kfaka
          • 4.5.1 准备数据
          • 4.5.2 自定义Avro 序列化和反序列化
          • 4.5.3 创建生产者工具类
          • 4.5.4 创建消费者工具类
          • 4.5.5 运行程序
        • 4.6 使用 Flink 自定义序列化到 Kafka
          • 4.6.1 准备数据
          • 4.6.2 自定义Avro 序列化和反序列化
          • 4.6.3 创建 Flink-source 类
          • 4.6.4 创建 Flink-sink 类
          • 4.6.5 运行程序

四、Flink 高级特性和新特性

4. 数据类型及序列化

4.1 数据类型

flink 支持的数据类型:七种


4.2 POJO 类型细节

注意事项:

  • 该类需要有 public 修饰
  • 该类需要有 public 修饰的无参构造函数
  • 该类的所有(no-static)、(no-transient)字段必须是 public,如果不是 public 则必须是有标准的 getter 和 setter
  • 该类的所有字段都必须是 flink 支持的数据类型

4.3 Avro优点介绍
  • Avro 是数据序列化系统,支持大批量数据交换的应用。

  • 支持二进制序列化方式,性能好 / 效率高,使用 JSON 描述。

  • 动态语言友好,RPC 远程调用,支持同步和异步通信。


4.4 定义Avro Json格式
  • namespace:要生成的目录
  • type:类型 avro 需要指定 record
  • name:会自动生成的对象
  • fields:要指定的字段

注意: 创建的文件后缀名一定要叫 avsc,而不是 avro 后缀,使用 idea 生成 Order 对象

{
    "namespace": "cn.itcast.beans",
    "type": "record",
    "name": "OrderModel",
    "fields": [
        {"name": "userId", "type": "string"},
        {"name": "timestamp",  "type": "long"},
        {"name": "money",  "type": "double"},
        {"name": "category", "type": "string"}
    ]
}

注意:由于在导入 pom 依赖的时候,需要注意插件冲突,注释掉以下依赖,不然会一直爆错!

<!--        这个会和 avro 冲突,所以先注释一下-->
<!--        <dependency>-->
<!--            <groupId>org.apache.hive</groupId>-->
<!--            <artifactId>hive-exec</artifactId>-->
<!--            <version>2.1.0</version>-->
<!--        </dependency>-->
  • 快看一!导入需要的依赖到 pom 文件中:
<dependency>
    <groupId>org.apache.avro</groupId>
    <artifactId>avro</artifactId>
    <version>1.8.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.flink/flink-avro -->
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-avro</artifactId>
    <version>${flink.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>2.5.1</version>
</dependency>
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-streams</artifactId>
    <version>2.5.1</version>
</dependency>
  • 快看二!导入需要的插件到 pom 文件中:
<!-- avro编译插件 -->
<plugin>
    <groupId>org.apache.avro</groupId>
    <artifactId>avro-maven-plugin</artifactId>
    <version>1.8.2</version>
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>schema</goal>
            </goals>
            <configuration>
                <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>
                <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>


4.5 使用 Java 自定义序列化到 Kfaka
4.5.1 准备数据

order.csv

user_001,1621718199,10.1,电脑
user_001,1621718201,14.1,手机
user_002,1621718202,82.5,手机
user_001,1621718205,15.6,电脑
user_004,1621718207,10.2,家电
user_001,1621718208,15.8,电脑
user_005,1621718212,56.1,电脑
user_002,1621718260,40.3,家电
user_001,1621718580,11.5,家居
user_001,1621718860,61.6,家居

4.5.2 自定义Avro 序列化和反序列化

首先需要实现2个接口分别为 Serializer 和 Deserializer 分别是序列化和反序列化

package cn.itcast.day14.serialization_java;

/**
 * @author lql
 * @time 2024-03-10 16:29:49
 * @description TODO
 */

import cn.itcast.day14.beans.OrderModel;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import org.apache.kafka.common.serialization.*;

/**
 *  自定义序列化和反序列化
 */
public class SimpleAvroSchemaJava implements Serializer<OrderModel>, Deserializer<OrderModel> {
    @Override
    public void configure(Map<String, ?> configs, boolean isKey) {

    }

    @Override
    public void close() {

    }

    @Override
    public byte[] serialize(String s, OrderModel order) {
        // 创建序列化执行器
        SpecificDatumWriter<OrderModel> writer = new SpecificDatumWriter<OrderModel>(order.getSchema());
        // 创建一个流 用存储序列化后的二进制文件
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 创建二进制编码器
        BinaryEncoder encoder = EncoderFactory.get().directBinaryEncoder(out, null);
        try {
            // 数据入都流中
            writer.write(order, encoder);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return out.toByteArray();
    }

    @Override
    public OrderModel deserialize(String s, byte[] bytes) {
        // 用来保存结果数据
        OrderModel order = new OrderModel();
        // 创建输入流用来读取二进制文件
        ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(bytes);
        // 创建输入序列化执行器
        SpecificDatumReader<OrderModel> stockSpecificDatumReader = new SpecificDatumReader<OrderModel>(order.getSchema());
        //创建二进制解码器
        BinaryDecoder binaryDecoder = DecoderFactory.get().directBinaryDecoder(arrayInputStream, null);
        try {
            // 数据读取
            order= stockSpecificDatumReader.read(null, binaryDecoder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 结果返回
        return order;
    }
}
4.5.3 创建生产者工具类
package cn.itcast.day14.serialization_java;

import cn.itcast.day14.beans.OrderModel;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
 * @author lql
 * @time 2024-03-10 16:33:31
 * @description TODO
 */
public class OrderProducerJava {
    public static void main(String[] args) {
        // 获取数据
        List<OrderModel> data = getData();
        System.out.println(data);
        try {
            // 创建配置文件
            Properties props = new Properties();
            props.setProperty("bootstrap.servers", "node1:9092");
            // 这里的健:还是 string 序列化
            props.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
            // 这里的值:需要指向自定义的序列化
            props.setProperty("value.serializer", "cn.itcast.day14.serialization_java.SimpleAvroSchemaJava");
            // 创建kafka的生产者
            KafkaProducer<String, OrderModel> userBehaviorProducer = new KafkaProducer<String, OrderModel>(props);
            // 循环遍历数据
            for (OrderModel orderModel : data) {
                ProducerRecord<String, OrderModel> producerRecord 
                        = new ProducerRecord<String, OrderModel>("order", orderModel);
                userBehaviorProducer.send(producerRecord);
                System.out.println("数据写入成功"+data);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static List<OrderModel> getData() {
        ArrayList<OrderModel> orderModels = new ArrayList<OrderModel>();
        try {
            BufferedReader br = new BufferedReader(
                    new FileReader(
                            new File("D:\\IDEA_Project\\BigData_Java\\flinkbase_pro\\data\\input\\order.csv")
                    )
            );
            String line = "";
            while ((line = br.readLine()) != null) {
                String[] fields = line.split(",");
                orderModels.add(new OrderModel(fields[0], 
                        Long.parseLong(fields[1]), 
                        Double.parseDouble(fields[2]), 
                        fields[3]));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return orderModels;
    }
}
4.5.4 创建消费者工具类
package cn.itcast.day14.serialization_java;

import cn.itcast.day14.beans.OrderModel;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.util.Arrays;
import java.util.Properties;
/**
 * @author lql
 * @time 2024-03-10 16:38:29
 * @description TODO
 */
public class OrderConsumerJava {
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.put("bootstrap.servers", "node1:9092");
        prop.put("group.id", "order");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        
        // 设置反序列化类为自定义的avro反序列化类
        prop.put("value.deserializer", "cn.itcast.day14.serialization_java.SimpleAvroSchemaJava");
        
        KafkaConsumer<String, OrderModel> consumer = new KafkaConsumer<String, OrderModel>(prop);
        
        consumer.subscribe(Arrays.asList("order"));
        while (true) {
            // poll 方法用于从 kafka 中拉取数据
            ConsumerRecords<String, OrderModel> poll = consumer.poll(1000);
            for (ConsumerRecord<String, OrderModel> stringStockConsumerRecord : poll) {
                System.out.println(stringStockConsumerRecord.value());
            }
        }
    }
}
4.5.5 运行程序
# 首先启动zookeeper

# 启动 kafka,记得后台启动
后台:
	cd /export/servers/kafka_2.11-0.10.0.0
	nohup bin/kafka-server-start.sh config/server.properties 2>&1 &
	停止:
	cd /export/servers/kafka_2.11-0.10.0.0
	bin/kafka-server-stop.sh
	
# 创建topic
bin/kafka-topics.sh --create --zookeeper node1:2181 --replication-factor 1 --partitions 1 --topic order
# 模拟消费者
bin/kafka-console-consumer.sh --zookeeper node1:2181 --from-beginning --topic order

结果:

  • 生产者打印:
[{"userId": "user_001", "timestamp": 1621718199, "money": 10.1, "category": "电脑"}, {"userId": "user_001", "timestamp": 1621718201, "money": 14.1, "category": "手机"}, {"userId": "user_002", "timestamp": 1621718202, "money": 82.5, "category": "手机"}, {"userId": "user_001", "timestamp": 1621718205, "money": 15.6, "category": "电脑"}, {"userId": "user_004", "timestamp": 1621718207, "money": 10.2, "category": "家电"}, {"userId": "user_001", "timestamp": 1621718208, "money": 15.8, "category": "电脑"}, {"userId": "user_005", "timestamp": 1621718212, "money": 56.1, "category": "电脑"}, {"userId": "user_002", "timestamp": 1621718260, "money": 40.3, "category": "家电"}, {"userId": "user_001", "timestamp": 1621718580, "money": 11.5, "category": "家居"}, {"userId": "user_001", "timestamp": 1621718860, "money": 61.6, "category": "家居"}]
数据写入成功
  • 消费者打印:
{"userId": "user_001", "timestamp": 1621718199, "money": 10.1, "category": "电脑"}
{"userId": "user_001", "timestamp": 1621718201, "money": 14.1, "category": "手机"}
{"userId": "user_002", "timestamp": 1621718202, "money": 82.5, "category": "手机"}
{"userId": "user_001", "timestamp": 1621718205, "money": 15.6, "category": "电脑"}
{"userId": "user_004", "timestamp": 1621718207, "money": 10.2, "category": "家电"}
{"userId": "user_001", "timestamp": 1621718208, "money": 15.8, "category": "电脑"}
{"userId": "user_005", "timestamp": 1621718212, "money": 56.1, "category": "电脑"}
{"userId": "user_002", "timestamp": 1621718260, "money": 40.3, "category": "家电"}
{"userId": "user_001", "timestamp": 1621718580, "money": 11.5, "category": "家居"}
{"userId": "user_001", "timestamp": 1621718860, "money": 61.6, "category": "家居"}

总结:值的序列化需要指定自己定义的序列化。


4.6 使用 Flink 自定义序列化到 Kafka
4.6.1 准备数据

order.csv

user_001,1621718199,10.1,电脑
user_001,1621718201,14.1,手机
user_002,1621718202,82.5,手机
user_001,1621718205,15.6,电脑
user_004,1621718207,10.2,家电
user_001,1621718208,15.8,电脑
user_005,1621718212,56.1,电脑
user_002,1621718260,40.3,家电
user_001,1621718580,11.5,家居
user_001,1621718860,61.6,家居

4.6.2 自定义Avro 序列化和反序列化

首先需要实现2个接口分别为 SerializationSchema 和 DeserializationSchema 分别是序列化和反序列化

package cn.itcast.day14.serialization_flink;

/**
 * @author lql
 * @time 2024-03-10 17:35:09
 * @description TODO
 */
import cn.itcast.day14.beans.OrderModel;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.flink.api.common.serialization.DeserializationSchema;
import org.apache.flink.api.common.serialization.SerializationSchema;
import org.apache.flink.api.common.typeinfo.TypeInformation;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 *  自定义序列化和反序列化
 */
public class SimpleAvroSchemaFlink implements DeserializationSchema<OrderModel>, SerializationSchema<OrderModel> {

    @Override
    public byte[] serialize(OrderModel order) {
        // 创建序列化执行器
        SpecificDatumWriter<OrderModel> writer = new SpecificDatumWriter<OrderModel>(order.getSchema());
        // 创建一个流 用存储序列化后的二进制文件
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 创建二进制编码器
        BinaryEncoder encoder = EncoderFactory.get().directBinaryEncoder(out, null);
        try {
            // 数据入都流中
            writer.write(order, encoder);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return out.toByteArray();
    }

    @Override
    public TypeInformation<OrderModel> getProducedType() {
        return TypeInformation.of(OrderModel.class);
    }

    @Override
    public OrderModel deserialize(byte[] bytes) throws IOException {
        // 用来保存结果数据
        OrderModel userBehavior = new OrderModel();
        // 创建输入流用来读取二进制文件
        ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(bytes);
        // 创建输入序列化执行器
        SpecificDatumReader<OrderModel> stockSpecificDatumReader = new SpecificDatumReader<OrderModel>(userBehavior.getSchema());
        //创建二进制解码器
        BinaryDecoder binaryDecoder = DecoderFactory.get().directBinaryDecoder(arrayInputStream, null);
        try {
            // 数据读取
            userBehavior=stockSpecificDatumReader.read(null, binaryDecoder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 结果返回
        return userBehavior;
    }

    @Override
    public boolean isEndOfStream(OrderModel userBehavior) {
        return false;
    }
}

4.6.3 创建 Flink-source 类
package cn.itcast.day14.serialization_flink;

/**
 * @author lql
 * @time 2024-03-10 17:37:15
 * @description TODO
 */
import cn.itcast.day14.beans.OrderModel;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer;

import java.util.Properties;

public class OrderProducerFlink {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<String> value = env.readTextFile("D:\\IDEA_Project\\BigData_Java\\flinkbase_pro\\data\\input\\order.csv");

        DataStream<OrderModel> orderModelDataStream = value.map(row -> {
            String[] fields = row.split(",");
            return new OrderModel(fields[0], Long.parseLong(fields[1]), Double.parseDouble(fields[2]), fields[3]);
        });

        Properties prop = new Properties();
        prop.setProperty("bootstrap.servers", "node1:9092");
        //4.连接Kafka
        FlinkKafkaProducer<OrderModel> producer = new FlinkKafkaProducer<>(
                "order",
                new SimpleAvroSchemaFlink(),
                prop
        );

        //5.将数据打入kafka
        orderModelDataStream.addSink(producer);

        //6.执行任务
        env.execute();
    }
}
4.6.4 创建 Flink-sink 类
package cn.itcast.day14.serialization_flink;

/**
 * @author lql
 * @time 2024-03-10 17:40:04
 * @description TODO
 */
import cn.itcast.day14.beans.OrderModel;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;

import java.util.Properties;

public class OrderConsumerFlink {
    public static void main(String[] args) throws Exception {
        //1.构建流处理运行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1); // 设置并行度1 方便后面测试
        // 2.设置kafka 配置信息
        Properties prop = new Properties();
        prop.put("bootstrap.servers", "node1:9092");
        prop.put("group.id", "UserBehavior");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        // 下面有提及:SimpleAvroSchemaFlink,上面就不需要指定了!
        // 3.构建Kafka 连接器
        FlinkKafkaConsumer kafka = new FlinkKafkaConsumer<OrderModel>("order", new SimpleAvroSchemaFlink(), prop);

        //4.设置Flink层最新的数据开始消费
        kafka.setStartFromLatest();
        //5.基于kafka构建数据源
        DataStream<OrderModel> data = env.addSource(kafka);
        //6.结果打印
        data.print();
        env.execute();
    }
}
4.6.5 运行程序

这里运用 Kafka-Tool 2.0.7 可视化工具,工具包放在资源处啦,大家感兴趣可以观看我上传的资源哟!

总结:📚 刚开始学习这个知识点时,我真是感觉有些吃力,觉得它太抽象、太难以理解了。但想到这是企业工作环境中必须掌握的技术,能够为企业节省资源、提高数据存储效率,我就鼓起勇气,决定迎难而上。💪

于是,我根据例子,一个字母一个字母地敲下代码,反复调试、尝试。终于,当程序运行成功的那一刻,我感到了前所未有的成就感!

🎉原来,成功真的就是坚持的结果。只有当你坚持不懈地努力,才能有机会看到胜利的曙光。

🌈明天,我也要继续努力学习,不断挑战自己,迎接更多的成功!🚀 加油!💪

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

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

相关文章

RabbitMQ - 06 - Topic交换机

目录 控制台创建队列与交换机 编写消费者方法 编写生产者测试方法 结果 Topic交换机与Direct交换机基本一致 可参考 这篇帖子 http://t.csdnimg.cn/AuvoK topic交换机与Direct交换机的区别是 Topic交换机接收的消息RoutingKey必须是多个单词&#xff0c;以 . 分割 Topic交…

练习01-登录注册(简单)

一、用户登录/注册实现 综合前面学的知识来实现简单的注册登录功能 1.准备工作 注册登录页面 数据库&#xff0c;数据表 mybatis 坐标引入&#xff0c;MySQL驱动 配置 映射文件 用户实体类 Servlet代码 2.页面 不想手写的可以看博主IT黄大大【带源码】 【炫酷登录界…

贝叶斯优化CNN-GRU回归预测(matlab代码)

贝叶斯优化CNN-GRU回归预测matlab代码 贝叶斯优化方法则采用贝叶斯思想&#xff0c;通过不断探索各种参数组合的结果&#xff0c;根据已有信息计算期望值&#xff0c;并选择期望值最大的组合作为最佳策略&#xff0c;从而在尽可能少的实验次数下达到最优解。 数据为Excel股票…

PostgreSQL数据优化——死元组清理

最近遇到一个奇怪的问题&#xff0c;一个百万级的PostgreSQL表&#xff0c;只有3个索引。但是每次执行insert或update语句就要几百ms以上。经过查询发现是一个狠简单的问题&#xff0c;数据库表死元组太多了&#xff0c;需要手动清理。 在 PG 中&#xff0c;update/delete 语句…

每日五道java面试题之springMVC篇(二)

目录&#xff1a; 第一题. 请描述Spring MVC的工作流程&#xff1f;描述一下 DispatcherServlet 的工作流程&#xff1f;第二题. MVC是什么&#xff1f;MVC设计模式的好处有哪些?第三题. 注解原理是什么?第四题. Spring MVC常用的注解有哪些&#xff1f;第五题. SpingMvc中的…

【数据结构初阶 9】内排序

文章目录 &#x1f308; 1. 直接插入排序&#x1f308; 2. 希尔排序&#x1f308; 3. 简单选择排序&#x1f308; 4. 堆排序&#x1f308; 5. 冒泡排序&#x1f308; 6. 快速排序6.1 霍尔版快排6.2 挖坑版快排6.3 双指针快排6.4 非递归快排 &#x1f308; 7. 归并排序7.1 递归版…

用户管理【MySQL】

文章目录 查看用户信息创建用户修改密码删除用户授予权限收回权限 查看用户信息 在名为mysql的数据库中有一个表user维护着 MySQL 的用户信息。 其中&#xff1a; user&#xff1a; 表示该用户的用户名。host&#xff1a; 表示该用户可以从哪个主机登录&#xff0c;localhost…

了解飞行时间传感

简介:测距技术 人类和许多动物利用各种感官来测量与其他物体的距离。视觉是最常用的。在晚上,触觉可以用来感受其他物体的存在——当然触觉对于视障人

读算法的陷阱:超级平台、算法垄断与场景欺骗笔记06_共谋(下)

1. 博弈论 1.1. 当市场竞争对手之间普遍存在着误解和不信任情绪时&#xff0c;从长远来看&#xff0c;他们一半时间是在合作&#xff0c;另一半时间则是在背叛承诺 1.2. 当一方越了解对手&#xff0c;或者说可以更好地掌握对方的战略性行为时&#xff0c;他才可能找到展开合作…

b树(一篇文章带你 理解 )

目录 一、引言 二、B树的基本定义 三、B树的性质与操作 1 查找操作 2 插入操作 3 删除操作 四、B树的应用场景 1 数据库索引 2 文件系统 3 网络路由表 五、哪些数据库系统不使用B树进行索引 1 列式数据库 2 图形数据库 3 内存数据库 4 NoSQL数据库 5 分布式数据…

理解linux进程

基本概念 课本概念&#xff1a;程序的一个执行实例&#xff0c;正在执行的程序等 内核观点&#xff1a;担当分配系统资源&#xff08;CPU时间&#xff0c;内存&#xff09;的实体 windows上的进程 由上图可以看出在OS中进程可以同时存在并且非常多 大概理解进程 进程内核task_s…

SpringSecurity两种验证方式及调用流程

一、HttpBasic方式 <security:http-basic/> 二、Formlogin方式 <security:form-login login-page"/userLogin" /> 三、SpringSecurity执行流程

OpenCV的常用数据类型

OpenCV涉及的常用数据类型除包含C的基本数据类型,如&#xff1a;char、uchar&#xff0c;int、unsigned int,short 、long、float、double等数据类型外, 还包含Vec&#xff0c;Point、Scalar、Size、Rect、RotatedRect、Mat等类。C中的基本数据类型不需再做说明下面重点介绍一下…

redisson解决redis服务器的主从一致性问题

redisson解决redis的主节点和从节点一致性的问题。从而解决锁被错误获取的情况。 实际开发中我们会搭建多台redis服务器&#xff0c;但这些服务器分主次&#xff0c;主服务器负责处理写的操作&#xff08;增删改&#xff09;&#xff0c;从服务器负责处理读的操作&#xff0c;…

全国保护性耕作/常规耕作农田分类数据集

基于Sentinel-2遥感产品&#xff0c;使用来自文献调研和目视解译产生的保护性/常规耕作样本点&#xff0c;通过交叉验证方法训练随机森林分类器&#xff0c;生成了2016-2020年全国保护性耕作/常规耕作农田分类数据集。分类代码&#xff1a;0值代表非农田&#xff0c;1值表示第一…

掌握React中的useEffect:函数组件中的魔法钩子

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Django 模版基本语法

Django学习笔记 模版语法 本质&#xff1a;在HTML中写一些占位符&#xff0c;由数据对这些占位符进行替换和处理。 views.py def page2(request):#定义一些变量将变量传送给templates中的html文件name1 sallyname2 yingyinghobbys [swimming,badminton,reading]person {…

数学建模【对粒子群算法中惯性权重和学习因子的改进】

一、改进原因 这是前面 数学建模【粒子群算法】 中的一部分&#xff0c;这里提到了w存在的一些问题&#xff0c;那么本篇介绍一些方法对w和因子进行一些改进&#xff0c;提高粒子群算法的效率和准确度。 二、改进方法 1.线性递减惯性权重 惯性权重w体现的是粒子继承先前的速度…

如何获取用户请求的真实ip,并返回访问者的ip地理位置?node,vue

一、获取真实IP 方式1、前端调用免费公共接口获取 前端获取访问者的真实的外网ip,可以通过调用接口https://api.ipify.org/来获取。你也可以直接在网页上访问它来看自己的外网ip。 ipify介绍&#xff1a; ipify是一个免费的公共 API&#xff0c;用于获取设备的公共 IP 地址。…

备考2025年AMC8数学竞赛:吃透2000-2024年600道AMC8真题就够

我们继续来随机看五道AMC8的真题和解析&#xff0c;根据实践经验&#xff0c;对于想了解或者加AMC8美国数学竞赛的孩子来说&#xff0c;吃透AMC8历年真题是备考最科学、最有效的方法之一。 即使不参加AMC8竞赛&#xff0c;吃透了历年真题600道和背后的知识体系&#xff0c;那么…