⚡ 点积相似度(Dot Product)完整可视化

📌 学习目标: 深入理解点积的计算原理、几何意义,以及它如何同时考虑向量的方向和长度。

1点积的基本概念

数学定义

代数定义:
dot_product(A, B) = Σ(Aᵢ × Bᵢ)

展开形式:
A · B = A₀×B₀ + A₁×B₁ + A₂×B₂ + ... + A₇₆₇×B₇₆₇

几何定义:
A · B = ||A|| × ||B|| × cos(θ)

其中:
• ||A|| = 向量 A 的长度(模长)
• ||B|| = 向量 B 的长度(模长)
• θ = 向量 A 和 B 之间的夹角
核心特点:
  • 点积 = 方向 × 长度 的综合度量
  • 值域:(-∞, +∞),可正可负可为零
  • 计算效率最高(只需乘加运算,无需开方)
  • 正值 → 方向相近;负值 → 方向相反;零 → 垂直

点积 > 0

向量方向相近
(夹角 < 90°)

相似

点积 = 0

向量正交
(夹角 = 90°)

无关

点积 < 0

向量方向相反
(夹角 > 90°)

相反

22D 空间几何理解

说明:点积可以理解为一个向量在另一个向量方向上的投影长度乘以该向量的长度

2D 示例计算

向量 A = (3, 4) ||A|| = 5
向量 B = (4, 3) ||B|| = 5
向量 C = (-3, 4) ||C|| = 5

A · B = 3×4 + 4×3 = 12 + 12 = 24 (正值,方向相近)
A · C = 3×(-3) + 4×4 = -9 + 16 = 7 (正值,夹角小于90°)
B · C = 4×(-3) + 3×4 = -12 + 12 = 0 (零,正交!)

几何验证:
A · B = ||A|| × ||B|| × cos(θ)
     = 5 × 5 × cos(16.26°)
     = 25 × 0.96
     ≈ 24 ✓

3点积的几何意义:投影

投影公式:
A · B = ||A|| × (B 在 A 方向上的投影长度)
     = ||B|| × (A 在 B 方向上的投影长度)

理解:点积衡量的是两个向量在同一方向上的"重合程度"

43D 空间点积可视化

3D 示例计算

向量 A = (1, 2, 3)
向量 B = (4, 5, 6)

A · B = 1×4 + 2×5 + 3×6
     = 4 + 10 + 18
     = 32

5768 维向量的点积计算

以 GTE 模型生成的 768 维向量为例,展示前 5 个维度的计算过程:
维度 i vec1[i]
(句子1)
vec2[i]
(句子2)
乘积
Aᵢ × Bᵢ
累加和
完整计算(768 维):

6Java 代码实现

/**
 * 计算点积(内积)
 *
 * @param vec1 向量1 (768维)
 * @param vec2 向量2 (768维)
 * @return 点积值 (范围: (-∞, +∞))
 */
public static double dotProduct(float[] vec1, float[] vec2) {
    if (vec1.length != vec2.length) {
        throw new IllegalArgumentException("向量维度不匹配");
    }

    double result = 0.0;

    // 遍历所有维度(768维)- 最简单高效的计算
    for (int i = 0; i < vec1.length; i++) {
        result += vec1[i] * vec2[i];  // 只需乘法和加法
    }

    return result;
}

/**
 * 点积与余弦相似度的关系
 * cosine = dotProduct / (||A|| × ||B||)
 */
public static double cosineSimilarityFromDotProduct(float[] vec1, float[] vec2) {
    double dot = dotProduct(vec1, vec2);
    double norm1 = Math.sqrt(dotProduct(vec1, vec1));  // ||A|| = √(A·A)
    double norm2 = Math.sqrt(dotProduct(vec2, vec2));  // ||B|| = √(B·B)

    return dot / (norm1 * norm2);
}

/**
 * 对于归一化向量,点积就等于余弦相似度
 * 因为 ||A|| = ||B|| = 1
 */
public static double dotProductNormalized(float[] vec1, float[] vec2) {
    // 假设向量已经归一化
    // 此时 dot(A, B) = ||A|| × ||B|| × cos(θ) = 1 × 1 × cos(θ) = cos(θ)
    return dotProduct(vec1, vec2);
}

/**
 * 使用 SIMD 优化的点积(性能优化版本)
 * 实际生产中可以使用 Java Vector API (JDK 16+)
 */
public static double dotProductOptimized(float[] vec1, float[] vec2) {
    double sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0;  // 4路并行累加

    int i = 0;
    int limit = vec1.length - 3;

    // 循环展开,利用 CPU 流水线
    for (; i < limit; i += 4) {
        sum0 += vec1[i] * vec2[i];
        sum1 += vec1[i+1] * vec2[i+1];
        sum2 += vec1[i+2] * vec2[i+2];
        sum3 += vec1[i+3] * vec2[i+3];
    }

    // 处理剩余元素
    for (; i < vec1.length; i++) {
        sum0 += vec1[i] * vec2[i];
    }

    return sum0 + sum1 + sum2 + sum3;
}

7点积矩阵热力图

说明:计算所有句子两两之间的点积值。注意点积可以是负数!
热力图解读:
  • 颜色越,点积越大(方向相近且/或长度大)
  • 颜色越,点积越小或为负(方向相反或正交)
  • 对角线值通常最大(自己与自己的点积 = ||A||²)

8三种度量方式对比

对比维度 点积 (Dot Product) 余弦相似度 (Cosine) 欧氏距离 (Euclidean)
公式 Σ(Aᵢ × Bᵢ) (A · B) / (||A|| × ||B||) √(Σ(Aᵢ - Bᵢ)²)
值域 (-∞, +∞) [-1, 1] [0, +∞)
考虑因素 方向 + 长度 仅方向 绝对位置差异
计算复杂度 O(n) - 最简单 O(n) - 需要额外计算模长 O(n) - 需要开方
归一化向量 点积 = 余弦相似度 与点积相同 d² = 2 - 2×cosine
优点 • 计算最快
• 同时考虑方向和长度
• 适合推荐系统
• 不受长度影响
• 值域有界
• 适合文本检索
• 直观易懂
• 绝对距离
• 适合聚类
缺点 • 值域无界
• 受长度影响大
• 不同量纲难比较
• 忽略向量大小
• 计算稍慢
• 受长度影响
• 维度诅咒
ES 配置 similarity: "dot_product" similarity: "cosine" similarity: "l2_norm"

9点积的重要性质

关键性质

1. 自身点积 = 模长平方
A · A = ||A||²

2. 交换律
A · B = B · A

3. 分配律
A · (B + C) = A · B + A · C

4. 与余弦相似度的关系
cos(θ) = (A · B) / (||A|| × ||B||)

5. 归一化向量的特殊性
若 ||A|| = ||B|| = 1,则:
A · B = cos(θ) ∈ [-1, 1]

10点积的应用场景

场景 推荐度量 原因
推荐系统(用户-物品) ✅ 点积 用户偏好强度和物品特征强度都重要
归一化后的语义检索 ✅ 点积 等价于余弦相似度,但计算更快
Maximum Inner Product Search (MIPS) ✅ 点积 专门针对点积优化的检索算法
注意力机制 (Attention) ✅ 点积 Transformer 中 Q·K 使用点积
文本语义检索(未归一化) ✅ 余弦相似度 文档长度不应影响相似度
聚类分析 ✅ 欧氏距离 需要绝对距离度量
💡 最佳实践:
  1. 高性能场景:先归一化向量,然后使用点积(等价于余弦,但更快)
  2. 推荐系统:直接使用点积,因为向量大小有意义
  3. 文本检索:如果向量未归一化,用余弦相似度;已归一化用点积
  4. Elasticsearch:对于归一化向量,使用 dot_productcosine 更快

11在 Elasticsearch 中使用点积

⚠️ 重要提示: 在 Elasticsearch 中使用 dot_product 时,必须先将向量归一化! 否则点积值可能超出预期范围,影响评分。
// 1. 创建索引时指定 similarity 为 dot_product
PUT /my_index
{
  "mappings": {
    "properties": {
      "title_vector": {
        "type": "dense_vector",
        "dims": 768,
        "index": true,
        "similarity": "dot_product"  ← 使用点积
      }
    }
  }
}

// 2. 索引文档时,必须使用归一化的向量!
POST /my_index/_doc
{
  "title": "Java 教程",
  "title_vector": [0.1, 0.2, ...]  // 归一化后的 768 维向量
}

// 3. kNN 搜索
POST /my_index/_search
{
  "knn": {
    "field": "title_vector",
    "query_vector": [0.1, 0.2, ...],  // 同样需要归一化!
    "k": 10,
    "num_candidates": 100
  }
}

// Elasticsearch 的评分转换:
// 对于归一化向量,点积范围是 [-1, 1]
// ES 将其转换为:score = (1 + dot_product) / 2
// 这样评分范围变成 [0, 1]
性能对比(归一化向量):
度量方式 计算操作 相对速度
dot_product n 次乘法 + (n-1) 次加法 ⚡ 最快
cosine 3n 次乘法 + 3(n-1) 次加法 + 2 次开方 + 1 次除法 中等
l2_norm n 次减法 + n 次乘法 + (n-1) 次加法 + 1 次开方 中等

12总结:三种度量的关系

数学关系总结

对于任意向量:
cos(θ) = (A · B) / (||A|| × ||B||)

对于归一化向量(||A|| = ||B|| = 1):
A · B = cos(θ)
d²(A, B) = ||A||² + ||B||² - 2(A · B) = 2 - 2cos(θ)

结论:
归一化后,三种度量本质上是等价的,只是表达形式不同!
• 点积:[-1, 1],越大越相似
• 余弦:[-1, 1],越大越相似
• 欧氏距离:[0, √2],越小越相似
🎯 最终建议:
  1. 始终对向量进行 L2 归一化
  2. 归一化后,优先使用 dot_product,计算最快
  3. 如果向量未归一化且不想归一化,使用 cosine
  4. 需要绝对距离度量时,使用 l2_norm