本文为您介绍在Hologres中如何使用向量计算功能。

背景信息

Proxima是一款来自于阿里达摩院的实现向量近邻搜索的高性能软件库,相比于fassi等开源的同类产品,Proxima在稳定性、性能等方面都要更为出色,能够提供业内性能和效果领先的基础方法模块,支持图像、视频、人脸等各种应用场景。交互式分析(Hologres)向量查询功能与Proxima深度整合,提供高性能的向量查询服务。

Proxima简介

  • 基本概念
    • 特征向量:向量是一种将实体和应用代数化的一种表示,其将实体间的关系抽象成向量空间中的距离,而距离的远近代表着相似程度。例如:身高、年龄、性别、地域。
    • 向量检索:在特征向量数据集合中进行快速搜索和匹配的方法,常涉及到的问题有KNN和RNN。
    • KNN(K-Nearest Neighbor):查找离查询点最近的 K 个点。
    • RNN(Radius Nearest Neighbor):查找查询点某半径范围内的所有点。
  • Proxima的基本模型
    分为索引构建和在线检索两部分,索引构建从原始向量数据中构建出相关索引文件,并传予在线检索模块加载使用。在线检索加载完索引文件后,为向量检索提供查询服务。
    • 索引构建:支持Brute Force、KD-Tree、Product Quantization、KNN Graph、LSH 等。
    • 在线检索:在聚类后的数据集上进行KNN & RNN搜索,用户设定检索过程中的参数。
  • Proxima与Hologres概念对照
    Proxima概念 Hologres中的概念
    特征向量 数组类型 Array
    向量索引 一种特殊类型的Index
    距离计算
    • 一种类型的UDF: proxima_distance()
    • 每种距离计算对应一个UDF
    KNN查询 order by distance(x, [x1, x2]) asc limit k
    RNN查询 where distance(x, [x1,x2]) < r

使用Proxima进行向量计算

在交互式分析(Hologres)中使用Proxima进行向量计算的操作步骤如下:

  1. 安装Proxima插件。
    Proxima是以一个extension的方式与Hologres连通,因此在使用之前需要执行如下命令安装Proxima插件。
    create extension proxima;
    Proxima插件是针对数据库级别使用的,一个数据库仅需要安装一次即可。
  2. 向量查询。
    在Hologres中,向量使用FLOAT4类型的数组表示,向量查询的API场景如下:
    • 精确查询
      pm_xxx开头的UDF均为精准查询。
      1. 使用精准的API来做Top N的查询,需要您在表中定义好对应的向量字段,示例语句如下。
        create table feature_tb (
            id bigint,
            feature float4[] check(array_ndims(feature) = 1 and array_length(feature, 1) = 4)
        );
      2. 查询Top N,示例语句如下。
        select pm_squared_euclidean_distance(feature, '{0.1,0.1,0.1,0.1}') as distance from feature_tb order by distance asc limit 10;
    • 近似查询(推荐,利用索引加速查询)
      pm_approx开头的UDF均为近似查询。如果要使用近似查询API来做Top N查询,除了需要在表里面定义好对应的向量字段外,还需要为对应的字段设置上Proxima索引,查询方法与索引类型比配,查询效率更高,示例如下:
      --在使用Proxima向量检索场景,由于Proxima索引检索的单点特性,Shard为1可以充分发挥性能,无需多个Shard。
      --创建一个shard为1的table group,命名为tg_1,如果已经创建,不用重复创建。
      CALL HG_CREATE_TABLE_GROUP ('tg_1', 1);
      
      begin;
      create table feature_tb (
          id bigint,
          feature float4[] check(array_ndims(feature) = 1 and array_length(feature, 1) = 4)
      );
      call set_table_property('feature_tb', 'proxima_vectors', '{"feature":{"algorithm":"Graph","distance_method":"SquaredEuclidean","builder_params":
      {"min_flush_proxima_row_count" : 1000}, "searcher_init_params":{}}}');
      call set_table_property('feature_tb','table_group','tg_1');
      end;
      参数描述如下表所示。
      参数 描述
      algorithm 用于指定构建向量索引的算法,目前仅支持Graph。
      distance_method 用于定义构建向量索引使用的距离计算方法。Hologres目前仅支持如下三种距离计算函数:
      • SquaredEuclidean

        平方欧式距离,推荐使用, 查询效率最高。适合查询时使用pm_approx_squared_euclidean_distance。

      • Euclidean

        开方的欧式距离,适合查询时使用pm_approx_euclidean_distance,如果使用其他距离函数会利用不上索引。

      • InnerProduct

        内积距离,比较低效,尽量避免使用,除非业务有强需求,适合查询时使用pm_approx_inner_product_distance。

  3. UDF列表说明
    交互式分析(Hologres)当前版本支持的向量计算UDF如下:
    • 精准版
      float4 pm_squared_euclidean_distance(float4[], float4[])
      float4 pm_euclidean_distance(float4[], float4[])
      float4 pm_inner_product_distance(float4[], float4[])
    • 近似版本
      float4 pm_approx_squared_euclidean_distance(float4[], float4[])
      float4 pm_approx_euclidean_distance(float4[], float4[])
      float4 pm_approx_inner_product_distance(float4[], float4[])
      使用如下的方式查询Top N,近似查询中的第二个参数必须是常量值,尽量不加其它的过滤条件,在有其它过滤情况下,会影响索引使用,性能可能更差:
      -- 计算内积的TOPK,此时建表里面的proxima_vector参数的distance_method需要为SquaredEuclidean
      select pm_approx_squared_euclidean_distance(feature, '{0.1,0.2,0.3,0.4}') as distance from feature_tb order by distance asc limit 10 ;
      
      -- 计算内积的TOPK,此时建表里面的proxima_vector参数的distance_method需要为Euclidean
      select pm_approx_euclidean_distance(feature, '{0.1,0.2,0.3,0.4}') as distance from feature_tb order by distance asc limit 10 ;
      
      -- 计算内积的TOPK,此时建表里面的proxima_vector参数的distance_method需要为InnerProduct
      select pm_approx_inner_product_distance(feature, '{0.1,0.2,0.3,0.4}') as distance from feature_tb order by distance desc limit 10 ;

使用示例

使用Proxima进行向量计算的示例语句如下。
create extension proxima;

CALL HG_CREATE_TABLE_GROUP ('tg_1', 1);

begin;
create table feature_tb (
    id bigint,
    feature float4[] check(array_ndims(feature) = 1 and array_length(feature, 1) = 4)
);
call set_table_property('feature_tb', 'proxima_vectors', '{"feature":{"algorithm":"Graph","distance_method":"SquaredEuclidean","builder_params":
{"min_flush_proxima_row_count" : 1000}, "searcher_init_params":{}}}');
call set_table_property('feature_tb','table_group','tg_1');
end;

insert into feature_tb select i, array[random(), random(), random(), random()]::float4[] from generate_series(1, 10000) i;
analyze feature_tb;

select pm_approx_squared_euclidean_distance(feature, '{0.1,0.2,0.3,0.4}') as distance from feature_tb order by distance desc limit 10 ;

距离函数说明

Hologres支持的三种向量距离评估函数如下:

  • 不开方的欧式距离,计算公式如下。不开方的欧式距离
  • 开方的欧氏距离,计算公式如下。开方的欧氏距离
  • 内积距离,计算公式如下。内积距离
说明 如果您选用欧式距离进行向量计算,不开方的欧式距离与开方的欧式距离相比,可以少一个开方的计算,并且计算出的Top K记录一致。因此,不开方的欧式距离性能更好,在满足功能需求的情况下,一般建议您使用不开方的欧式距离。

常见问题

  • 报错ERROR: function pm_approx_inner_product_distance(real[], unknown) does not exist

    原因:通常是因为未在数据库中执行create extension proxima;语句来初始化Proxima插件。

    解决方法:执行create extension proxima;语句初始化Proxima插件。

  • 报错Writting column: feature with array size: 5 violates fixed size list (4) constraint declared in schema

    原因:由于写入到特征向量列的数据维度与表中定义的维度数不一致,导致出现该报错。

    解决方法:可以排查下是否有胀数据。

  • 报错The size of two array must be the same in DistanceFunction, size of left array: 4, size of right array:

    原因:由于pm_xx_distance(left, right)中,left的维度与right的维度不一致所致。

    调整pm_xx_distance(left, right)中,left的维度与right的维度一致。

  • 如何通过Java写入向量?
    通过Java写入向量的示例如下。
    private static void insertIntoVector(Connection conn) throws Exception {
        try (PreparedStatement stmt = conn.prepareStatement("insert into feature_tb values(?,?);")) {
            for (int i = 0; i < 100; ++i) {
               stmt.setInt(1, i);
               Float[] featureVector = {0.1f,0.2f,0.3f,0.4f};
               Array array = conn.createArrayOf("FLOAT4", featureVector);
               stmt.setArray(2, array);
               stmt.execute();
            }
        }
    }
  • 如何通过执行计划检查是否利用上Proxima索引?
    如果执行计划中存在Proxima filter: xxxx表明使用了索引,如下图所示;如果没有,则索引没有使用上,一般是建表语句与查询语句不匹配。索引