简介
kNN搜索
k-nearest neighbor(kNN)搜索找到与查询向量最近的k个向量,如通过相似度计算。
kNN的常见用例包括:
基于自然语言处理(NLP)算法的相关性排序
产品推荐和推荐引擎
图像或视频的相似性搜索
要运行kNN搜索,您必须能够将数据转换为有意义的向量值。您可以在Elasticsearch之外创建这些向量,并将它们作为dense_vvector字段值添加到文档中。查询表示为具有相同维度的向量。
根据相似性度设计向量,使文档的向量与查询向量越接近匹配度越高。
kNN方法:
ES支持两种kNN搜索的方法:
1、近似kNN:使用kNN搜索选项
2、精确暴力kNN:利用向量函数script_score查询
多数情况下,我们只需要使用近似kNN。近似kNN提供低延迟是以较慢的索引速度和不完美的准确性为代价。
暴力搜索必须扫描每个匹配的文档节点来计算向量函数,这将导致搜索非常慢。我们可以通过限制传给向量函数的文档数量来降低延迟。比如我们通过其他查询条件能筛选出一个很小的文档子集,那么我们就可以通过这个方法获取较好的性能。
近似kNN搜索
运行近似kNN搜索,使用kNN选项搜索一个或多个启用索引的 dense_vector 字段。
1) 显式映射一个或多个密集向量字段。近似kNN搜索需要以下映射选项:
- index字段设置为true。
similarity字段,该值确定用于基于查询和文档向量之间的相似性对文档进行评分的相似性度量方式,如l2_norm,欧氏距离等。
创建向量索引
在创建索引时需要选择dense_vector类型并指定index为true,并定义索引时文档间相似度量算法,此时es在索引文档时会为knn搜索生成新的索引文件,新的索引文件采用的是树加链表的存储结构,并根据similarity指定的相似算法计算文档间距离,特征相近的数据会存储在临近的分支里。
PUT image-index
{
"mappings": {
"properties": {
"image-vector": {
"type": "dense_vector",
"dims": 3,
"index": true,
"similarity": "l2_norm"
},
"title-vector": {
"type": "dense_vector",
"dims": 5,
"index": true,
"similarity": "l2_norm"
},
"title": {
"type": "text"
},
"file-type": {
"type": "keyword"
}
}
}
}
2)插入索引数据
POST image-index/_bulk?refresh=true
{ "index": { "_id": "1" } }
{ "image-vector": [1, 5, -20], "title-vector": [12, 50, -10, 0, 1], "title": "moose family", "file-type": "jpg" }
{ "index": { "_id": "2" } }
{ "image-vector": [42, 8, -15], "title-vector": [25, 1, 4, -12, 2], "title": "alpine lake", "file-type": "png" }
{ "index": { "_id": "3" } }
{ "image-vector": [15, 11, 23], "title-vector": [1, 5, 25, 50, 20], "title": "full moon", "file-type": "jpg" }
3)使用knn选项搜索
POST image-index/_search
{
"knn": {
"field": "image-vector",
"query_vector": [-5, 9, -12],
"k": 10,
"num_candidates": 100
},
"fields": [ "title", "file-type" ]
}

搜索结果中的_score为查询向量和文档向量之间的相似度,计算方式即为索引中指定的similarity字段。
num_candidates是检索分片时获得的候选集数量。类似于milvus的n_list。
为了收集结果,kNN搜索api在每个分片上查找一定数量(num_candidates )的近似最近邻候选对象。搜索计算候选向量与查询向量的相似度,从每个分片选择k个最相似的结果。搜索最终拿到每个分片返回的结果然后找到最终的k个邻近结果。
我们可以通过调大num_candidates的值来更精确的获取结果,代价是搜索的速度会变慢。如果使用一个比较大的num_candidates值会从每个分片获取更多的候选者。这就要花费更多的时间,也就有更大的可能找到真正的k个邻近结果。
类似的,我们可以降低num_candidates的值来获取更快的搜索,同时要接受潜在不太精确的结果。
kNN+filter搜索
POST image-index/_search
{
"knn": {
"field": "image-vector",
"query_vector": [54, 10, -2],
"k": 5,
"num_candidates": 50,
"filter": {
"term": {
"file-type": "png"
}
}
},
"fields": ["title"],
"_source": false
}
java api
依赖:
<!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/co.elastic.clients/elasticsearch-java -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.1.1</version>
</dependency>
ElasticSearchConfig
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.annotation.PostConstruct;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
impor

本文介绍了如何在Elasticsearch中实现kNN搜索,用于处理基于向量的相似度查询,如NLP相关性排序、产品推荐和图像相似性搜索。通过创建向量索引、插入数据并使用kNN选项进行搜索,可以高效地找到最接近的向量结果。此外,还展示了JavaAPI的使用方法。
最低0.47元/天 解锁文章
9964

被折叠的 条评论
为什么被折叠?



