从「关键词匹配」到「语义理解」:我是如何用 Embedding 让搜索「听懂人话」的?

大家好,我是掘金的一位创作者FogLetter。今天想和大家聊聊一个看似枯燥、实则非常有趣的技术------Embedding 向量化搜索

如果你也曾经为「搜索功能不够智能」而头疼,或者好奇为什么现在的搜索引擎能「猜」到你想要什么,那么这篇笔记一定会让你有所收获。


一、从「机械匹配」到「语义理解」的进化

还记得早期的搜索功能吗?用户输入「React TailwindCSS」,系统只会机械地匹配包含这两个词的标题。如果一篇文章标题是《使用 Next.js 和 Tailwind CSS 构建博客》,尽管内容高度相关,仅仅因为没有出现「React」这个词,就会被系统无情地过滤掉。

这就是传统关键词匹配的局限性------它不懂语义,只认识字面。

而现代的语义搜索,已经能够理解「React」和「Next.js」的关联,知道「TailwindCSS」是一种 CSS 框架。即使标题中没有完全匹配的关键词,只要内容语义相关,就能被找出来。

这背后的魔法,就是 Embedding。


二、Embedding:把文字变成向量的「翻译官」

什么是 Embedding?

简单来说,Embedding 是一种将文本(词、句子、段落)转换成高维向量的技术。这个向量,可以理解为文本在数学空间中的「坐标」。

我用的是 OpenAI 的 text-embedding-ada-002 模型,它会将任何文本转换成 1536 维的向量。是的,1536 个数字代表一段文本!

为什么需要向量化?

因为计算机不理解文字,但理解数字。通过把文本转换成向量,我们就能用数学方法计算文本之间的相似度。

javascript 复制代码
// 把文本变成向量
const res = await client.embeddings.create({
    model: 'text-embedding-ada-002',
    input: 'React,TailwindCSS'
});
const { embedding } = res.data[0]; // 得到1536维的向量

现在,「React」不再只是6个字母,而是1536个数字组成的数学表示。更重要的是,语义相似的文本,它们的向量在空间中的位置也很接近。


三、余弦相似度:衡量「心灵相通」的数学公式

有了向量,如何判断两段文本是否相似呢?这就需要余弦相似度出场了。

余弦相似度通过计算两个向量之间的夹角余弦值,来判断它们的相似程度。值越接近1,说明越相似;越接近0,说明越不相关。

javascript 复制代码
// 计算余弦相似度
export const cosineSimilarity = (v1, v2) => {
    const dotProduct = v1.reduce((acc, curr, i) => acc + curr * v2[i], 0);
    const lengthV1 = Math.sqrt(v1.reduce((acc, curr) => acc + curr * curr, 0));
    const lengthV2 = Math.sqrt(v2.reduce((acc, curr) => acc + curr * curr, 0));
    return dotProduct / (lengthV1 * lengthV2);
};

这个公式的美妙之处在于,它不受向量长度影响,只关注方向。就像比较两个人的思维方式是否相似,而不在乎他们思考的深度。


四、实战:构建智能搜索系统

第一步:建立向量数据库

首先,我需要把所有文章的标题和分类都转换成向量,建立自己的「向量数据库」:

javascript 复制代码
const postsWithEmbedding = [];

for (const { title, category } of posts) {
    const res = await client.embeddings.create({
        model: 'text-embedding-ada-002',
        input: `标题:${title}; 分类:${category}`
    });
    postsWithEmbedding.push({
        title,
        category,
        embedding: res.data[0].embedding
    });
}

// 保存到文件,避免重复计算
await fs.writeFile('./data/posts_with_embedding.json', 
    JSON.stringify(postsWithEmbedding, null, 2));

这个过程虽然耗时,但一劳永逸。建立好的向量数据库可以反复使用。

第二步:实时语义搜索

当用户输入查询时:

javascript 复制代码
// 1. 把查询词转换成向量
const query = 'react,tailwindcss';
const res = await client.embeddings.create({
    model: 'text-embedding-ada-002',
    input: query
});
const { embedding } = res.data[0];

// 2. 与数据库中所有向量计算相似度
const results = posts.map(item => ({
    ...item,
    similarity: cosineSimilarity(embedding, item.embedding)
}))
// 3. 按相似度排序,取前3名
.sort((a, b) => a.similarity - b.similarity)
.reverse()
.slice(0, 3);

console.log(`与「${query}」最相关的内容:`);
results.forEach((item, index) => {
    console.log(`${index + 1}. ${item.title}, ${item.category}`);
});

五、效果对比:传统搜索 vs 语义搜索

让我用实际数据展示两者的差异:

传统关键词搜索「react,tailwindcss」可能返回:

  1. 《如何在 React 中使用 Tailwind CSS 实现 Material Design 风格》
  2. 《使用 Next.js 和 Tailwind CSS 构建一个简单的博客应用》

语义搜索「react,tailwindcss」返回:

  1. 《如何在 React 中使用 Tailwind CSS 实现 Material Design 风格》
  2. 《使用 Next.js 和 Tailwind CSS 构建一个简单的博客应用》
  3. 《使用 Tailwind CSS 和 Alpine.js 构建一个简单的交互式表单》
  4. 《如何使用 Vue.js 和 Tailwind CSS 创建响应式布局》

看到区别了吗?语义搜索找到了更多相关的内容,即使它们没有完全包含查询关键词。


六、为什么这很重要?创作角度的思考

作为内容创作者,我深刻理解读者找不到相关内容的痛苦。很多时候,读者并不知道准确的关键词,他们只能用自己的语言描述需求。

语义搜索的价值在于:

  • 理解用户意图:即使查询不准确,也能找到相关内容
  • 发现隐性关联:识别内容之间的深层联系
  • 提升用户体验:减少「搜索结果为空」的挫败感

这就像有一个懂技术的朋友在帮你找资料,他理解你的需求,而不只是机械地匹配关键词。


七、进阶思考:向量的奇妙特性

Embedding 最神奇的地方不止于相似度计算。由于向量在空间中具有数学关系,我们还可以做很多有趣的事情:

  1. 词义推理国王 - 男人 + 女人 ≈ 女王
  2. 主题聚类:通过向量距离自动给文章分类
  3. 内容推荐:找到语义相似的文章推荐给读者

这些能力,让搜索从「工具」变成了「智能助手」。


八、性能考量:大数据下的优化

你可能会问:每次搜索都要和所有向量计算相似度,性能不会很差吗?

确实,如果数据量很大,需要优化策略:

  • 使用专业的向量数据库(如 Pinecone、Chroma、Supabase)
  • 采用近似最近邻搜索算法
  • 对向量进行索引和分片

但对于大多数应用场景,几千到几万条数据的情况下,直接计算是完全可行的。


结语:技术的温度

技术本身是冰冷的,但当我们用它来解决真实问题时,它就变得有温度了。

通过 Embedding 和语义搜索,我让我的博客、我的项目能够更好地理解读者和用户的需求。这种「被理解」的体验,正是技术最有价值的地方。

下次当你实现搜索功能时,不妨考虑一下:是继续做机械的关键词匹配,还是升级到能够「听懂人话」的语义搜索?

毕竟,在这个信息过载的时代,帮助用户快速找到他们真正需要的内容,就是我们作为开发者能够提供的最好的用户体验。

相关推荐
修己xj4 小时前
告别手动画图:用自然语言生成可直接发布的 SVG+PNG 技术图
aigc
橙子家5 小时前
浏览器缓存之【基础键值存储】:Local storage 和 Session storage
前端
星星在线7 小时前
MusicFree:一个「All in One」的个人音乐服务器,让听歌回归简单
前端·后端
IT_陈寒8 小时前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x8 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者9 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
用户51914958484510 小时前
Windows 渗透测试载荷加载器 POC 工具集
人工智能·aigc
袋鱼不重10 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
Fireworks10 小时前
深入vue3源码解读 -- 1、响应式的基础概念
前端
程序员黑豆10 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程