PostgreSQL:对预矢量化数据库执行余弦相似性搜索



我正在尝试在预矢量化数据库表(如三元组相似性(上实现余弦相似性搜索,具有以下结构中的对象:

from django.contrib.postgres.fields import ArrayField
from django.db import models
class Information(object):
vectorized = ArrayField(models.FloatField(default=0.0))  # will contain 512-dimensional vector of floats
original_data = models.TextField(blank=True)
original_data_length = models.IntegerField(default=0)

其中属性vectorized将包含从original_data生成的 512 维向量。


例如,用户输入一个字符串"什么是苹果?":

  1. 输入转换为 512 维矢量A
  2. A遍历数据库上x(或不(的所有对象。
  3. 在每次迭代中,计算Ax.vectorized之间的归一化点积(余弦相似性((请参阅余弦相似性定义(。
  4. x相似度最高的对象(A的最高归一化内积(被选中,并打印出x.original_data

为此,我实现了简单的代码,它效率低下,因为它是在框架级别而不是数据库级别执行的,并且为数据库表中的所有对象分配了内存:

from core.models import Information
from numpy import dot  # dot product = inner product limited for real numbers
from numpy.linalg import norm
user_input = user_input  # let this be 512 dimensional vector converted from user input
most_similar = ("", 0)
for item in Information.objects.all():
similarity = dot(item, user_input)/norm(item, user_input)
if similarity > most_similar[1]: 
most_similar = (item.original_data, similarity)
print(most_similar[0])

有没有办法实现上面代码的更有效的方法?

有没有办法使用PostgreSQL来做到这一点?

谢谢!

这一直对我有用——请注意,它需要预规范化的向量,这无论如何都是一个很好的默认值:

CREATE OR REPLACE FUNCTION dot_product_norm_d(a double precision[], b double precision[])
RETURNS double precision AS
$$
SELECT sum(result)
FROM (SELECT (tuple.val1 * tuple.val2) AS result
FROM (SELECT UNNEST($1) AS val1,
UNNEST($2) AS val2,
generate_subscripts($1, 1) AS ix) tuple
ORDER BY ix) inn;
$$ LANGUAGE SQL IMMUTABLE STRICT;

这里有一个相关问题的答案很有帮助:Postgres 中的向量(数组(加法

不可能在PostgreSQL内部对向量执行余弦相似性。为此,您需要使用像AquilaDB或EuclidesDB这样的矢量数据库。AquilaDB 支持将 JSON 文档与向量一起存储,我发现这非常适合您的情况。因为,您可以将任何将交叉引用在 AquilaDB 中索引的任何向量的元数据添加到您的 PostgreSQL 数据库中。他们在他们的维基页面上有一些不错的教程。

最新更新