Painless 脚本扩展
借助 Painless 脚本扩展,您可以直接在 Painless 脚本中使用 k-近邻 (k-NN) 距离函数,对 knn_vector
字段执行操作。Painless 为每个上下文设置了严格的允许函数和类列表,以确保其脚本的安全。OpenSearch 为 k-NN 评分脚本中使用的几个距离函数添加了 Painless 脚本扩展,因此您可以使用它们来自定义 k-NN 工作负载。
k-NN Painless 脚本函数入门
要使用 k-NN Painless 脚本函数,首先创建一个带有 knn_vector
字段的索引,如向量评分脚本入门中所述。创建索引并摄入一些数据后,您就可以使用 Painless 扩展了
GET my-knn-index-2/_search
{
"size": 2,
"query": {
"script_score": {
"query": {
"bool": {
"filter": {
"term": {
"color": "BLUE"
}
}
}
},
"script": {
"source": "1.0 + cosineSimilarity(params.query_value, doc[params.field])",
"params": {
"field": "my_vector",
"query_value": [9.9, 9.9]
}
}
}
}
}
field
需要映射到 knn_vector
字段,并且 query_value
必须是一个与 field
具有相同维度的浮点数组。
函数类型
下表描述了 OpenSearch 提供的 Painless 函数。
函数名称 | 函数签名 | 描述 |
---|---|---|
l2Squared | float l2Squared (float[] queryVector, doc['vector field']) | 此函数计算给定查询向量和文档向量之间 L2 距离(欧几里得距离)的平方。较短的距离表示更相关的文档,因此此示例反转了 l2Squared 函数的返回值。如果文档向量与查询向量匹配,结果为 0 ,因此此示例还在距离上加 1 ,以避免除以零错误。 |
l1Norm | float l1Norm (float[] queryVector, doc['vector field']) | 此函数计算给定查询向量和文档向量之间 L1 范数距离(曼哈顿距离)。 |
cosineSimilarity | float cosineSimilarity (float[] queryVector, doc['vector field']) | 余弦相似度是查询向量和文档向量的内积,均归一化为长度 1 。如果查询向量的幅值在整个查询过程中没有变化,您可以传递查询向量的幅值以提高性能,而不是为每个过滤文档重复计算幅值float cosineSimilarity (float[] queryVector, doc['vector field'], float normQueryVector) 通常,余弦相似度的范围是 [-1, 1]。然而,在信息检索的情况下,两个文档的余弦相似度范围是 0 到 1 ,因为 tf-idf 统计量不能为负。因此,OpenSearch 添加了 1.0 ,以便始终产生正的余弦相似度分数。 |
hamming | float hamming (float[] queryVector, doc['vector field']) | 此函数计算给定查询向量和文档向量之间的汉明距离。汉明距离是对应元素不同的位置数量。较短的距离表示更相关的文档,因此此示例反转了汉明距离的返回值。 |
OpenSearch 2.16 及更高版本支持二进制向量的 hamming
空间类型。有关更多信息,请参阅二进制 k-NN 向量。
约束
-
如果文档的
knn_vector
字段与查询的维度不同,该函数将抛出IllegalArgumentException
。 -
如果向量字段没有值,该函数将抛出
IllegalStateException
。您可以通过首先检查文档的字段中是否包含值来避免这种情况。
"source": "doc[params.field].size() == 0 ? 0 : 1 / (1 + l2Squared(params.query_value, doc[params.field]))",
由于分数只能是正数,此脚本将向量字段文档的排名高于没有向量字段的文档。
使用余弦相似度时,将零向量([0, 0, ...]
)作为输入是不合法的。这是因为此类向量的幅值为 0,这会在相应的公式中引发 除以 0
异常。包含零向量的请求将被拒绝,并抛出相应的异常。