向量索引

向量索引介绍

向量召回是指将商品或者内容等以向量的形式表达,并建立向量索引库,索引库上支持输入一个或多个用户或商品向量来根据向量距离召回topK的商品或内容。

向量索引配置

不带类目的向量配置

{
  "table_name": "test_vector",
  "summarys": {
    "summary_fields": [
      "id",
      "vector_field"
    ]
  },
  "indexs": [
    {
      "index_name": "pk",
      "index_type": "PRIMARYKEY64",
      "index_fields": "id",
      "has_primary_key_attribute": true,
      "is_primary_key_sorted": false
    },
    {
      "index_name": "embedding",
      "index_type": "CUSTOMIZED",
      "index_fields": [
        {
          "boost": 1,
          "field_name": "id"
        },
        {
          "boost": 1,
          "field_name": "vector_field"
        }
      ],
      "indexer": "aitheta2_indexer",
      "parameters": {
        "enable_rt_build": "false",
        "min_scan_doc_cnt": "20000",
        "vector_index_type": "Qc",
        "major_order": "col",
        "builder_name": "QcBuilder",
        "distance_type": "SquaredEuclidean",
        "embedding_delimiter": ",",
        "enable_recall_report": "false",
        "is_embedding_saved": "false",
        "linear_build_threshold": "5000",
        "dimension": "128",
        "search_index_params": "{\"proxima.qc.searcher.scan_ratio\":0.01}",
        "searcher_name": "QcSearcher",
        "build_index_params": "{\"proxima.qc.builder.quantizer_class\":\"Int8QuantizerConverter\",\"proxima.qc.builder.quantize_by_centroid\":true,\"proxima.qc.builder.optimizer_class\":\"BruteForceBuilder\",\"proxima.qc.builder.thread_count\":10,\"proxima.qc.builder.optimizer_params\":{\"proxima.linear.builder.column_major_order\":true},\"proxima.qc.builder.store_original_features\":false,\"proxima.qc.builder.train_sample_count\":3000000,\"proxima.qc.builder.train_sample_ratio\":0.5}"
      }
    }
  ],
  "attributes": [
    "id",
    "vector_field"
  ],
  "fields": [
    {
      "field_name": "id",
      "field_type": "INTEGER"
    },
    {
      "user_defined_param": {
        "multi_value_sep": ","
      },
      "field_name": "vector_field",
      "field_type": "FLOAT",
      "multi_value": true
    }
  ]
}

带有类目的向量配置

{
  "table_name": "test_vector",
  "summarys": {
    "summary_fields": [
      "id",
      "vector_field",
      "category_id"
    ]
  },
  "indexs": [
    {
      "index_name": "pk",
      "index_type": "PRIMARYKEY64",
      "index_fields": "id",
      "has_primary_key_attribute": true,
      "is_primary_key_sorted": false
    },
    {
      "index_name": "embedding",
      "index_type": "CUSTOMIZED",
      "index_fields": [
        {
          "boost": 1,
          "field_name": "id"
        },
        {
          "field_name": "category_id",
          "boost": 1
        },
        {
          "boost": 1,
          "field_name": "vector_field"
        }
      ],
      "indexer": "aitheta2_indexer",
      "parameters": {
        "enable_rt_build": "false",
        "min_scan_doc_cnt": "20000",
        "vector_index_type": "Qc",
        "major_order": "col",
        "builder_name": "QcBuilder",
        "distance_type": "SquaredEuclidean",
        "embedding_delimiter": ",",
        "enable_recall_report": "false",
        "is_embedding_saved": "false",
        "linear_build_threshold": "5000",
        "dimension": "128",
        "search_index_params": "{\"proxima.qc.searcher.scan_ratio\":0.01}",
        "searcher_name": "QcSearcher",
        "build_index_params": "{\"proxima.qc.builder.quantizer_class\":\"Int8QuantizerConverter\",\"proxima.qc.builder.quantize_by_centroid\":true,\"proxima.qc.builder.optimizer_class\":\"BruteForceBuilder\",\"proxima.qc.builder.thread_count\":10,\"proxima.qc.builder.optimizer_params\":{\"proxima.linear.builder.column_major_order\":true},\"proxima.qc.builder.store_original_features\":false,\"proxima.qc.builder.train_sample_count\":3000000,\"proxima.qc.builder.train_sample_ratio\":0.5}"
      }
    }
  ],
  "attributes": [
    "id",
    "vector_field",
    "category_id"
  ],
  "fields": [
    {
      "field_name": "id",
      "field_type": "INTEGER"
    },
    {
      "user_defined_param": {
        "multi_value_sep": ","
      },
      "field_name": "vector_field",
      "field_type": "FLOAT",
      "multi_value": true
    },
    {
      "field_name": "category_id",
      "field_type": "INTEGER"
    }
  ]
}
重要
  • 引入分类的目的是为了支持按照分类进行向量检索,比如一个图片有不同的类别,如果不指定分类构建向量索引,只是对检索出来的向量进行过滤很可能会出现无结果的情况。

  • 在配置的向量索引时,若为管理员模式,build_index_params和search_index_params的参数内容要去除转义。

字段含义

  • field_name:构建向量索引的字段,必须为RAW类型,最少包括2个字段,一个是主键(或者是主键的hash值),字段值必须是整数,另一个是包含向量的字段。如果需要对向量按照分类构建索引,可以新增一个分类字段,字段类型为RAW类型,字段值为整数。这些字段在索引中的顺序必须和在fields配置的顺序相同,而且必须是按照主键、类目(如果有)、向量这个顺序。

  • index_name:向量索引的名称。

  • index_type:索引类型,必须为CUSTOMIZED。

  • indexer:构建向量索引的插件,目前仅支持aitheta2_indexer。

  • parameters:向量索引的构建参数和查询参数。

    • dimension:维度

    • embedding_delimiter: 向量分隔符,默认是","

    • distance_type:距离类型,目前仅支持如下两种

      • InnerProduct (内积)

      • SquaredEuclidean(平方欧式距离),经过归一化的数据请配置SquaredEuclidean。

    • major_order: 数据存储方式,目前支持如下两种

      • col (按列存, 对dimension有要求,必须是2的幂次方, 性能更优)

      • row(按行存,默认使用)

    • builder_name: 索引构建类型,建议配置下面两种(更多参数请联系我们)

      • QcBuilder

      • LinearBuilder(线性构建,数据文档数量少于1w时,推荐使用)

    • searcher_name: 索引检索类型,和builder_name对应,如果有GPU需求请联系我们。

      • QcSearcher(CPU检索,对应QcBuilder)

      • LinearSearcher (CPU暴力检索,对应LinearBuilder)

    • build_index_params:索引构建参数,和builder_name参数对应,具体见Proxima Builder配置。

    • search_index_params:索引检索参数,和searcher_name参数对应,具体见search_index_params配置。

    • linear_build_threshold:线性构建的阈值,若文档数量低于该阈值,则会使用LinearBuilder构建, LinearSearcher检索。默认是10000,用线性构建的好处是可以节省内存,召回结果无损, 但是若数据规模较大时,性能极差。

    • min_scan_doc_cnt: 召回候选集的个数最小值,默认10000,和proxima.qc.searcher.scan_ratio的概念类似。两者都配置的情况下,取两者的最大值

      • scan_ratio&min_scan_doc_cnt不是越大越好。太大的话,会极大影响性能&延迟

      • 一般而言, 若召回topk个向量,min_scan_doc_cnt的建议大小为max(10000, 100*topk),scan_ratio为max(10000, 100*topk)/total_doc_cnt, 具体的还得结合数据规模、召回率以及性能等参数。

      • 之所以存在两个类似参数,主要是由于实时以及多类目场景下的需求。一般用户只需要配置scan_ratio即可

    • enable_recall_report: 是否开启召回率指标汇报,默认关闭

    • is_embedding_saved: 是否保存原始向量,默认关闭。如果开启INT8/FP16量化且开启实时检索,务必开启该选项,否则会导致批次增量构建失败

    • enable_rt_build:是否支持实时索引,默认开启

    • ignore_invalid_doc:是否忽略有问题的向量数据,默认开启

    • rt_index_params:实时索引参数,当enable_rt_build为true时,可配置,如:

      {
        "proxima.oswg.streamer.segment_size": 2048
      }

查询语法

通用查询

HA3语法

query=index_name:'0.1,0.2,0.98,0.6;0.3,0.4,0.98,0.6...'
注:index_name为向量索引名,后面是要查询的向量

SQL语法

query=select proxima_score('index_name') as score,id from table_name where MATCHINDEX('index_name', ?) order by score asc limit 5&&kvpair=timeout:1000,iquan.plan.cache.enable:true;urlencode_data:false;iquan.plan.prepare.level:jni.post.optimize;dynamic_params:[["0.892704,0.783731"]]
注:index_name为向量索引名,kvpair中的dynamic_params是要查询的向量

指定top n查询

HA3语法

query=index_name:'0.1,0.2,0.98,0.6;0.3,0.4,0.98,0.6&n=10'
注:index_name为向量索引名,后面是要查询的向量,n指定向量检索返回的top结果数。

SQL语法

query=select proxima_score('index_name') as score,id from table_name where MATCHINDEX('index_name', ?) order by score asc limit 5&&kvpair=timeout:1000,iquan.plan.cache.enable:true;urlencode_data:false;iquan.plan.prepare.level:jni.post.optimize;dynamic_params:[["0.892704,0.783731&n=10"]]
注:index_name为向量索引名,kvpair中的dynamic_params是要查询的向量,n指定向量检索返回的top结果数。

设定最低分阈值

HA3语法

query=index_name:'0.1,0.2,0.98,0.6;0.3,0.4,0.98,0.6&n=10&sf=0.8'
注:index_name为向量索引名,后面是要查询的向量,sf指定要过滤分数的阈值。

SQL语法

query=select proxima_score('index_name') as score,id from table_name where MATCHINDEX('index_name', ?) order by score asc limit 5&&kvpair=timeout:1000,iquan.plan.cache.enable:true;urlencode_data:false;iquan.plan.prepare.level:jni.post.optimize;dynamic_params:[["0.892704,0.783731&n=10&sf=0.8"]]
注:index_name为向量索引名,kvpair中的dynamic_params是要查询的向量,sf指定要过滤分数的阈值。

区分类目的查询

HA3语法

query=aitheta_index_name:'16#0.1,0.2,0.98,0.6;1512#0.3,0.4,0.98,0.6&n=200'
// query需要做urlencode
query=aitheta_index_name:'16%230.1%2c0.2%2c0.98%2c0.6%3b1512%230.3%2c0.4%2c0.98%2c0.6%26n%3d200'
注:区分类目的情况下,参数值中需要指定类目id以及要查询的向量,类目id和向量之间使用'#'分隔(query中需要对'#'做URLEncode),多个类目之间使用逗号分隔,多个向量之间以分号分隔。

SQL语法

query=select proxima_score('index_name') as score,id from table_name where MATCHINDEX('index_name', ?) order by score asc limit 5&&kvpair=timeout:1000,iquan.plan.cache.enable:true;urlencode_data:false;iquan.plan.prepare.level:jni.post.optimize;dynamic_params:[["16%230.1%2c0.2%2c0.98%2c0.6%3b1512%230.3%2c0.4%2c0.98%2c0.6%26n%3d200"]]
注:index_name为向量索引名,kvpair中的dynamic_params是要查询的向量
注:dynamic_params内容需要做urlencode
注:区分类目的情况下,参数值中需要指定类目id以及要查询的向量,类目id和向量之间使用'#'分隔(query中需要对'#'做URLEncode),多个类目之间使用逗号分隔,多个向量之间以分号分隔。

设置召回参数

HA3语法

query=index_name:'0.1,0.2,0.98,0.6;0.3,0.4,0.98,0.6&n=10&sf=0.8&search_params={"proxima.qc.searcher.scan_ratio":0.001,"proxima.general.searcher.scan_count":10000}'
注:search_params指定向量召回参数,为json格式。proxima.qc.searcher.scan_ratio含有同上,proxima.general.searcher.scan_count意义同min_scan_doc_cnt
注:n,sf,search_params出现的顺序不能变

SQL语法

query=select proxima_score('index_name') as score,id from table_name where MATCHINDEX('index_name', ?) order by score asc limit 5&&kvpair=timeout:1000,iquan.plan.cache.enable:true;urlencode_data:false;iquan.plan.prepare.level:jni.post.optimize;dynamic_params:[["0.892704,0.783731&n=10&sf=0.8&search_params={"proxima.qc.searcher.scan_ratio":0.001,"proxima.general.searcher.scan_count":10000}"]]

注:index_name为向量索引名,kvpair中的dynamic_params是要查询的向量,search_params指定向量召回参数,为json格式。proxima.qc.searcher.scan_ratio含有同上,proxima.general.searcher.scan_count意义同min_scan_doc_cnt
注:n,sf,search_params出现的顺序不能变

​查询时按相似度排序

HA3语法

query=index_name:'0.1,0.2,0.98,0.6;0.3,0.4,0.98,0.6...'&&kvpairs=first_formula:proxima_score(index_name)&&sort=+RANK
注:index_name为向量索引名,后面是要查询的向量,kvpairs子句指定粗排公式为proxima_score(索引名),sort子句指定按相似度得分从小到大排序

SQL语法

query=select proxima_score('index_name') as score,id from table_name where MATCHINDEX('index_name', ?) order by score asc limit 5&&kvpair=timeout:1000,iquan.plan.cache.enable:true;urlencode_data:false;iquan.plan.prepare.level:jni.post.optimize;dynamic_params:[["0.892704,0.783731"]]
注:index_name为向量索引名,kvpair中的dynamic_params是要查询的向量,select中的proxima_score(索引名)函数用于获取向量得分,通过order by 指定向量得分为排序依据,asc表示正序,desc 表示倒序