第 37 章
向量搜索
MySQL 向量搜索与 AI 集成
随着大语言模型(LLM)的爆发式增长,向量数据库成为 AI 应用的核心基础设施。MySQL 9.0 正式引入 VECTOR 数据类型,使开发者可以在熟悉的 MySQL 环境中实现语义搜索、RAG(检索增强生成)等 AI 功能,无需引入额外的向量数据库服务。
什么是向量搜索
文本/图片/音频
↓ Embedding 模型 (OpenAI, text-embedding-3, BGE...)
高维向量 [0.12, -0.34, 0.78, ..., 0.05] (通常 768~3072 维)
↓ 存入数据库
近似最近邻搜索 (ANN)
↓ 余弦相似度 / 点积 / L2 距离
语义相似的结果集
向量搜索的核心应用场景:
- 语义搜索:搜索"防晒霜"能找到"SPF 50 防紫外线面霜"
- RAG(检索增强生成):基于私有知识库回答问题
- 推荐系统:找到与用户历史行为相似的商品/内容
- 图片搜索:以图搜图
- 重复检测:找出相似文档/代码
MySQL 9.0 VECTOR 数据类型
MySQL 9.0(2024 年 7 月发布)正式引入 VECTOR(dimensions) 数据类型,用于存储固定维度的浮点向量。
-- 创建包含向量列的表(存储商品的语义向量)
CREATE TABLE products (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
description TEXT,
category VARCHAR(50),
price DECIMAL(10,2),
embedding VECTOR(1536) NOT NULL COMMENT 'OpenAI text-embedding-3-small 输出 1536 维',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
VECTOR INDEX idx_embedding (embedding) -- 向量索引(MySQL 9.0+)
) ENGINE=InnoDB;
-- 插入向量数据
-- embedding 使用 JSON 数组格式输入
INSERT INTO products (name, description, embedding)
VALUES (
'防晒霜 SPF50',
'高效防紫外线,轻薄不油腻',
STRING_TO_VECTOR('[0.12, -0.34, 0.78, ..., 0.05]') -- 1536 个浮点数
);
VECTOR 类型操作函数
-- 向量相似度计算(余弦相似度)
SELECT id, name,
VECTOR_DISTANCE(embedding, STRING_TO_VECTOR('[...]'), 'COSINE') AS distance
FROM products
ORDER BY distance ASC
LIMIT 10;
-- 向量相似度(点积,向量已归一化时等价于余弦相似度)
SELECT id, name,
DOT_PRODUCT(embedding, STRING_TO_VECTOR('[...]')) AS similarity
FROM products
ORDER BY similarity DESC
LIMIT 10;
-- 向量转换
SELECT VECTOR_TO_STRING(embedding) FROM products WHERE id = 1; -- 转回 JSON
SELECT VECTOR_DIM(embedding) FROM products WHERE id = 1; -- 查看维度 → 1536
-- 向量索引 ANN 搜索(近似最近邻)
SELECT id, name, VECTOR_DISTANCE(embedding, ?, 'COSINE') AS dist
FROM products
ORDER BY dist ASC
LIMIT 10
-- MySQL 优化器自动使用 VECTOR INDEX 进行 ANN 搜索
生成 Embedding 向量
使用 OpenAI API(Go 示例)
package main
import (
"context"
"github.com/sashabaranov/go-openai"
"database/sql"
)
func embedText(text string) ([]float32, error) {
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
resp, err := client.CreateEmbeddings(context.Background(),
openai.EmbeddingRequest{
Input: []string{text},
Model: openai.SmallEmbedding3, // text-embedding-3-small, 1536 维
})
if err != nil {
return nil, err
}
return resp.Data[0].Embedding, nil
}
func storeProduct(db *sql.DB, name, desc string) error {
// 1. 生成 embedding
vec, err := embedText(name + " " + desc)
if err != nil { return err }
// 2. 转为 JSON 数组字符串
vecJSON, _ := json.Marshal(vec)
// 3. 插入 MySQL
_, err = db.Exec(
"INSERT INTO products (name, description, embedding) VALUES (?, ?, STRING_TO_VECTOR(?))",
name, desc, string(vecJSON))
return err
}
使用本地模型(BGE-M3,中文效果好)
# 使用 Ollama 运行本地 Embedding 模型
ollama pull bge-m3
# Python 示例
import ollama
import json
def embed_text(text: str) -> list[float]:
response = ollama.embeddings(model='bge-m3', prompt=text)
return response['embedding'] # 1024 维
# 批量处理(节省 API 调用费用)
texts = ["防晒霜 SPF50", "保湿乳液", "护肤精华"]
embeddings = [embed_text(t) for t in texts]
相似度计算详解
| 方法 | 公式 | 适用场景 | MySQL 函数 |
|---|---|---|---|
| 余弦相似度 | cos(θ) = A·B / (|A||B|) | 文本语义相似度(最常用) | VECTOR_DISTANCE(a, b, 'COSINE') |
| 欧氏距离 (L2) | √∑(aᵢ-bᵢ)² | 图像特征、地理位置 | VECTOR_DISTANCE(a, b, 'EUCLIDEAN') |
| 点积 | ∑(aᵢ×bᵢ) | 向量已归一化时等价余弦 | DOT_PRODUCT(a, b) |
-- 综合示例:找到与给定文本最相似的 5 个商品
-- 先在应用层获取查询文本的 embedding,再传入 SQL
SELECT
id,
name,
description,
ROUND(1 - VECTOR_DISTANCE(embedding, ?, 'COSINE'), 4) AS similarity
FROM products
WHERE category = '护肤' -- 可以先用传统过滤缩小范围
ORDER BY VECTOR_DISTANCE(embedding, ?, 'COSINE') ASC
LIMIT 5;
RAG 架构实战
RAG(Retrieval-Augmented Generation)让 LLM 能回答私有知识库中的问题,是 AI 应用最流行的架构模式。
用户提问: "如何退货?"
↓
1. 对问题生成 Embedding
↓
2. MySQL 向量搜索 TOP-K 相关文档
↓
3. 拼接 Prompt: 上下文 + 原始问题
↓
4. 发送给 LLM (GPT-4, Claude, Qwen...)
↓
5. 返回基于知识库的答案
-- 知识库表
CREATE TABLE knowledge_base (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
source VARCHAR(200) COMMENT '来源文档',
chunk_index SMALLINT COMMENT '文档分块索引',
embedding VECTOR(1536) NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
VECTOR INDEX idx_emb (embedding)
) ENGINE=InnoDB;
// Go RAG 实现
func AnswerQuestion(db *sql.DB, userQuestion string) (string, error) {
// 1. 对用户问题生成 embedding
qEmbedding, _ := embedText(userQuestion)
qVecJSON, _ := json.Marshal(qEmbedding)
// 2. 向量搜索 Top 5 相关文档
rows, _ := db.Query(`
SELECT title, content,
ROUND(1 - VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE'), 4) AS sim
FROM knowledge_base
ORDER BY VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE') ASC
LIMIT 5`,
string(qVecJSON), string(qVecJSON))
var context strings.Builder
for rows.Next() {
var title, content string
var sim float64
rows.Scan(&title, &content, &sim)
if sim > 0.7 { // 相似度阈值过滤
context.WriteString(fmt.Sprintf("# %s\n%s\n\n", title, content))
}
}
// 3. 构建 Prompt 调用 LLM
prompt := fmt.Sprintf(`基于以下知识库内容回答问题:
%s
问题:%s
请基于以上内容给出准确答案,如果知识库中没有相关信息,请说明。`,
context.String(), userQuestion)
return callLLM(prompt)
}
混合检索(向量 + 关键词)
纯向量搜索有时会漏掉精确匹配的结果(如产品型号、人名),混合检索结合了语义搜索和关键词搜索的优势。
-- 方案:MySQL 全文索引 + 向量索引联合检索
SELECT id, name, description,
-- 归一化向量相似度分
(1 - VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE')) AS vec_score,
-- 全文搜索相关度分
MATCH(name, description) AGAINST(? IN NATURAL LANGUAGE MODE) AS ft_score,
-- 加权混合分
(1 - VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE')) * 0.7 +
MATCH(name, description) AGAINST(? IN NATURAL LANGUAGE MODE) * 0.3 AS hybrid_score
FROM products
WHERE MATCH(name, description) AGAINST(? IN BOOLEAN MODE) -- 先用 FTS 过滤
OR VECTOR_DISTANCE(embedding, STRING_TO_VECTOR(?), 'COSINE') < 0.5
ORDER BY hybrid_score DESC
LIMIT 20;
替代方案对比
| 方案 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| MySQL 9.0 VECTOR | 无需额外服务,SQL 集成 | ANN 算法较基础,大规模性能有限 | <100 万向量,已有 MySQL 基础设施 |
| pgvector (PostgreSQL) | HNSW/IVFFlat 索引,性能强 | 需要切换到 PostgreSQL | AI 原生应用,已有 PG 基础设施 |
| Milvus / Qdrant | 专用向量数据库,亿级规模 | 额外运维成本,数据同步 | 超大规模向量搜索 |
| Elasticsearch | 混合搜索(向量+关键词) | 复杂、资源消耗大 | 搜索为核心场景 |
| Redis (RedisVL) | 低延迟,适合实时推荐 | 内存成本高 | 实时推荐,热数据向量 |
MySQL 9.0 向量搜索的局限:目前(9.0)向量索引使用的是较简单的 ANN 实现,在千万级向量规模时性能不及专用向量数据库(Milvus/pgvector)。适合:中小规模(<500 万)向量,希望减少基础设施复杂度的场景。大规模场景仍建议使用 pgvector 或专用向量数据库。
实践建议:对于已在使用 MySQL 的 SaaS 产品,MySQL 9.0 的 VECTOR 类型是引入 AI 功能的最快路径:不用学新数据库,不用管理额外服务,直接在现有 MySQL 表上加 VECTOR 列即可实现语义搜索。待规模增长后,再评估是否迁移到专用向量数据库。