?向量字段函数
向量函数的计算是把所有匹配的文档都计算一遍,因此花费的查询时间会随着匹配文档的数量线性增加。因为这个原因,我们建议通过query参数来限制匹配的文档数量
下面是可用的向量函数和向量访问方法:
cosineSimilarity ?– 计算余弦相似性dotProduct ?– 计算点积l1norm ?– 计算曼哈顿距离l2norm ?- 计算欧几里德距离doc[<field>].vectorValue ?– 返回向量值的浮点数数组doc[<field>].magnitude ?– 返回向量的大小
我们现在创建一个dense_vector的索引并插入几个文档进去:
PUT my-index-000001
{
"mappings": {
"properties": {
"my_dense_vector": {
"type": "dense_vector",
"dims": 3
},
"status" : {
"type" : "keyword"
}
}
}
}
PUT my-index-000001/_doc/1
{
"my_dense_vector": [0.5, 10, 6],
"status" : "published"
}
PUT my-index-000001/_doc/2
{
"my_dense_vector": [-0.5, 10, 10],
"status" : "published"
}
POST my-index-000001/_refresh
使用余弦相似性进行计算:
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": "cosineSimilarity(params.query_vector, 'my_dense_vector') + 1.0",
"params": {
"query_vector": [4, 3.4, -0.2]
}
}
}
}
}
说明:
1、通过使用filter来限制脚本计算的文档数量
2、余弦相似性计算结果 加 1.0是为了防止计算的得分变成负数
3、通过把查询向量当做脚本的参数来优化脚本
备注:如果文档的向量字段存储的向量的维度与查询向量的维度不一致,则会出现异常。
使用点积进行计算:
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": """
double value = dotProduct(params.query_vector, 'my_dense_vector');
return sigmoid(1, Math.E, -value);
""",
"params": {
"query_vector": [4, 3.4, -0.2]
}
}
}
}
}
备注:使用?sigmoid函数来防止文档得分变成负数
使用l1norm进行计算:
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": "1 / (1 + l1norm(params.queryVector, 'my_dense_vector'))",
"params": {
"queryVector": [4, 3.4, -0.2]
}
}
}
}
}
备注:与余弦相似性代表相似性不同,l1norm ?和l2norm代表的是距离或者不同,这意味着,越相似的向量,通过l1norm ?和l2norm函数计算之后得到的评分越低,因此为了让越相似的向量评分越高,我们需要对l1norm ?和l2norm函数的结果求倒数。为了避免文档与查询向量完全匹配出现零的情况,我们在分母上面加1.
使用l2norm进行计算:
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": "1 / (1 + l2norm(params.queryVector, 'my_dense_vector'))",
"params": {
"queryVector": [4, 3.4, -0.2]
}
}
}
}
}
备注:当文档的向量字段没有值的时候,向量计算函数在计算时会报错。
我们可以通过检查文档的向量字段的大小来判断是否需要进行计算,例如:
"source": "doc['my_vector'].size() == 0 ? 0 : cosineSimilarity(params.queryVector, 'my_vector')"
我们最好使用cosineSimilarity ,?dotProduct ,?l1norm ?或者?l2norm 函数来计算向量。如果想自定义计算,我们也可以通过下面的函数来访问向量的值:
doc[<field>].vectorValue ?doc[<field>].magnitude
样例:下面的脚本利用这两个函数来计算余弦相似度:
GET my-index-000001/_search
{
"query": {
"script_score": {
"query" : {
"bool" : {
"filter" : {
"term" : {
"status" : "published"
}
}
}
},
"script": {
"source": """
float[] v = doc['my_dense_vector'].vectorValue;
float vm = doc['my_dense_vector'].magnitude;
float dotProduct = 0;
for (int i = 0; i < v.length; i++) {
dotProduct += v[i] * params.queryVector[i];
}
return dotProduct / (vm * (float) params.queryVectorMag);
""",
"params": {
"queryVector": [4, 3.4, -0.2],
"queryVectorMag": 5.25357
}
}
}
}
}
|