Elasticsearch 中的位向量

作者:来自 Elastic Benjamin Trent

从 Elasticsearch 中的向量搜索开始,我们就支持浮点值(float)。在 8.6 版中,我们添加了对字节(byte)编码向量的支持。在 8.14 版中,我们添加了自动量化到半字节值(half-byte)的功能。在 8.15 版中,我们添加了对位(bit)编码向量的支持。

但是,什么是位向量及其实际含义?正如字面上所言,位向量是向量的每个维度都是一个位(bit)。当将向量的数据大小与典型的浮点值进行比较时,位向量的大小减少了 32 倍之多。

每一位都很重要

一些语义嵌入模型本身输出位向量,例如 Cohere。此外,一些其他类型的数据(例如 image hashing)直接利用位向量。

但是,大多数语义嵌入模型输出浮点向量,并且不支持直接位编码。

你可以自己简单地将向量二值化,因为数学很简单。对于每个向量维度,检查值是否 > 中位数。如果是,则为 1 位,否则为 0 位。

图 0:将 8 个浮点值转换为单独的位值,然后折叠为单字节,假设中间值为 0。

以下是一些对向量进行二值化的简单 Python 代码:

ini 复制代码
1.  import numpy as np
2.  # first determine which is greater than 0
3.  bits = np.array(my_float_vector) > 0
4.  # now transform to bits
5.  bits = np.packbits(bits)
6.  # now transform it to a hexidecimal string for indexing into Elasticsearch
7.  hex_str = bits.tobytes().hex()

显然,这会丢失相当多的信息。但对于较大的向量或专门优化以与位编码配合良好的向量,节省的空间是值得的。

考虑 100 万个 1024 维浮点向量。每个向量大小为 4KB,所有向量将需要大约 4GB。使用二进制量化,每个向量现在只有 128 字节,所有向量总共只有 128MB 左右。当你考虑存储和内存成本时,这非常有吸引力。

现在,由于我们不再处于 float 领域,我们不能使用典型的距离函数,如 cosineSimilarity 或 dotProduct。相反,我们利用汉明距离利用每个维度都是单个位的优势。

汉明距离相当简单,对于每个单独的位,我们计算与另一个向量中相应位的异或。然后我们将结果位相加。

图 1:两个位元素之间的汉明距离计算。

让我们回想一下我们的 100 万个 1024 维向量。除了节省空间之外,使用 128 字节上的汉明(hamming)距离与使用 1024 个浮点上的 dotProduct 相比,计算时间显著减少。

对于一些简单的基准测试(这并不详尽),我们在 Elasticsearch 中使用 flat 索引对 100 万个 1024 维向量进行了索引。

仅使用 2GB 的堆外空间,位向量大约只需要 40ms 就能返回,但浮点向量需要超过 3000ms。如果我们将堆外空间增加到 4GB,位向量仍然需要相同的时间(它们甚至更早地装入内存),而浮点向量则缩短到 200ms。

因此,汉明距离仍然比浮点点积快得多,并且需要的内存要少得多。

一点错误

位向量并不完美,很明显这是一种有损编码。担心的不是向量不唯一。即使使用位编码,386 维向量仍然有 个可能的唯一向量。主要担心的是距离冲突和编码引入的错误大小。

即使我们假设一个分布良好的位编码,在收集大量向量时也可能会发生许多距离冲突。直观地说,这是有道理的,因为我们的距离测量是对位求和。例如,00000001 和 10000000 与 00000001 和 00000010 之间的距离相同。一旦你需要收集超过维度的文档,就会发生冲突。实际上,它会比这发生得更快。

为了说明这一点,这里有一项小型研究。这里的重点是找出需要收集多少位向量才能获得真正的最近前 𝑘 个向量。

对于第一个实验,我们使用了来自其 Wikipedia 数据集的 100 万个 CohereV3 向量。我们随机抽样(不重复)了 50 个查询向量,并使用它们来确定真正的 dotProduct 和 hamming 距离。

以下是表现 "最佳" 和 "最差" 的查询向量。质量是检索正确的 100 个最近邻居所需的文档数量(例如,越多越差)。

图 2:性能最佳的 CohereV3 查询向量及其距离,你可以看到距离实际上是如何很好地对齐的 图 3:表现最差的 CohereV3 查询向量及其距离。在这里,较近的距离对齐得很好,但当我们开始收集较远的向量时,这种相关性会减弱。

图 4:在所有 50 个查询中获取真正的 𝑘 个最近邻居所需的向量中位数。CohereV3 在这里表现出色,表明即使对于 第 100 个最近邻居,也只需要大约 10 倍的过采样。然而,从视觉上看,我们可以看到所需的过采样呈指数级增长。

从这项小型研究来看,CohereV3 表现非常出色。中位数情况显示,你可以过采样约 10 倍以实现类似的召回率。但是,在最坏的情况下,当收集超过 50 个最近的文档时,它开始出现问题,需要超过 10 倍的过采样。根据查询和数据集,你可能会遇到问题。

那么,当模型和数据集组合未针对位向量进行优化时,二值化效果如何?我们使用 e5-small-v2 并嵌入 quora 数据集来测试这一点。随机取 500k 个向量,然后从这些向量中随机抽取 50 个查询向量。

图 5:表现最佳的 e5-small 查询向量及其距离。极近的距离对齐得相当好,但仍然不是特别好。 图 6:表现最差的 e5-small 查询向量及其距离。汉明距离和点积距离实际上不相关。

图 7:获取真正的 𝑘 个最近邻居所需的向量中位数。

最佳的 e5-small 向量表现中等,其汉明距离与点积呈半相关。最坏的情况则完全不同。距离实际上是不相关的。中值表明,你需要过采样大约 800 倍才能获得最接近的 10 个向量,而且情况只会越来越糟。

简而言之,对于二进制量化效果良好且模型很好地适应数据集的模型,位量化是一个很好的选择。也就是说,请记住,随着你收集更多向量,所需的过采样可能会呈指数级增长。

对于域外数据集,其中最近的向量对于模型没有很好区分,或者对于根本没有针对二进制量化进行优化的模型,即使只有少量的最近向量,位向量也可能存在问题。

好的,但是我该如何使用它?

在 Elasticsearch 中使用位向量时,你可以在映射中指定位编码。例如:

markdown 复制代码
1.  {
2.    "mappings": {
3.      "properties": {
4.        "vector": {
5.          "type": "dense_vector",
6.          "element_type": "bit"
7.        }
8.      }
9.    }
10.  }

图 8:在 Elasticsearch 中映射位向量,允许进行位编码。第一个文档将静态设置位维度。

或者如果你不想在 HNSW 索引中编制索引,那么你可以使用 flat 索引类型。

json 复制代码
1.  {
2.    "mappings": {
3.      "properties": {
4.        "vector": {
5.          "type": "dense_vector",
6.          "element_type": "bit",
7.          "index_options": {
8.            "type": "flat"
9.          }
10.        }
11.      }
12.    }
13.  }

图 9:在平面索引类型中映射 Elasticsearch 中的位向量。

然后,要使用位向量索引文档,可以使用以下命令:

markdown 复制代码
1.  {
2.    "vector": "945fb26ec197caf96803725b6b05ba420f8bd3d19c2034391f910a3bcff98032733f75a47d1fdae134da91c71c97d9a3c9a253194bbe952dc768bd46e717fa91eafb43e0a232f8a983a6614b88ab2029b65b823f15dc32dbad5d8b4524ea896edba2f8508174f8b34dd66760187c2d38c635d42228c3ef991a0970e80bdd4aa7"
3.  }

图 10:十六进制格式的 1024 维位向量。

现在你可以使用 knn 查询

json 复制代码
1.  {
2.    "query": {
3.      "knn": {
4.        "field": "vector",
5.        "query_vector": "1a7bf8e8f943dcddfd8375bafef2ad630ab6bd3e8924f8e40a3755dd00ae6477e2c3bfd57ed771d8f0f33f4b2c9d443166b40ba443bd54a9c5783931dcb68c3c683034b065fe37e9c2ca15d74c44170920b18e3f485ddf1bed25cc083cf38d474992a89cba16d0c8e5d1f8a5dba099118654d863e09acb9cf2743fe0239a6a64"
6.      }
7.    }
8.  }

图 11:使用 1024 维十六进制向量查询位向量。

还有一点

感谢你看完所有这些 2-bit 笑话。我们对位向量在 8.15 中为 Elasticsearch 带来的可能性感到非常兴奋。请在 8.15 发布后在 Elastic Cloud 中试用它,或者立即在 Elasticsearch Serverless 中试用它!

准备好自己尝试一下了吗?开始免费试用

Elasticsearch 集成了 LangChain、Cohere 等工具。加入我们的高级语义搜索网络研讨会,构建你的下一个 GenAI 应用程序!

原文:Bit vectors in Elasticsearch --- Search Labs

相关推荐
woshiabc1114 小时前
windows安装Elasticsearch及增删改查操作
大数据·elasticsearch·搜索引擎
arnold667 小时前
探索 ElasticSearch:性能优化之道
大数据·elasticsearch·性能优化
成长的小牛2339 小时前
es使用knn向量检索中numCandidates和k应该如何配比更合适
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客11 小时前
Elasticsearch:什么是查询语言?
大数据·数据库·elasticsearch·搜索引擎·oracle
启明真纳11 小时前
elasticache备份
运维·elasticsearch·云原生·kubernetes
幽弥千月21 小时前
【ELK】ES单节点升级为集群并开启https【亲测可用】
elk·elasticsearch·https
运维&陈同学21 小时前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法
Y编程小白1 天前
Git版本控制工具--基础命令和分支管理
大数据·git·elasticsearch
酱学编程2 天前
ES搜索原理
大数据·elasticsearch·搜索引擎
龙少95432 天前
【SpringBoot中怎么使用ElasticSearch】
spring boot·elasticsearch·jenkins