当前位置: 首页 > news >正文

【LLM】RedisSearch 向量相似性搜索在 SpringBoot 中的实现

整理不易,请不要吝啬你的赞和收藏。

1. 前言

写这篇文章挺不容易的,网络上对于 SpringBoot 实现 Redis 向量相似性搜索的文章总体来说篇幅较少,并且这些文章很多都写得很粗糙,或者不是我想要的实现方式,所以我不得不阅读大量官方文档,边试错,边修改,这花费了不少时间,不过好在结果还不错。
话不多说,下面说下这篇文章。这篇文章将介绍两种实现方式, 第一种为使用 Jedis 中的 UnifiedJedis 类实现, 第二种为使用 SpringAI 中的 VectorStore 实现。通过这边文章你将收获,如何使用阿里百炼 Embedding 模型实现文本向量化,如何通过连接池获取 UnifiedJedis 对象,如何在 SpringBoot 中实现向量数据的存储以及使用 fTSearch 进行向量相似性搜索,如何使用 SpringAI 的 VecotStore。

2. 前提条件

  • 已安装 Redis Stack ,如何安装请参考 docker compose 安装 Redis Stack 。
  • 已对 Redis 作为向量库有了解,如不了解请参考 Redis 作为向量库入门指南。
  • 项目中引入了 Spring AI Alibaba ,如何引入请参考 Spring AI Alibaba 的简单使用 。
  • 项目中引入了 Redis ,如何引入请参考 SpringBoot 引入 redis 。

3. 使用 UnifiedJedis 实现

:这个方式需要你先创建向量索引,如果不了解请参考 Redis 作为向量库入门指南 。需要注意的是这个方式基于创建的索引数据类型为 Hash

3.1 引入依赖

我的 SpringBoot 版本为3.2.4,spring-ai-alibaba-starter 版本升级为了 1.0.0-M3.2,jdk 版本为17。
:需要注意我之前文章使用的 Redis 客户端为 lettuce,但因其对 RedisSearch 语法支持较差,所以我改为使用 Jedis。Jedis 中的 UnifiedJedis 类对 RedisSeach 语法有很好的支持。

3.1.1 引入 Redis 客户端

我们使用 spring-boot-starter-data-redis 来集成和管理 Redis, 使用 Jedis 作为 Java 中 Redis 的客户端,注意 SpringBoot2.0 默认使用 lettuce 作为客户端,需要排除 lettuce-core 包。
我的 spring-boot-starter-data-redis 版本为 3.2.4,jedis 的版本为 5.2.0
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions>
</dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId>
</dependency>
:建议引入 spring-boot-starter-parent 用来管理 SpringBoot 项目的依赖版本和构建配置。
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.4</version>
</parent>

 3.1.2 引入 Spring AI Alibaba

这个实现方式中,项目中引入 spring-ai-alibaba 主要是为了调用阿里百炼 Embedding 模型实现文本向量化,如果你有其它的文本向量化包,可以改为引用其它的。
我使用的版本是 1.0.0-M3.2,对应 Spring AI 的版本为 1.0.0-M3。
<dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId>
</dependency>

3.2 添加配置

3.2.1 添加 redis 配置

application.yml 文件中添加redis相关配置,包含 host、port、password、连接池信息等。
spring:data:redis:database: 0host: 127.0.0.1port: 6379password: gusy1234jedis:pool:# 连接池最大连接数max-active: 8# 连接池最大空闲连接数max-idle: 8# 连接池最大阻塞等待时间,负值表示没有限制max-wait: 0# 连接池最小空闲连接数min-idle: 2# 连接超时时间(毫秒)timeout: 1000

3.3 配置连接池

3.3.1 使用自定连接池

这个是我读 Jedis 代码摸索出来的,也用了一些时间琢磨,在此做个记录吧,更推荐使用 第二种。使用自定义连接池管理 UnifiedJedis:
@Bean
public UnifiedJedis unifiedJedis() {HostAndPort hostAndPort = new HostAndPort(host, port);// 设置 Jedis 客户端配置DefaultJedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder().password(password).database(database).build();// 设置连接池参数ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();poolConfig.setMaxTotal(maxActive);poolConfig.setMaxIdle(maxIdle);poolConfig.setMinIdle(minIdle);PooledConnectionProvider provider = new PooledConnectionProvider(hostAndPort, jedisClientConfig, poolConfig);return new UnifiedJedis(provider);
}

3.3.2 (推荐)使用 JedisPooled

比较意外的是,在尝试使用 Spring AI 的 Redis VectorStore 实现时,阅读源码,发现了一个更好的创建 UnifiedJedis 连接池的方式,并且是 Redis 推荐的方式( Redis 官方文档),就是使用 JedidsPooled。 JedisPooled 继承自 UnifiedJedis。JedisPooled 在 Jedis 版本 4.0.0 中添加,提供了 类似JedisPool 的功能,但具有更直接的 API。相比于 JedisPool ,JedisPooled 作为连接池更为简单,其不需要为每个命令添加一个 try-with-resources 块。 
@Bean
public JedisPooled jedisPooled() throws URISyntaxException {ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();// 池中最大活跃连接数,默认 8poolConfig.setMaxTotal(maxActive);// 池中最大空闲连接数,默认 8poolConfig.setMaxIdle(maxIdle);// 池中的最小空闲连接数,默认 0poolConfig.setMinIdle(minIdle);// 启用等待连接变为可用poolConfig.setBlockWhenExhausted(true);// 等待连接变为可用的最大秒数,jdk17 以上支持,低版本可用 setMaxWaitMillispoolConfig.setMaxWait(Duration.ofSeconds(1));// 控制检查池中空闲连接的间隔时间,jdk17 以上支持,低版本可用 setTimeBetweenEvictionRunsMillispoolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));return new JedisPooled(poolConfig, new URI(redisUri));
}

3.4 Text Embedding

3.4.1 调用百炼 Embedding Model

使用百炼 Embedding 模型实现将文本转成向量数组,并且自定义了使用的 模型和向量维度等参数。
    public List<Embedding> textEmbedding(List<String> texts) {// 调用百炼 Embedding 模型EmbeddingResponse embeddingResponse = dashScopeEmbeddingModel.call(new EmbeddingRequest(texts,DashScopeEmbeddingOptions.builder().withModel(DashScopeApi.EmbeddingModel.EMBEDDING_V3.getValue()) // 设置使用的模型.withTextType(DashScopeApi.DEFAULT_EMBEDDING_TEXT_TYPE) // 设置文本类型.withDimensions(1024)   // 设置向量维度,可选768、1024、1536.build()));List<Embedding> results = embeddingResponse.getResults();// 打印向量
//        if (CollectionUtils.isEmpty(results)) {
//            int tempSize = results.size();
//            for (int i = 0; i < tempSize; i++) {
//                float[] embeddingValue = results.get(i).getOutput();
//                log.info("embeddingValue:{}", embeddingValue.toString());
//            }
//        }return results;}

3.5 向量数据入库

3.5.1 主要代码

向量数据入库,存入 Hash 类型数据。
@Autowired
private RedisTemplate redisTemplate;/*** 存入向量信息** @param key          redis KEY* @param vectorField  向量存储字段名* @param vectorValue  向量值* @param contentField 向量文本内容存储字段名* @param content      向量文本内容,增加存储文本内容,方便查看向量的内容*/
public void addDocument(String key, String vectorField, float[] vectorValue, String contentField, String content) {// 将向量值转为二进制byte[] vectorByte = CommonUtil.floatArrayToByteArray(vectorValue);// 组装字段mapMap<String, Object> fieldMap = new LinkedMap<>();fieldMap.put(contentField, content.getBytes(StandardCharsets.UTF_8));fieldMap.put(vectorField, vectorByte);// 入库redisTemplate.opsForHash().putAll(key, fieldMap);
}

3.5.2 存储数据展示

可以看到存储的数据类型为 Hash ,其中 vector_filed 为存储的向量值, content 为向量文本内容。

3.6 查询相似度

3.6.1 主要代码

执行 FT.SEARCH 查询相似度,基于 KNN 算法(k 近邻算法),并且使用余弦相似度度量法作为 KNN 的距离度量方式。
@Autowired
private JedisPooled jedisPooled;/*** 相似度搜索** @param queryVector 查询的向量内容* @param k           返回 k 个最相似内容* @param indexName   索引名称* @param vectorField 向量存储字段名* @return*/
public SearchResult similaritySearch(float[] queryVector, int k, String indexName, String vectorField) {// 组装查询// 同:FT.SEARCH embedding_index "* => [KNN 3 @vector_field $query_vector AS distance]"//              PARAMS 2 query_vector "\x12\xa9\xf5\x6c"//              SORTBY distance//              DIALECT 4Query q = new Query("*=>[KNN $K @" + vectorField + " $query_vector AS distance]").returnFields("content", "distance").addParam("K", k).addParam("query_vector", CommonUtil.floatArrayToByteArray(queryVector)).setSortBy("distance", true).dialect(4);// 使用 UnifiedJedis 执行 FT.SEARCH 语句try {SearchResult result = jedisPooled.ftSearch(indexName, q);log.info("redis相似度搜索,result:{}", JSONObject.toJSONString(result));return result;}catch (Exception e) {log.warn("redis相似度搜索,异常:", e);throw new ErrorCodeException(e.getMessage());}
}

3.6.2 查询结果展示

其中 distance 为两向量的距离。

3.7 工具方法

3.7.1 float[] 转二进制

/*** float[] 转二进制** @param floats* @return*/
public static byte[] floatArrayToByteArray(float[] floats) {byte[] bytes = new byte[Float.BYTES * floats.length];ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer().put(floats);return bytes;
}

4 SpringAI VectorStore 实现

Spring AI VectorStore 的实现跟我上面的实现逻辑差不多,只不过 Spring AI 将向量入库和查询都封装成通用的,减少代码量,并且其它向量库的 jar 也都实现了上述接口,可已更方便快捷的切换向量库。
如果配置文件中 initialize-schema 值为 true,索引将在配置初始化的时候自动被创建。
其代码位置( RedisVectorStore. afterPropertiesSet),可以看到其创建的索引数据类型为 JSON,使用余弦计算相似度,下面的 schemaFields() 在我的另一篇文章 Redis 作为向量库入门指南 中有介绍。

4.1 引入依赖

4.1.1 引入 Spring AI Alibaba

我使用的版本是 1.0.0-M3.2,对应 Spring AI 的版本为 1.0.0-M3。
<dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId>
</dependency>

4.1.2 引入 Spring Ai Redis Store

这是 SpringAI 中 Redis 作为 VectorStore 的包,由 spring 提供,跟 SpringAI 版本相同。
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
</dependency>

4.2 添加配置

4.2.1 添加 Spring Ai Alibaba 配置

application.yml 中添加:
spring:ai:dashscope:# 阿里百炼平台申请的 api_key -->api-key: your api_keychat:client:enabled: true

4.2.2 添加 Spring AI Redis Store 配置

这里我使用了手动配置,与 Spring AI 中 自动配置的参数稍有区别,请甄别( Spring AI Redis VectorStore 使用), application.yml 中添加:
spring:data:redis:# uri 为 spring ai 中使用 redis 作为 Vector Store 的配置uri: redis://:gusy1234@127.0.0.1:6379/0ai:# 这里我多包了一层 mine ,因为如果多加一层,spring 会自动装配mine:# redis 作为向量库的配置    vectorstore:redis:# 是否初始化索引信息initialize-schema: true# 索引名称,默认 spring-ai-indexindex-name: spring-ai-index# 向量字段 key 的前缀,默认 embedding:prefix: 'embedding-ai:'# 文档批处理计算嵌入的策略。选项为 TOKEN_COUNT 或 FIXED_SIZEbatching-strategy: TOKEN_COUNT

4.3 配置 JedisPooled 连接池

3.3.2

4.4 配置 VectorSotre

新增 VectorStoreConfig 配置类, VectorSotre 配置之前你需要先配置 EmbeddingModel 和 JedisPooled 。
:官网文档中的代码已过时,这是最新的实现方式。
    @Resourceprivate DashScopeEmbeddingModel dashScopeEmbeddingModel;@Resourceprivate JedisPooled jedisPooled;@Bean("vectorStoreWithDashScope")public VectorStore vectorStore() {return new RedisVectorStore(RedisVectorStore.RedisVectorStoreConfig.builder().withIndexName(indexName).withPrefix(prefix)
//                .withEmbeddingFieldName("embedding")  // 向量字段名,默认 embedding
//                .withContentFieldName("content")  // 文本字段名,默认 content.build(), embeddingModel, jedisPooled, initializeSchema); // initializeSchema 为是否初始化索引配置信息}

4.5 向量数据入库

4.5.1 主要代码

@Autowired
@Qualifier("vectorStoreWithDashScope")
private VectorStore vectorStore;// 向量入库主要代码
List<String> inputInfos = List.of("文本1","文本2");
List<Document> documentList = new ArrayList<>();
inputInfos.forEach(text -> {documentList.add(new Document(text));
});
vectorStore.add(documentList);

4.5.2 存储数据展示

可以看到 Spring AI 存储的向量为 JSON 格式,其 Redis 库中的内容如下,其中 embedding 为向量内容, content 为向量文本:

4.6 查询相似度

4.6.1 主要代码

可以看到代码实现很简单,参数也都是熟悉的,这里不再赘述。
// 相似度查询主要代码
List<Document> result = vectorStore.similaritySearch(org.springframework.ai.vectorstore.SearchRequest.defaults().withQuery(inputInfos.get(0))    // 查询的内容.withTopK(3)// 一个值从 0 到 1 的双精度数,接近1的值表示更高的相似性。默认为为0.75。.withSimilarityThreshold(0.6)
);

4.6.2 查询结果展示

5. 参考文档​​​​​

  • Java 中使用 Jedis 客户端库执行向量搜索
  • Spring AI Redis Vector Database 文档
  • Spring AI Alibaba 向量存储文档
  • Jedis 官方教程

相关文章:

【LLM】RedisSearch 向量相似性搜索在 SpringBoot 中的实现

整理不易&#xff0c;请不要吝啬你的赞和收藏。 1. 前言 写这篇文章挺不容易的&#xff0c;网络上对于 SpringBoot 实现 Redis 向量相似性搜索的文章总体来说篇幅较少&#xff0c;并且这些文章很多都写得很粗糙&#xff0c;或者不是我想要的实现方式&#xff0c;所以我不得不阅…...

如何为64位LabVIEW配置正确的驱动程序

在安装 64位 LabVIEW 后&#xff0c;确保驱动程序正确配置是关键。如果您首先安装了 32位 LabVIEW 和相关驱动&#xff0c;然后安装了 64位 LabVIEW&#xff0c;需要确保为 64位 LabVIEW 安装和配置适当的驱动程序&#xff0c;才能正常访问硬件设备。以下是详细步骤&#xff1a…...

Redis(5,jedis和spring)

在前面的学习中&#xff0c;只是学习了各种redis的操作&#xff0c;都是在redis命令行客户端操作的&#xff0c;手动执行的&#xff0c;更多的时候就是使用redis的api&#xff08;&#xff09;&#xff0c;进一步操作redis程序。 在java中实现的redis客户端有很多&#xff0c;…...

Git 小白入门教程

&#x1f3af; 这篇文章详细介绍了版本控制的重要性&#xff0c;特别是通过Git实现的分布式版本控制相对于SVN集中式控制的优势。文章首先解释了版本控制的基本概念&#xff0c;强调了在文档或项目多版本迭代中备份与恢复任意版本的能力。接着&#xff0c;重点阐述了Git的历史背…...

Python从0到100(八十五):神经网络与迁移学习在猫狗分类中的应用

在人工智能的浩瀚宇宙中&#xff0c;深度学习犹如一颗璀璨的星辰&#xff0c;引领着机器学习和计算机视觉领域的前沿探索。而神经网络&#xff0c;作为深度学习的核心架构&#xff0c;更是以其强大的数据建模能力&#xff0c;成为解决复杂问题的重要工具。今天&#xff0c;我们…...

代码随想录刷题day14(2)|(链表篇)02.07. 链表相交(疑点)

目录 一、链表理论基础 二、链表相交求解思路 三、相关算法题目 四、疑点 一、链表理论基础 代码随想录 二、链表相交求解思路 链表相交时&#xff0c;是结点的位置&#xff0c;也就是指针相同&#xff0c;不是结点的数值相同&#xff1b; 思路&#xff1a;定义两个指针…...

C++ 复习总结记录九

C 复习总结记录九 主要内容 1、list 介绍及使用 2、list 剖析及模拟实现 3、list 与 vector 对比 一 list 介绍及使用 List 相关文档 1、List 在任意位置进行插入和删除的序列式容器 O(1) &#xff0c;且该容器可前后双向迭代 2、List 底层是带头双向循环链表&#xff…...

数据库性能优化(sql优化)_SQL执行计划02_yxy

数据库性能优化_SQL执行计划详解02 常用操作符解读1.1 表扫描类型操作符1.1.1 CSCN 聚集索引扫描1.1.2 CSEK 聚集索引数据定位1.1.3 SSEK 二级索引数据定位1.1.4 SSCN 直接使用二级索引进行扫描1.2 其他常见操作符1.2.1 BLKUP 二次扫描1.2.2 SLCT 选择1.2.3 PRJT 投影1.2.4 NSE…...

Vivado生成X1或X4位宽mcs文件并固化到flash

1.生成mcs文件 01.在vivado里的菜单栏选择"tools"工具栏 02.在"tools"里选择"生成内存配置文件" 03.配置参数 按照FPGA板上的flash型号进行选型&#xff0c;相关配置步骤可参考下图。 注意&#xff1a;Flash数据传输位宽如果需要选择X4位宽&am…...

在K8S中使用Values文件定制不同环境下的应用配置详解

在Kubernetes&#xff08;简称K8s&#xff09;环境中&#xff0c;应用程序的配置管理是一项关键任务。为了确保应用程序在不同环境&#xff08;如开发、测试、预发布和生产&#xff09;中都能稳定运行&#xff0c;我们需要为每个环境定制相应的配置。Values文件是在使用Helm管理…...

边缘网关具备哪些功能?

边缘网关&#xff0c;又称边缘计算网关&#xff0c;部署在网络边缘&#xff0c;它位于物联网设备与云计算平台之间&#xff0c;充当着数据流动的“守门员”和“处理器”。通过其强大的数据处理能力和多样化的通信协议支持&#xff0c;边缘网关能够实时分析、过滤和存储来自终端…...

ThinkPHP 8 操作JSON数据

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…...

环境变量配置与问题解决

目录 方法 配置了还是运行不了想要的东西 解决方案 为什么 解决方案 方法 方法一&#xff1a;此电脑右击-属性-相关链接-高级系统设置-环境变量&#xff08;N&#xff09;-系统变量里面找到Path-三个确定】 方法二&#xff1a;winr cmd 黑框输入sysdm.cpl&#xff0c;后面…...

pytorch2.5实例教程

以下是再次为你提供的一个详细的PyTorch使用教程&#xff1a; 一、安装PyTorch 环境准备 确保系统已安装合适版本的Python&#xff08;推荐3.10及以上&#xff09;。 安装方式 CPU版本 对于Linux和macOS&#xff1a; 使用命令 pip install torch torchvision torchaudio。 对…...

【开源免费】基于SpringBoot+Vue.JS智慧图书管理系统(JAVA毕业设计)

本文项目编号 T 152 &#xff0c;文末自助获取源码 \color{red}{T152&#xff0c;文末自助获取源码} T152&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

基于自然语言处理的垃圾短信识别系统

基于自然语言处理的垃圾短信识别系统 &#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 设计题目设计目的设计任务描述设计要求输入和输出…...

Node.js HTTP模块详解:创建服务器、响应请求与客户端请求

Node.js HTTP模块详解&#xff1a;创建服务器、响应请求与客户端请求 Node.js 的 http 模块是 Node.js 核心模块之一&#xff0c;它允许你创建 HTTP 服务器和客户端。以下是一些关键知识点和代码示例&#xff1a; 1. 创建 HTTP 服务器 使用 http.createServer() 方法可以创建…...

Day 17 卡玛笔记

这是基于代码随想录的每日打卡 654. 最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组…...

深圳大学-智能网络与计算-实验一:RFID原理与读写操作

实验目的与要求 掌握超高频RFID标签的寻卡操作。掌握超高频RFID标签的读写操作。掌握超高频RFID标签多张卡读取时的防冲突机制。 方法&#xff0c;步骤 软硬件的连接与设置超高频RFID寻卡操作超高频RFID防冲突机制超高频RFID读写卡操作 实验过程及内容 一&#xff0e;软硬…...

⚡C++ 中 std::transform 函数深度解析:解锁容器元素转换的奥秘⚡【AI 润色】

在 C 编程的世界里&#xff0c;我们常常需要对容器中的元素进行各种转换操作。无论是将数据进行格式调整&#xff0c;还是对元素进行数学运算&#xff0c;高效的转换方法都是提升代码质量和效率的关键。std&#xff1a;&#xff1a;transform函数作为 C 标准库<algorithm &g…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...

6.计算机网络核心知识点精要手册

计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法&#xff1a;数据与控制信息的结构或格式&#xff0c;如同语言中的语法规则语义&#xff1a;控制信息的具体含义和响应方式&#xff0c;规定通信双方"说什么"同步&#xff1a;事件执行的顺序与时序…...