向量搜索

LanBuffer 的 Table API 基于 Lance 格式提供高性能向量搜索能力,兼容 LanceDB 协议。

基本向量搜索

向量搜索通过查询端点 POST /v1/table/{id}/query/ 实现。当请求体中包含非空的 vector 字段时,自动执行向量搜索。

SDK 示例:

import * as lancedb from "@lancedb/lancedb";

const db = await lancedb.connect("lanbuff://127.0.0.1:7001");

// 创建包含向量数据的表
const tbl = await db.createTable("products", [
  { vector: [0.1, 0.2, 0.3, 0.4], name: "产品A", price: 29.9 },
  { vector: [0.5, 0.1, 0.8, 0.2], name: "产品B", price: 49.9 },
  { vector: [0.9, 0.7, 0.1, 0.6], name: "产品C", price: 19.9 },
  { vector: [0.3, 0.4, 0.5, 0.1], name: "产品D", price: 99.9 },
]);

// 搜索最相似的 3 条记录
const results = await tbl.search([0.1, 0.2, 0.3, 0.4]).limit(3).toArray();
console.log(results);

HTTP 请求:

curl -X POST http://127.0.0.1:7001/v1/table/products/query/ \
  -H "Content-Type: application/json" \
  -d '{
    "vector": [0.1, 0.2, 0.3, 0.4],
    "k": 3
  }'

距离度量

通过 distance_type 参数指定距离计算方式:

度量说明适用场景
L2欧氏距离(默认)通用场景
cosine余弦相似度文本嵌入、归一化向量
dot内积推荐系统、最大内积搜索
hamming汉明距离二进制向量
// 使用余弦相似度
const results = await tbl
  .search([0.1, 0.2, 0.3, 0.4])
  .distanceType("cosine")
  .limit(5)
  .toArray();

带过滤的向量搜索

结合 SQL 过滤表达式缩小搜索范围:

// 先过滤再搜索(prefilter,默认行为)
const results = await tbl
  .search([0.1, 0.2, 0.3, 0.4])
  .where("price < 50")
  .limit(10)
  .toArray();

预过滤 vs 后过滤:

  • 预过滤prefilter: true,默认)— 先根据条件过滤数据,再在过滤后的子集上执行向量搜索。结果数量精确等于 k(如果有足够的匹配数据)。
  • 后过滤prefilter: false)— 先执行向量搜索找到 k 个最近邻,再用条件过滤。结果数量可能少于 k
// 后过滤模式
const results = await tbl
  .search([0.1, 0.2, 0.3, 0.4])
  .where("price < 50")
  .prefilter(false)
  .limit(10)
  .toArray();

选择返回列

只返回需要的列以减少数据传输:

const results = await tbl
  .search([0.1, 0.2, 0.3, 0.4])
  .select(["name", "price"])
  .limit(5)
  .toArray();

向量索引

对于大规模数据集,创建向量索引可以显著提升搜索性能:

// 创建 IVF_PQ 索引
await tbl.createIndex("vector", {
  config: lancedb.Index.ivfPq({
    numPartitions: 256,
    numSubVectors: 16,
  }),
});

索引类型选择:

索引类型特点建议场景
IVF_FLAT无量化,精度最高数据量 < 100 万,对精度要求极高
IVF_PQ乘积量化,内存占用小通用大规模场景(默认推荐)
IVF_SQ标量量化,精度与速度平衡中等规模,需要较好精度
IVF_HNSW_SQHNSW 图 + 标量量化对延迟要求极高的场景

索引参数调优

搜索时可通过参数调整召回率与速度的平衡:

// nprobes: 探测的分区数,越大召回率越高但越慢
// refine_factor: 精炼因子,从候选集中重新排序
const results = await tbl
  .search([0.1, 0.2, 0.3, 0.4])
  .nprobes(20)
  .refineFactor(10)
  .limit(5)
  .toArray();
参数说明默认值
nprobes探测的 IVF 分区数,增大可提高召回率由索引决定
refine_factor精炼因子,先取 k * refine_factor 个候选再精排

暴力搜索

跳过索引直接暴力搜索(适合小数据集或调试):

curl -X POST http://127.0.0.1:7001/v1/table/products/query/ \
  -H "Content-Type: application/json" \
  -d '{
    "vector": [0.1, 0.2, 0.3, 0.4],
    "k": 5,
    "bypass_vector_index": true
  }'