搜索词转向量进行向量搜索达到语义匹配排序的效果
这个计算余弦相似度的MYSQL函数:
IF JSON_LENGTH(v1) != JSON_LENGTH(v2) THEN
RETURN NULL;
END IF;
WHILE
i < len
DO
SET sim = sim + (JSON_EXTRACT(v1, CONCAT('$[', i, ']')) * JSON_EXTRACT(v2, CONCAT('$[', i, ']')));
SET i = i + 1;
END WHILE;
RETURN sim;
END然后通过这个SQL语句搜索:
$normalizedVector = json_encode($normalizedVector);
$similarity = new Expression("COSIM(v.normalized_vector, :json)", [
':json' => $normalizedVector
]);
$query2->select(["v.id", "v.merchant_id", "v.product_id", "v.qfa_id", 'similarity' => $similarity]);
$query2->andWhere(['v.id' => $recordIds]);
$query2->orderBy(['similarity' => SORT_DESC]);
$query2->limit($n);
if ($withQfa) {
$query2->innerJoinWith('qfa as q');
$query2->andWhere('q.status=1');
}这个COSIM的函数,只是将两个json向量数组对应位置的两个数相乘后累加起来返回,为什么能达到语意搜索的效果?
COSIM 函数实际上只计算了两个 JSON 数组的点积(对应位置元素相乘后累加),而不是严格的余弦相似度(余弦相似度还需要除以两个向量的模长乘积)。但它依然能在你的场景中实现语义搜索,原因如下:
1. 语义搜索的原理:向量嵌入(Embedding)
现代语义搜索通常基于 文本嵌入(如 Word2Vec、BERT 等模型),将一段文本转换成一个高维稠密向量。这些向量的特点是:语义相近的文本,其向量在空间中的方向也相近。因此,我们可以用向量间的夹角余弦来度量相似度,即:
[
\text{cosine\_similarity}(A, B) = \frac{A \cdot B}{|A| |B|}
]
- 当两个向量方向完全一致时,余弦相似度为 1;
- 当它们正交时,为 0;
- 当方向相反时,为 -1(但嵌入向量通常非负,所以范围在 [0,1])。
2. 为什么点积能代替余弦相似度?
在代码中,查询向量使用了 $normalizedVector 这一变量名,暗示查询向量已经做过归一化处理(即 (|B| = 1))。如果存储的向量 v.normalized_vector 同样也是归一化的((|A| = 1)),那么:
[
A \cdot B = \frac{A \cdot B}{1 \times 1} = \text{cosine\_similarity}(A, B)
]
此时点积就等于余弦相似度。即使存储的向量没有归一化,只要查询向量归一化,点积仍然与余弦相似度成正比(相差一个常数因子 (|A|)),排序结果不变。因此,在你的场景下,直接计算点积已经足够得到语义相似度的排序。
3. 函数 COSIM 的作用
COSIM 函数虽然名称是余弦相似度,但实现的是点积。它逐一取出两个 JSON 数组对应位置的值相乘并累加。这个过程正是向量相似度计算的核心运算。
- 为什么能实现语义搜索?
因为该函数计算出的点积数值越大,代表两个向量在方向上越接近,从而语义上越相关。配合ORDER BY similarity DESC,就能将最相关的记录排在前面。
4. 注意事项
- 如果向量没有归一化,点积会受到向量长度影响,可能导致长度大的向量获得更高的分数,从而影响排序。此时应改用完整的余弦相似度公式:
[
\frac{A \cdot B}{\sqrt{\sum A_i^2} \times \sqrt{\sum B_i^2}}
]
其中分母部分可以通过预先存储向量的模长(或计算平方和)来优化。 - 你的函数未考虑向量长度不等的情况(已返回
NULL),这保证了输入向量的维度一致。 性能方面:该函数使用循环逐元素相乘,当向量维度较高(如 512 维或更高)时,每次查询都会对每条记录执行循环,效率较低。在生产环境中,建议:
- 使用数据库的向量扩展(如 MySQL 8.0.31 后的
VECTOR类型 + 向量函数); - 或将向量存储到专门支持向量检索的数据库(如 Milvus、Pgvector、Elasticsearch 等);
- 或利用近似最近邻(ANN)算法加速检索。
- 使用数据库的向量扩展(如 MySQL 8.0.31 后的
总结
COSIM 函数虽然只计算了点积,但因为查询向量已经归一化(且假设存储向量也归一化),它等价于余弦相似度,因此能够正确反映两个文本向量的语义相关性。这正是语义搜索能够“按意思”排序的核心数学基础。
版权属于:Joyber
本文链接:https://blog.qqvbc.com/default/1444.html
转载时须注明出处及本声明