Link Search Menu Expand Document Documentation Menu

使用评分脚本的精确 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 搜索。为了使用汉明距离,相关字段必须是 binarylong 字段类型。如果您使用 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"
        }
      }
    }
  }
}


相关文章

剩余 350 字符

有问题?

想做贡献?