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

初始向量数据库之Milvus

写在前面

之前学习图像识别算法的时候,了解到向量数据库,因为当时没有应用场景就没有进行系统的学习。直到最近在跟一个朋友撰写大模型应用开发相关的书籍时,又了解到了向量数据库的内容,因此觉得必要系统学习一下向量数据库的内容。

在正式介绍向量数据库之前,需要了解一下什么是向量数据库,他与传统数据库的区别在哪里,向量数据库常应用在什么地方等等。为此整理一个传统数据库和向量数据库的区别,如下所示:

维度传统数据库(关系型 / NoSQL)向量数据库
数据类型结构化 / 半结构化数据(可直接解读)高维向量(非结构化数据的编码)
核心查询方式精确匹配(等于、大于、关联)相似性查询(语义距离计算)
索引结构B 树、哈希表等HNSW、IVF 等 ANN 索引
设计目标高效管理结构化数据,保证精确性高效检索向量,保证语义相似性
典型应用场景金融交易、用户管理、高并发读写RAG、以图搜图、智能推荐

一、Milvus数据库基本概念

首先,需要了解一下Milvus数据库的基本概念,基础概念可以帮助我们快速理解和掌握Milvus数据库,下面将从四个方面进行总结介绍Milvus数据库的基础概念。

1、数据模型

  • 向量:高维数值数组,是处理核心,由原始数据经嵌入模型转换而来,通过 “距离” 衡量相似性。
  • 实体:基本数据单元,含唯一主键和字段(必选向量字段 + 可选标量字段)。
  • 集合:同类实体的集合(类似 “表”),需预先定义字段结构,创建后不可修改。
  • 分区:集合的子集,按业务逻辑拆分数据以提升查询效率,支持动态管理。
  • :数据存储的物理单元,分活跃段(可写入)和密封段(不可修改,可建索引)。

2、索引机制

  • 索引:加速向量相似性搜索的特殊数据结构,如 HNSW(图结构,快且准)、IVF 类(聚类分桶,平衡性能)等。
  • 索引参数:影响性能与精度,如 IVF 的 nlist(桶数量)、HNSW 的 M(邻居数)等。

3、查询与操作

  • 相似度度量:衡量向量相似性的方式,如欧氏距离(L2)、余弦相似度等,需在创建集合时指定。
  • Top-K 查询:返回与目标向量最相似的前 K 个结果,是核心查询方式。
  • 标量过滤:结合标量字段条件(如时间、标签)进行联合查询。
  • 分区键:自动将实体分配到对应分区的标量字段,简化分区管理。

4、架构组件

  • 代理(Proxy):接入层,负责请求接收、负载均衡与转发。
  • 元数据存储(Meta Store):基于 etcd 存储元数据(集合结构、索引信息等)。
  • 查询节点(Query Node):处理查询请求,加载索引并执行搜索,可水平扩展。
  • 数据节点(Data Node):负责数据持久化,写入对象存储并生成日志。
  • 索引节点(Index Node):后台构建密封段的索引,提升查询效率。

二、Milvus数据库搭建

Milvus数据库提供了Docker Compose 搭建单节点的脚本,本次演示的版本为2.6版本。其github地址为:Release milvus-2.6.0 · milvus-io/milvus · GitHub。

version: '3.5'services:etcd:container_name: milvus-etcdimage: quay.io/coreos/etcd:v3.5.18environment:- ETCD_AUTO_COMPACTION_MODE=revision- ETCD_AUTO_COMPACTION_RETENTION=1000- ETCD_QUOTA_BACKEND_BYTES=4294967296- ETCD_SNAPSHOT_COUNT=50000volumes:- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcdcommand: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcdhealthcheck:test: ["CMD", "etcdctl", "endpoint", "health"]interval: 30stimeout: 20sretries: 3minio:container_name: milvus-minioimage: minio/minio:RELEASE.2024-12-18T13-15-44Zenvironment:MINIO_ACCESS_KEY: minioadminMINIO_SECRET_KEY: minioadminports:- "9001:9001"- "9000:9000"volumes:- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_datacommand: minio server /minio_data --console-address ":9001"healthcheck:test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]interval: 30stimeout: 20sretries: 3standalone:container_name: milvus-standaloneimage: milvusdb/milvus:v2.6.0command: ["milvus", "run", "standalone"]security_opt:- seccomp:unconfinedenvironment:ETCD_ENDPOINTS: etcd:2379MINIO_ADDRESS: minio:9000MQ_TYPE: woodpeckervolumes:- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvushealthcheck:test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]interval: 30sstart_period: 90stimeout: 20sretries: 3ports:- "19530:19530"- "9091:9091"depends_on:- "etcd"- "minio"networks:default:name: milvus

Java API使用Milvus数据库

部署好Milvus数据库之后,下面将介绍如何使用Java来访问Milvus数据库,并针对Java操作数据库封装工具类。

Maven依赖

首先,在正式介绍工具类的封装之前,需要导入Java操作Milvus数据库的SDK。下面是通过Maven的方式进行依赖的导入和构建,具体内容如下:

<dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId><version>2.6.1</version>
</dependency>

Milvus工具类

完成依赖的导入后,下面将开始介绍Milvus数据库的工具类的封装。本文是以SpringBoot为基础,将Milvus数据库封装为组件使用,需要注意的是,配置文件或者环境变量中需要配置Milvus数据库相关的连接参数,具体代码如下所示:

import io.milvus.client.MilvusServiceClient;
import io.milvus.grpc.*;
import io.milvus.param.*;
import io.milvus.param.collection.*;
import io.milvus.param.index.*;
import io.milvus.param.partition.*;
import io.milvus.param.dml.*;
import io.milvus.param.highlevel.dml.*;
import io.milvus.param.highlevel.dml.response.*;
import io.milvus.response.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;/*** Milvus工具类*/
@Slf4j
@Component
public class MilvusUtils {@Value("${milvus.host:localhost}")private String host;@Value("${milvus.port:19530}")private int port;@Value("${milvus.username:}")private String username;@Value("${milvus.password:}")private String password;private MilvusServiceClient milvusClient;/*** 初始化Milvus客户端连接*/@PostConstructpublic void init() {ConnectParam.Builder builder = ConnectParam.newBuilder().withHost(host).withPort(port);// 如果配置了用户名和密码,则添加认证信息if (StringUtils.hasText(username) && StringUtils.hasText(password)) {builder.withAuthorization(username, password);}ConnectParam connectParam = builder.build();milvusClient = new MilvusServiceClient(connectParam);log.info("Milvus client connected to {}:{}", host, port);}/*** 关闭Milvus客户端连接*/@PreDestroypublic void destroy() {if (milvusClient != null) {milvusClient.close();log.info("Milvus client connection closed");}}/*** 检查集合是否存在** @param collectionName 集合名称* @return 是否存在*/public boolean hasCollection(String collectionName) {HasCollectionParam param = HasCollectionParam.newBuilder().withCollectionName(collectionName).build();R<Boolean> response = milvusClient.hasCollection(param);handleResponseStatus(response);return response.getData();}/*** 创建集合** @param collectionName 集合名称* @param schema         集合Schema*/public void createCollection(String collectionName, CollectionSchemaParam schema) {CreateCollectionParam param = CreateCollectionParam.newBuilder().withCollectionName(collectionName).withSchema(schema).build();R<RpcStatus> response = milvusClient.createCollection(param);handleResponseStatus(response);}/*** 创建集合(带额外参数)** @param collectionName 集合名称* @param schema         集合Schema* @param shardsNum      分片数量* @param consistencyLevel 一致性级别*/public void createCollection(String collectionName, CollectionSchemaParam schema, Integer shardsNum, ConsistencyLevelEnum consistencyLevel) {CreateCollectionParam.Builder builder = CreateCollectionParam.newBuilder().withCollectionName(collectionName).withSchema(schema);if (shardsNum != null) {builder.withShardsNum(shardsNum);}if (consistencyLevel != null) {builder.withConsistencyLevel(consistencyLevel);}R<RpcStatus> response = milvusClient.createCollection(builder.build());handleResponseStatus(response);}/*** 删除集合** @param collectionName 集合名称*/public void dropCollection(String collectionName) {DropCollectionParam param = DropCollectionParam.newBuilder().withCollectionName(collectionName).build();R<RpcStatus> response = milvusClient.dropCollection(param);handleResponseStatus(response);}/*** 加载集合到内存** @param collectionName 集合名称*/public void loadCollection(String collectionName) {LoadCollectionParam param = LoadCollectionParam.newBuilder().withCollectionName(collectionName).build();R<RpcStatus> response = milvusClient.loadCollection(param);handleResponseStatus(response);}/*** 加载集合到内存(带分区)** @param collectionName 集合名称* @param partitionNames 分区名称列表*/public void loadCollection(String collectionName, List<String> partitionNames) {LoadCollectionParam.Builder builder = LoadCollectionParam.newBuilder().withCollectionName(collectionName);if (!CollectionUtils.isEmpty(partitionNames)) {builder.withPartitionNames(partitionNames);}R<RpcStatus> response = milvusClient.loadCollection(builder.build());handleResponseStatus(response);}/*** 释放集合** @param collectionName 集合名称*/public void releaseCollection(String collectionName) {ReleaseCollectionParam param = ReleaseCollectionParam.newBuilder().withCollectionName(collectionName).build();R<RpcStatus> response = milvusClient.releaseCollection(param);handleResponseStatus(response);}/*** 检查分区是否存在** @param collectionName 集合名称* @param partitionName  分区名称* @return 是否存在*/public boolean hasPartition(String collectionName, String partitionName) {HasPartitionParam param = HasPartitionParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).build();R<Boolean> response = milvusClient.hasPartition(param);handleResponseStatus(response);return response.getData();}/*** 创建分区** @param collectionName 集合名称* @param partitionName  分区名称*/public void createPartition(String collectionName, String partitionName) {CreatePartitionParam param = CreatePartitionParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).build();R<RpcStatus> response = milvusClient.createPartition(param);handleResponseStatus(response);}/*** 删除分区** @param collectionName 集合名称* @param partitionName  分区名称*/public void dropPartition(String collectionName, String partitionName) {DropPartitionParam param = DropPartitionParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).build();R<RpcStatus> response = milvusClient.dropPartition(param);handleResponseStatus(response);}/*** 插入数据** @param collectionName 集合名称* @param insertRows     插入数据* @return 插入结果*/public InsertResponse insert(String collectionName, List<InsertParam.Field> insertRows) {InsertParam param = InsertParam.newBuilder().withCollectionName(collectionName).withFields(insertRows).build();R<MutationResult> response = milvusClient.insert(param);handleResponseStatus(response);return new InsertResponse(response.getData());}/*** 插入数据(指定分区)** @param collectionName 集合名称* @param partitionName  分区名称* @param insertRows     插入数据* @return 插入结果*/public InsertResponse insert(String collectionName, String partitionName, List<InsertParam.Field> insertRows) {InsertParam param = InsertParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).withFields(insertRows).build();R<MutationResult> response = milvusClient.insert(param);handleResponseStatus(response);return new InsertResponse(response.getData());}/*** 查询数据** @param collectionName 集合名称* @param expr           查询表达式* @param outputFields   输出字段* @return 查询结果*/public QueryResultsWrapper query(String collectionName, String expr, List<String> outputFields) {QueryParam param = QueryParam.newBuilder().withCollectionName(collectionName).withExpr(expr).withOutFields(outputFields).build();R<QueryResults> response = milvusClient.query(param);handleResponseStatus(response);return new QueryResultsWrapper(response.getData());}/*** 查询数据(指定分区)** @param collectionName 集合名称* @param partitionNames 分区名称列表* @param expr           查询表达式* @param outputFields   输出字段* @return 查询结果*/public QueryResultsWrapper query(String collectionName, List<String> partitionNames, String expr, List<String> outputFields) {QueryParam.Builder builder = QueryParam.newBuilder().withCollectionName(collectionName).withExpr(expr).withOutFields(outputFields);if (!CollectionUtils.isEmpty(partitionNames)) {builder.withPartitionNames(partitionNames);}R<QueryResults> response = milvusClient.query(builder.build());handleResponseStatus(response);return new QueryResultsWrapper(response.getData());}/*** 向量相似性搜索** @param collectionName 集合名称* @param vectorField    向量字段名* @param vectors        查询向量* @param topK           返回最相似的K个结果* @param expr           过滤表达式* @param outputFields   输出字段* @return 搜索结果*/public SearchResultsWrapper search(String collectionName, String vectorField, List<?> vectors,int topK, String expr, List<String> outputFields) {SearchParam param = SearchParam.newBuilder().withCollectionName(collectionName).withMetricType(MetricType.L2).withOutFields(outputFields).withTopK(topK).withVectors(vectors).withVectorFieldName(vectorField).withExpr(expr).build();R<SearchResults> response = milvusClient.search(param);handleResponseStatus(response);return new SearchResultsWrapper(response.getData());}/*** 向量相似性搜索(高级配置)** @param collectionName 集合名称* @param partitionNames 分区名称列表* @param vectorField    向量字段名* @param vectors        查询向量* @param topK           返回最相似的K个结果* @param metricType     度量类型* @param expr           过滤表达式* @param outputFields   输出字段* @param params         搜索参数* @return 搜索结果*/public SearchResultsWrapper search(String collectionName, List<String> partitionNames, String vectorField, List<?> vectors, int topK, MetricType metricType, String expr, List<String> outputFields, Map<String, Object> params) {SearchParam.Builder builder = SearchParam.newBuilder().withCollectionName(collectionName).withMetricType(metricType != null ? metricType : MetricType.L2).withOutFields(outputFields).withTopK(topK).withVectors(vectors).withVectorFieldName(vectorField);if (!CollectionUtils.isEmpty(partitionNames)) {builder.withPartitionNames(partitionNames);}if (StringUtils.hasText(expr)) {builder.withExpr(expr);}if (params != null && !params.isEmpty()) {builder.withParams(params.toString());}R<SearchResults> response = milvusClient.search(builder.build());handleResponseStatus(response);return new SearchResultsWrapper(response.getData());}/*** 删除数据** @param collectionName 集合名称* @param expr           删除表达式* @return 删除结果*/public MutationResult delete(String collectionName, String expr) {DeleteParam param = DeleteParam.newBuilder().withCollectionName(collectionName).withExpr(expr).build();R<MutationResult> response = milvusClient.delete(param);handleResponseStatus(response);return response.getData();}/*** 删除数据(指定分区)** @param collectionName 集合名称* @param partitionName  分区名称* @param expr           删除表达式* @return 删除结果*/public MutationResult delete(String collectionName, String partitionName, String expr) {DeleteParam param = DeleteParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).withExpr(expr).build();R<MutationResult> response = milvusClient.delete(param);handleResponseStatus(response);return response.getData();}/*** 创建索引** @param collectionName 集合名称* @param fieldName      字段名称* @param indexType      索引类型* @param metricType     度量类型* @param extraParam     额外参数*/public void createIndex(String collectionName, String fieldName, IndexType indexType,MetricType metricType, String extraParam) {CreateIndexParam param = CreateIndexParam.newBuilder().withCollectionName(collectionName).withFieldName(fieldName).withIndexType(indexType).withMetricType(metricType).withExtraParam(extraParam).build();R<RpcStatus> response = milvusClient.createIndex(param);handleResponseStatus(response);}/*** 创建索引(带索引名称)** @param collectionName 集合名称* @param indexName      索引名称* @param fieldName      字段名称* @param indexType      索引类型* @param metricType     度量类型* @param extraParam     额外参数*/public void createIndex(String collectionName, String indexName, String fieldName, IndexType indexType, MetricType metricType, String extraParam) {CreateIndexParam param = CreateIndexParam.newBuilder().withCollectionName(collectionName).withIndexName(indexName).withFieldName(fieldName).withIndexType(indexType).withMetricType(metricType).withExtraParam(extraParam).build();R<RpcStatus> response = milvusClient.createIndex(param);handleResponseStatus(response);}/*** 检查索引是否存在** @param collectionName 集合名称* @param fieldName      字段名称* @return 是否存在索引*/public boolean hasIndex(String collectionName, String fieldName) {DescribeIndexParam param = DescribeIndexParam.newBuilder().withCollectionName(collectionName).withFieldName(fieldName).build();R<DescribeIndexResponse> response = milvusClient.describeIndex(param);return response.getStatus() == R.Status.Success.getCode();}/*** 删除索引** @param collectionName 集合名称* @param fieldName      字段名称*/public void dropIndex(String collectionName, String fieldName) {DropIndexParam param = DropIndexParam.newBuilder().withCollectionName(collectionName).withFieldName(fieldName).build();R<RpcStatus> response = milvusClient.dropIndex(param);handleResponseStatus(response);}/*** 获取集合统计信息** @param collectionName 集合名称* @return 统计信息*/public GetCollectionStatisticsResponse getCollectionStatistics(String collectionName) {GetCollectionStatisticsParam param = GetCollectionStatisticsParam.newBuilder().withCollectionName(collectionName).build();R<GetCollectionStatisticsResponse> response = milvusClient.getCollectionStatistics(param);handleResponseStatus(response);return response.getData();}/*** 获取集合统计信息(指定分区)** @param collectionName 集合名称* @param partitionName  分区名称* @return 统计信息*/public GetCollectionStatisticsResponse getCollectionStatistics(String collectionName, String partitionName) {GetCollectionStatisticsParam param = GetCollectionStatisticsParam.newBuilder().withCollectionName(collectionName).withPartitionName(partitionName).build();R<GetCollectionStatisticsResponse> response = milvusClient.getCollectionStatistics(param);handleResponseStatus(response);return response.getData();}/*** 刷新集合,将缓冲区的数据持久化** @param collectionName 集合名称*/public void flush(String collectionName) {FlushParam param = FlushParam.newBuilder().addCollectionName(collectionName).build();R<FlushResponse> response = milvusClient.flush(param);handleResponseStatus(response);}/*** 刷新多个集合** @param collectionNames 集合名称列表*/public void flush(List<String> collectionNames) {FlushParam param = FlushParam.newBuilder().withCollectionNames(collectionNames).build();R<FlushResponse> response = milvusClient.flush(param);handleResponseStatus(response);}/*** 获取Milvus服务版本信息** @return 版本信息*/public String getVersion() {R<GetVersionResponse> response = milvusClient.getVersion();handleResponseStatus(response);return response.getData().getVersion();}/*** 检查Milvus服务是否健康** @return 是否健康*/public boolean isHealthy() {try {R<CheckHealthResponse> response = milvusClient.checkHealth();return response.getStatus() == R.Status.Success.getCode() && response.getData().getIsHealthy();} catch (Exception e) {log.error("Failed to check Milvus health", e);return false;}}/*** 处理响应状态** @param response 响应结果* @param <T>      响应数据类型*/private <T> void handleResponseStatus(R<T> response) {if (response.getStatus() != R.Status.Success.getCode()) {log.error("Milvus operation failed: {}", response.getMessage());throw new RuntimeException("Milvus operation failed: " + response.getMessage());}}/*** 获取Milvus客户端实例** @return MilvusServiceClient实例*/public MilvusServiceClient getClient() {return milvusClient;}
}

总结

上述的工具类主要实现了以下的方法

连接管理
  • init():初始化 Milvus 客户端连接(使用@PostConstruct注解,启动时自动执行)
  • destroy():关闭 Milvus 客户端连接(使用@PreDestroy注解,销毁时自动执行)
  • getClient():获取 Milvus 客户端实例(MilvusServiceClient
集合(Collection)操作
  • hasCollection(String collectionName):检查集合是否存在
  • createCollection(String collectionName, CollectionSchemaParam schema):创建集合(基础版)
  • createCollection(String collectionName, CollectionSchemaParam schema, Integer shardsNum, ConsistencyLevelEnum consistencyLevel):创建集合(带分片数和一致性级别参数)
  • dropCollection(String collectionName):删除集合
  • loadCollection(String collectionName):加载集合到内存
  • loadCollection(String collectionName, List<String> partitionNames):加载集合到内存(指定分区)
  • releaseCollection(String collectionName):释放内存中的集合
  • getCollectionStatistics(String collectionName):获取集合统计信息
  • getCollectionStatistics(String collectionName, String partitionName):获取集合统计信息(指定分区)
  • flush(String collectionName):刷新集合,将缓冲区数据持久化
  • flush(List<String> collectionNames):刷新多个集合
分区(Partition)操作
  • hasPartition(String collectionName, String partitionName):检查分区是否存在
  • createPartition(String collectionName, String partitionName):创建分区
  • dropPartition(String collectionName, String partitionName):删除分区
数据操作
  • insert(String collectionName, List<InsertParam.Field> insertRows):插入数据
  • insert(String collectionName, String partitionName, List<InsertParam.Field> insertRows):插入数据(指定分区)
  • query(String collectionName, String expr, List<String> outputFields):查询数据
  • query(String collectionName, List<String> partitionNames, String expr, List<String> outputFields):查询数据(指定分区)
  • delete(String collectionName, String expr):删除数据
  • delete(String collectionName, String partitionName, String expr):删除数据(指定分区)
向量搜索
  • search(String collectionName, String vectorField, List<?> vectors, int topK, String expr, List<String> outputFields):向量相似性搜索(基础版,默认 L2 度量)
  • search(String collectionName, List<String> partitionNames, String vectorField, List<?> vectors, int topK, MetricType metricType, String expr, List<String> outputFields, Map<String, Object> params):向量相似性搜索(高级版,支持自定义参数)
索引操作
  • createIndex(String collectionName, String fieldName, IndexType indexType, MetricType metricType, String extraParam):创建索引
  • createIndex(String collectionName, String indexName, String fieldName, IndexType indexType, MetricType metricType, String extraParam):创建索引(带索引名称)
  • hasIndex(String collectionName, String fieldName):检查索引是否存在
  • dropIndex(String collectionName, String fieldName):删除索引
服务状态检查
  • getVersion():获取 Milvus 服务版本信息
  • isHealthy():检查 Milvus 服务是否健康
内部工具方法
  • handleResponseStatus(R<T> response):处理响应状态,若操作失败则抛出异常(私有方法)

写在最后

本文主要介绍了Milvus数据库的基本概念,介绍了如何使用Docker部署Milvus数据库并通过Java API进行工具类的封装,希望对于学习和使用Milvus数据库的你有所帮助。

http://www.lryc.cn/news/624911.html

相关文章:

  • milvus如何存储特殊类型的数据
  • Milvus向量数据库安装步骤
  • 大厂 | 华为半导体业务部2026届秋招启动
  • 【大模型】RAG
  • 基于nvm安装管理多个node.js版本切换使用(附上详细安装使用图文教程+nvm命令大全)
  • ANSI终端色彩控制知识散播(I):语法封装(Python)——《彩色终端》诗评
  • 楼宇自控系统深化设计需关注哪些核心要点?技术与应用解析
  • 第一阶段C#-14:委托,事件
  • ReactNative开发实战——React Native开发环境配置指南
  • 机器翻译论文阅读方法:顶会(ACL、EMNLP)论文解析技巧
  • ADC的实现(单通道,多通道,DMA)
  • 如何编写自己的Spring容器
  • 【EI会议征稿】2025第四届健康大数据与智能医疗国际会议(ICHIH 2025)
  • VS Code Copilot 完整使用教程(含图解)
  • 全局锁应用场景理解
  • 深度学习——R-CNN及其变体
  • 04 类型别名type + 检测数据类型(typeof+instanceof) + 空安全+剩余和展开(运算符 ...)简单类型和复杂类型 + 模块化
  • Spark 运行流程核心组件(三)任务执行
  • 实习两个月总结
  • [系统架构设计师]软件架构的演化与维护(十)
  • SpringBoot--JWT
  • 大数据计算引擎(四)—— Impala
  • React diff——差异协调算法简介
  • 深入解析 Qwen3 GSPO:一种稳定高效的大语言模型强化学习算法
  • 整体设计 之“凝聚式中心点”原型 --整除:智能合约和DBMS的深层融合 之2
  • LLM - MCP传输协议解读:从SSE的单向奔赴到Streamable HTTP的双向融合
  • 【软考架构】第4章 信息安全的抗攻击技术
  • 群晖nas中 打开PHP连接MariaDB 功能扩展
  • CMakeLists.txt 学习笔记
  • SQL详细语法教程(六)存储+索引