ES支持的向量函数

 向量字段函数

向量函数的计算是把所有匹配的文档都计算一遍,因此花费的查询时间会随着匹配文档的数量线性增加。因为这个原因,我们建议通过query参数来限制匹配的文档数量

下面是可用的向量函数和向量访问方法:

  1. cosineSimilarity – 计算余弦相似性
  2. dotProduct – 计算点积
  3. l1norm – 计算曼哈顿距离
  4. l2norm - 计算欧几里德距离
  5. doc[<field>].vectorValue – 返回向量值的浮点数数组
  6. 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')"

我们最好使用cosineSimilaritydotProductl1norm 或者 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
        }
      }
    }
  }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值