首页 > 解决方案 > 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将包含 512 维向量,该向量是从original_data.


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

  1. 输入被转换为 512 维向量A
  2. A迭代x数据库上的所有对象(或不迭代)。
  3. A在每次迭代中,计算和之间的归一化点积(余弦相似度)x.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 做到这一点?

谢谢!

标签: sqldjangopostgresqlsearchcosine-similarity

解决方案


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

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;

这里有一个相关问题的答案很有帮助:Vector (array) addition in Postgres


推荐阅读