传统的数据库,比如 MySQL 等存的是精确值(数字、字符串),查询靠精确匹配或 LIKE 模糊搜索。
而传统数据库查询的精确匹配或 LIKE 模糊搜索没发进行语义搜索。此时向量数据库,比如 Milvus 就登场了。
向量数据库存的是向量 (一组浮点数数组,如 [0.12, -0.34, 0.56, ...]),查询靠语义相似度。
比如你搜"猫",它能找回" kitten ""猫咪"甚至"宠物",因为它比较的是语义上的"距离",而非字面是否一致。
向量数据库应用场景
-
RAG 知识库:把文档向量化存到 Milvus,用户提问时搜出最相关片段喂给 LLM
-
图片检索:以图搜图,根据视觉特征向量找相似图片
-
推荐系统:用用户行为向量匹配相似用户或商品
-
语义搜索:自然语言搜索非结构化文本
安装 Milvus
安装 Milvus 数据库需要借助 Docker 。使用 Docker 借助 Milvus 官方 github 仓库提供的 docker compose 配置文件可快速安装 Milvus :

把这个配置文件下载下来,使用 docker compose 启动 Milvus :
shell
docker compose -f ./milvus-standalone-docker-compose.yml up -d
用到的镜像根据配置文件自动下载,跑起来之可以在 docker 桌面端看到下载 milvus 、etcd 和 minio 三个镜像:

跑起来的 milvus 容器:

Milvus 通过 19530 端口对外暴露服务。
通过下面命令验证服务是否正常:
bash
docker ps --filter "name=milvus"
# 应看到三个容器均为 healthy

Milvus 数据库增删改查案例
接下来会使用 Node.js 语言实现 Milvus 数据库的增删改查案例。
Node.js 项目初始化
创建 milvus-test 文件夹,安装以下依赖包:
-
@zilliz/milvus2-sdk-node: Milvus 官方 Node.js SDK -
@langchain/openai: 调用嵌入模型,将文本转为向量 -
dotenv: 加载.env中的环境变量
.env 中配置阿里云百炼的 API Key:
ini
DASHSCOPE_API_KEY=sk-xxxxxxxx
在写代码之前,先理解 Milvus 向量数据库几个关键概念:

- Collection:相当于关系数据库中的一张表,存同类型的数据。
- Schema:定义字段结构,如主键 ID、标题、正文、向量。
- Vector Field:存储向量数据的特殊字段,搜索时用它计算相似度。
- Index:为向量字段建索引,否则只能暴力扫描,速度极慢。
项目结构
创建以下项目文件结构:
bash
src/
├── config.js # 统一配置:Milvus 地址、嵌入模型参数
├── client.js # MilvusClient 单例
├── embedding.js # 文本 → 向量(调用百炼 text-embedding-v4)
├── collection.js # 集合管理:创建 Schema、建索引、加载到内存
├── create.js # 增:插入数据
├── read.js # 查:向量搜索 + 标量查询
├── update.js # 改:Upsert(有则更新,无则插入)
├── delete.js # 删:按 ID / 按条件删除
└── index.js # 主入口,串联演示完整流程
连接 Milvus
js
// src/client.js
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
export const milvusClient = new MilvusClient({
address: "localhost:19530", // Docker 暴露的 gRPC 端口
database: "default",
timeout: 30000,
});
socket 连接是惰性的,只有在发起第一次请求时才真正建立。
文本向量化(Embedding)
向量数据库本身不负责把文本变成向量,这一步需要嵌入模型 完成。这里用阿里云百炼的 text-embedding-v4,输出 1024 维向量。
js
// src/embedding.js
import { OpenAIEmbeddings } from "@langchain/openai";
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.DASHSCOPE_API_KEY,
modelName: "text-embedding-v4",
dimensions: 1024,
configuration: {
baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
},
});
// 单条文本 → 向量
export async function embedText(text) {
return embeddings.embedQuery(text);
}
// 批量文本 → 向量数组
export async function embedTexts(texts) {
return embeddings.embedDocuments(texts);
}
embedQuery 接收单个字符串,将该字符串转为向量。
embedDocuments 接收字符串数组,将字符串数组转为向量数组。
创建 Collection
Collection 是数据的容器,需要先定义 Schema、建索引,最后加载到内存。
js
// src/collection.js
import { DataType, MetricType, IndexType } from "@zilliz/milvus2-sdk-node";
await milvusClient.createCollection({
collection_name: "demo_articles",
fields: [
{
name: "id",
data_type: DataType.VarChar,
is_primary_key: true,
type_params: { max_length: "64" },
},
{
name: "title",
data_type: DataType.VarChar,
type_params: { max_length: "512" },
},
{
name: "content",
data_type: DataType.VarChar,
type_params: { max_length: "65535" },
},
{
name: "embedding",
data_type: DataType.FloatVector,
type_params: { dim: "1024" },
},
],
enable_dynamic_field: true, // 允许存入未在 Schema 中声明的字段
});
// 为向量字段建索引(搜索前必须)
await milvusClient.createIndex({
collection_name: "demo_articles",
field_name: "embedding",
index_type: IndexType.IVF_FLAT, // 倒排索引,适合百万级数据
metric_type: MetricType.COSINE, // 余弦相似度
params: { nlist: 128 },
});
// 加载到内存(搜索前必须)
await milvusClient.loadCollectionSync({
collection_name: "demo_articles",
});
三步走:建表 → 建索引 → 加载。缺一不可。
增(Insert)
插入数据前,先把文本转为向量,再连同原文一起写入。
js
// src/create.js
const contents = articles.map((a) => a.content);
const embeddings = await embedTexts(contents); // 批量向量化
const rows = articles.map((article, i) => ({
id: article.id,
title: article.title,
content: article.content,
embedding: embeddings[i], // 向量字段
}));
const result = await milvusClient.insert({
collection_name: "demo_articles",
data: rows,
});
// 刷新使数据可被搜索
await milvusClient.flushSync({ collection_names: ["demo_articles"] });
关于 flush :Milvus 的数据先写内存再异步落盘。
flushSync会阻塞等待落盘完成,确保后续搜索能查到刚插入的数据。
查(Search / Query)
Milvus 提供两种"查":
向量相似度搜索(ANN Search)
把查询文本也转成向量,在向量空间找 Top-K 最近邻居。
js
// src/read.js
const queryVector = await embedText("什么是向量数据库?");
const result = await milvusClient.search({
collection_name: "demo_articles",
data: queryVector, // 查询向量
anns_field: "embedding", // 在哪个向量字段上搜索
limit: 3, // Top-K
output_fields: ["id", "title"], // 返回哪些标量字段
params: { nprobe: 16 }, // 搜索精度(越大越准但也越慢)
});
运行结果示例:
less
搜索查询: "什么是向量数据库?"
#1 [article-002] 向量数据库入门:从零开始学习 Milvus (相似度: 0.8252)
#2 [article-004] Docker 容器化部署最佳实践 (相似度: 0.3095)
标量查询(按 ID 或条件过滤)
不走向量搜索,像传统数据库一样精确查询。
js
// 按 ID 查询
await milvusClient.query({
collection_name: "demo_articles",
ids: ["article-001", "article-003"],
output_fields: ["id", "title"],
});
// 按条件过滤
await milvusClient.query({
collection_name: "demo_articles",
filter: 'id like "article-%"',
limit: 10,
});
改(Upsert)
Milvus 的更新操作是 Upsert:主键已存在则覆盖(含向量重新计算),不存在则插入。
js
// src/update.js
const vec = await embedText(newContent);
await milvusClient.upsert({
collection_name: "demo_articles",
data: [
{
id: "article-002", // 相同 ID → 覆盖旧数据
title: "新标题",
content: newContent,
embedding: vec,
},
],
});
await milvusClient.flushSync({ collection_names: ["demo_articles"] });
删(Delete)
支持按 ID 列表或按表达式删除。
js
// src/delete.js
// 按 ID 删除
await milvusClient.delete({
collection_name: "demo_articles",
ids: ["article-005"],
});
// 按表达式删除
await milvusClient.delete({
collection_name: "demo_articles",
filter: 'id == "article-004"', // 对标量字段的条件表达式
});
// 每次删除后刷新
await milvusClient.flushSync({ collection_names: ["demo_articles"] });
效果演示
在 package.json 中添加 npm scripts 命令:
json
{
"scripts": {
"start": "node src/index.js"
}
}
运行 pnpm start 命令程序会依次执行:创建集合 → 插入 5 篇文章 → 语义搜索验证 → 按 ID 查询 → Upsert 更新 → 按 ID 删除 → 按条件删除。每一步都有清晰的日志输出。
受限于篇幅,这个只截取部分执行效果:

代码已上传 github 仓库:github.com/Panda-plus5...
安装 Milvus 可视化管理工具
Milvus 可视化管理工具推荐使用 Attu ,相当于 MySQL 的 Navicat 。
使用可视化管理工具可以方便查看数据库中的数据。
可以在以下链接获取安装包:

下载后直接安装,使用默认配置连接:

连接后可以方便地查看 Entity 数据:

总结
在 AI 时代,语义搜索已成为 RAG、智能问答等应用的核心能力,而传统数据库(如 MySQL)受限于精确匹配和模糊查询,无法理解"猫"与" kitten "之间的语义关联。向量数据库(如 Milvus)正是填补这一空白------它将文本、图片等非结构化数据映射为高维向量,通过相似度计算实现"理解含义"的搜索。
掌握了上文的增删改查,你就能将 Milvus 融入实际项目。
欢迎读者点赞、收藏!