使用评分脚本的精确 k-NN 搜索
您可以使用评分脚本进行精确 k-最近邻 (k-NN) 搜索,以找到给定查询点的精确 k-最近邻。使用 k-NN 评分脚本,您可以在执行最近邻搜索之前对索引应用过滤器。这对于动态搜索用例非常有用,因为索引主体可能会根据其他条件而变化。
由于评分脚本方法执行的是暴力搜索,因此其扩展效率不如近似方法。在某些情况下,最好考虑重构工作流或索引结构,以使用近似方法而不是评分脚本方法。
开始使用向量的评分脚本
与近似最近邻 (ANN) 搜索类似,要对向量主体使用评分脚本,您必须首先创建一个包含一个或多个 knn_vector
字段的索引。
如果您只打算使用评分脚本方法(而不使用近似方法),您可以将 index.knn
设置为 false
,并且不设置 index.knn.space_type
。您可以在搜索时选择空间类型。有关 k-NN 评分脚本支持的空间,请参阅空间。
此示例创建一个包含两个 knn_vector
字段的索引
PUT my-knn-index-1
{
"mappings": {
"properties": {
"my_vector1": {
"type": "knn_vector",
"dimension": 2
},
"my_vector2": {
"type": "knn_vector",
"dimension": 4
}
}
}
}
如果您*只*想使用评分脚本,可以省略 "index.knn": true
。这种方法可以加快索引速度并降低内存使用量,但您将失去在索引上运行标准 k-NN 查询的能力。
创建索引后,您可以向其中添加一些数据
POST _bulk
{ "index": { "_index": "my-knn-index-1", "_id": "1" } }
{ "my_vector1": [1.5, 2.5], "price": 12.2 }
{ "index": { "_index": "my-knn-index-1", "_id": "2" } }
{ "my_vector1": [2.5, 3.5], "price": 7.1 }
{ "index": { "_index": "my-knn-index-1", "_id": "3" } }
{ "my_vector1": [3.5, 4.5], "price": 12.9 }
{ "index": { "_index": "my-knn-index-1", "_id": "4" } }
{ "my_vector1": [5.5, 6.5], "price": 1.2 }
{ "index": { "_index": "my-knn-index-1", "_id": "5" } }
{ "my_vector1": [4.5, 5.5], "price": 3.7 }
{ "index": { "_index": "my-knn-index-1", "_id": "6" } }
{ "my_vector2": [1.5, 5.5, 4.5, 6.4], "price": 10.3 }
{ "index": { "_index": "my-knn-index-1", "_id": "7" } }
{ "my_vector2": [2.5, 3.5, 5.6, 6.7], "price": 5.5 }
{ "index": { "_index": "my-knn-index-1", "_id": "8" } }
{ "my_vector2": [4.5, 5.5, 6.7, 3.7], "price": 4.4 }
{ "index": { "_index": "my-knn-index-1", "_id": "9" } }
{ "my_vector2": [1.5, 5.5, 4.5, 6.4], "price": 8.9 }
最后,您可以使用 knn
脚本对数据运行精确最近邻搜索
GET my-knn-index-1/_search
{
"size": 4,
"query": {
"script_score": {
"query": {
"match_all": {}
},
"script": {
"source": "knn_score",
"lang": "knn",
"params": {
"field": "my_vector2",
"query_value": [2.0, 3.0, 5.0, 6.0],
"space_type": "cosinesimil"
}
}
}
}
}
所有参数都是必需的。
lang
是脚本类型。此值通常是painless
,但此处您必须指定knn
。-
source
是脚本的名称,即knn_score
。此脚本是 k-NN 插件的一部分,在标准
_scripts
路径下不可用。对_cluster/state/metadata
的 GET 请求也不会返回它。 field
是包含向量数据的字段。query_value
是您要查找最近邻的点。对于欧几里得和余弦相似度空间,该值必须是与字段映射中设置的维度匹配的浮点数组。对于汉明位距离,该值可以是带符号长整型或 base64 编码字符串(分别用于 long 和 binary 字段类型)。space_type
对应于距离函数。有关更多信息,请参阅空间。
近似方法中的后置过滤示例显示了一个返回少于 k
个结果的搜索。如果您想避免这种情况,评分脚本方法允许您实质上颠倒事件的顺序。换句话说,您可以在执行 k-NN 搜索之前过滤文档集。
此示例展示了使用评分脚本方法进行 k-NN 搜索的预过滤方法。首先,创建索引
PUT my-knn-index-2
{
"mappings": {
"properties": {
"my_vector": {
"type": "knn_vector",
"dimension": 2
},
"color": {
"type": "keyword"
}
}
}
}
然后添加一些文档
POST _bulk
{ "index": { "_index": "my-knn-index-2", "_id": "1" } }
{ "my_vector": [1, 1], "color" : "RED" }
{ "index": { "_index": "my-knn-index-2", "_id": "2" } }
{ "my_vector": [2, 2], "color" : "RED" }
{ "index": { "_index": "my-knn-index-2", "_id": "3" } }
{ "my_vector": [3, 3], "color" : "RED" }
{ "index": { "_index": "my-knn-index-2", "_id": "4" } }
{ "my_vector": [10, 10], "color" : "BLUE" }
{ "index": { "_index": "my-knn-index-2", "_id": "5" } }
{ "my_vector": [20, 20], "color" : "BLUE" }
{ "index": { "_index": "my-knn-index-2", "_id": "6" } }
{ "my_vector": [30, 30], "color" : "BLUE" }
最后,使用 script_score
查询在识别最近邻之前预过滤您的文档
GET my-knn-index-2/_search
{
"size": 2,
"query": {
"script_score": {
"query": {
"bool": {
"filter": {
"term": {
"color": "BLUE"
}
}
}
},
"script": {
"lang": "knn",
"source": "knn_score",
"params": {
"field": "my_vector",
"query_value": [9.9, 9.9],
"space_type": "l2"
}
}
}
}
}
开始使用二进制数据的评分脚本
k-NN 评分脚本还允许您使用汉明距离空间对二进制数据运行 k-NN 搜索。为了使用汉明距离,相关字段必须是 binary
或 long
字段类型。如果您使用 binary
类型,数据必须是 base64 编码字符串。
此示例展示了如何使用汉明距离空间和 binary
字段类型
PUT my-index
{
"mappings": {
"properties": {
"my_binary": {
"type": "binary",
"doc_values": true
},
"color": {
"type": "keyword"
}
}
}
}
然后添加一些文档
POST _bulk
{ "index": { "_index": "my-index", "_id": "1" } }
{ "my_binary": "SGVsbG8gV29ybGQh", "color" : "RED" }
{ "index": { "_index": "my-index", "_id": "2" } }
{ "my_binary": "ay1OTiBjdXN0b20gc2NvcmluZyE=", "color" : "RED" }
{ "index": { "_index": "my-index", "_id": "3" } }
{ "my_binary": "V2VsY29tZSB0byBrLU5O", "color" : "RED" }
{ "index": { "_index": "my-index", "_id": "4" } }
{ "my_binary": "SSBob3BlIHRoaXMgaXMgaGVscGZ1bA==", "color" : "BLUE" }
{ "index": { "_index": "my-index", "_id": "5" } }
{ "my_binary": "QSBjb3VwbGUgbW9yZSBkb2NzLi4u", "color" : "BLUE" }
{ "index": { "_index": "my-index", "_id": "6" } }
{ "my_binary": "TGFzdCBvbmUh", "color" : "BLUE" }
最后,使用 script_score
查询在识别最近邻之前预过滤您的文档
GET my-index/_search
{
"size": 2,
"query": {
"script_score": {
"query": {
"bool": {
"filter": {
"term": {
"color": "BLUE"
}
}
}
},
"script": {
"lang": "knn",
"source": "knn_score",
"params": {
"field": "my_binary",
"query_value": "U29tZXRoaW5nIEltIGxvb2tpbmcgZm9y",
"space_type": "hammingbit"
}
}
}
}
}
同样,您可以使用 long
字段对数据进行编码并运行搜索
GET my-long-index/_search
{
"size": 2,
"query": {
"script_score": {
"query": {
"bool": {
"filter": {
"term": {
"color": "BLUE"
}
}
}
},
"script": {
"lang": "knn",
"source": "knn_score",
"params": {
"field": "my_long",
"query_value": 23,
"space_type": "hammingbit"
}
}
}
}
}