1.创建LSH模型
给定矢量样本,创建局部敏感散列(LSH)模型并将其存储为Elasticsearch文档。
POST :9200/_aknn_create
{
“_index”: “aknn_models”,
“_type”: “aknn_model”,
“_id”: “twitter_image_search”,
“_source”: {
“_aknn_description”: “LSH model for Twitter image similarity search”,
“_aknn_nb_tables”: 64,
“_aknn_nb_bits_per_table”: 18,
“_aknn_nb_dimensions”: 1000
},
“_aknn_vector_sample”: [
# Provide a sample of 2 * _aknn_nb_tables * _aknn_nb_bits_per_table vectors
[0.11, 0.22, …],
[0.22, 0.33, …],
…
[0.88, 0.99, …]
]
}
返回:
{ “took”: }
2.索引新向量
给定一批新向量,使用预定义的LSH模型对每个向量进行散列,并将其原始值和散列值存储在Elasticsearch文档中。
POST :9200/_aknn_index
{
“_index”: “twitter_images”,
“_type”: “twitter_image”,
“_aknn_uri”: “aknn_models/aknn_model/twitter_image_search”
“_aknn_docs”: [
{
“_id”: 1,
“_source”: {
“_aknn_vector”: [0.12, 0.23, …],
# Any other fields you want...
}
}, ...
]
}
返回:
{ “took”: , “size”: }
3.相似性搜索
给定索引中的向量,搜索并返回其最近邻居。
GET :9200/twitter_images/twitter_image/1/_aknn_search?k1=1000&k2=10
返回:
{
“took”: ,
“timed_out”: false,
"hits": {
"max_score": 0,
"total": <number of hits returned, up to k2>,
"hits": [
{
"_id": "...",
'_index': "twitter_images",
"_score": <euclidean distance from query vector to this vector>,
'_source': {
# All of the document fields except for the potentially
# large fields containing the vector and hashes.
}
}, ...
]
}
}
4.履行
关于实施的关键事项是:
EsAknn完全在现有的Elasticsearch集群/节点中运行。它作为一组HTTP端点处理程序有效运行,并通过Java Client API与Elasticsearch进行对话。
搜索可以并行运行。可以使用循环策略并行地在多个节点上索引新向量。单个节点上的并行索引尚未经过广泛测试。
EsAknn使用Locality Sensitive Hashing 将浮点向量转换为离散表示,可以在Elasticsearch中对其进行有效索引和检索。
EsAknn将LSH模型和向量存储为标准文档。
EsAknn使用Bool查询k1根据离散哈希 查找近似最近邻居。然后计算到这些近似邻居的确切距离并返回k2最近的邻居。例如,您可以设置k1 = 1000和k2 = 10。
EsAknn目前仅实现欧几里德距离,但可以添加与LSH兼容的任何距离函数。
5.性能速度
EsAknn的速度通常表征为:
创建一个新的LSH模型:<1分钟。
索引新向量:每秒数百到数千。
搜索向量的邻居:<500毫秒。搜索时间与语料库的大小呈线性关系。
语料库与搜索时间通常遵循如下的子线性模式:
除此之外,速度是以下因素的函数:
向量的维度。
LSH模型中的表(也称为散列函数或树)的数量。
LSH模型中哈希值的位数。
检索到的近似邻居数量,k1。
返回的确切邻居数量,k2。
在图像相似性搜索引擎中,您可以看到针对670万个1000维向量的索引的搜索很少超过200毫秒。
6.召回
Recall定义为为搜索返回的真实最近邻居的比例,可以在各种值下进行评估k2。例如,如果您知道您的应用程序需要检索前十个最相似的项目,那么您应该评估召回时间k2=10。
与速度类似,召回取决于LSH配置。增加k1 通常是增加召回的最简单方法,但表和位的数量也起着重要作用。找到最大化调用和最小化搜索时间的配置可以被认为是超参数优化的一种形式。
下图表明,可以在各种语料库大小中找到具有高召回率和低搜索时间的配置。绘制的点代表召回/搜索时间的“前沿”。也就是说,我在许多配置上运行基准测试,并选择具有最低中值搜索时间的配置,用于三个语料库大小的每次中值调用。
下表显示了每个语料库大小,中位数回忆,中位数搜索时间和中位数回忆的组合的最佳配置> = 0.5。
语料库大小 医学。召回 医学。搜索时间 K1 _aknn_nb_tables _aknn_nb_bits_per_table
0 百万 1 191 500 200 12
1 百万 0.9 100 500 100 14
2 百万 0.8 62 1000 50 16
3 百万 0.7 49 500 50 16
4 百万 0.6 43 250 50 16
五 百万 0.5 50 250 50 19
6 100000 1 26 250 100 12
7 100000 0.9 21 500 50 14
8 100000 0.8 14 250 50 18
9 100000 0.7 11 100 50 14
10 100000 0.6 11 100 50 19
11 100000 0.5 14 500 10 8
12 10000 1 8 100 100 8
13 10000 0.9 五 100 50 12
14 10000 0.8 五 100 50 18
15 10000 0.7 6 250 10 8
16 10000 0.6 6 15 100 18
17 10000 0.5 3 15 50 14