PostgreSQL 扩展

pg_vector

Drizzle 模式中没有用于创建扩展的特定代码。我们假设如果你使用向量类型、索引和查询,则你已安装 pg_vector 扩展的 PostgreSQL 数据库。

pg_vector 是 Postgres 的开源向量相似性搜索

将向量与其他数据一起存储。支持:

列类型

vector

将向量与其他数据一起存储

更多信息,请参阅 pg_vector 官方文档 文档.

const table = pgTable('table', {
    embedding: vector({ dimensions: 3 })
})
CREATE TABLE IF NOT EXISTS "table" (
	"embedding" vector(3)
);

索引

你现在可以为 pg_vector 指定索引,并使用 pg_vector 函数进行查询、排序等操作。

让我们从 pg_vector 文档中选取一些 pg_vector 索引的示例,并将它们转换为 Drizzle 格式。

L2 距离、内积和余弦距离

// CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);
// CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);

const table = pgTable('items', {
    embedding: vector({ dimensions: 3 })
}, (table) => [
  index('l2_index').using('hnsw', table.embedding.op('vector_l2_ops'))
  index('ip_index').using('hnsw', table.embedding.op('vector_ip_ops'))
  index('cosine_index').using('hnsw', table.embedding.op('vector_cosine_ops'))
])

L1 距离、汉明距离和杰卡德距离 - 在 pg_vector 0.7.0 版本中添加

// CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);
// CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);
// CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);

const table = pgTable('table', {
    embedding: vector({ dimensions: 3 })
}, (table) => [
  index('l1_index').using('hnsw', table.embedding.op('vector_l1_ops'))
  index('hamming_index').using('hnsw', table.embedding.op('bit_hamming_ops'))
  index('bit_jaccard_index').using('hnsw', table.embedding.op('bit_jaccard_ops'))
])

辅助函数

对于查询,你可以使用预定义的向量函数,也可以使用 SQL 模板运算符创建自定义函数。

你还可以使用以下辅助程序:

import { l2Distance, l1Distance, innerProduct, 
          cosineDistance, hammingDistance, jaccardDistance } from 'drizzle-orm'

l2Distance(table.column, [3, 1, 2]) // table.column <-> '[3, 1, 2]'
l1Distance(table.column, [3, 1, 2]) // table.column <+> '[3, 1, 2]'

innerProduct(table.column, [3, 1, 2]) // table.column <#> '[3, 1, 2]'
cosineDistance(table.column, [3, 1, 2]) // table.column <=> '[3, 1, 2]'

hammingDistance(table.column, '101') // table.column <~> '101'
jaccardDistance(table.column, '101') // table.column <%> '101'

如果 pg_vector 需要使用其他函数,你可以从我们现有的实现中复制实现。具体操作如下

export function l2Distance(
  column: SQLWrapper | AnyColumn,
  value: number[] | string[] | TypedQueryBuilder<any> | string,
): SQL {
  if (is(value, TypedQueryBuilder<any>) || typeof value === 'string') {
    return sql`${column} <-> ${value}`;
  }
  return sql`${column} <-> ${JSON.stringify(value)}`;
}

你可以根据需要命名它并更改操作符。此示例允许使用数字数组、字符串数组、字符串,甚至是选择查询。你可以随意创建任何其他类型,甚至可以贡献代码并提交 PR。

示例

让我们从 pg_vector 文档中选取一些 pg_vector 查询的示例,并将它们转换为 Drizzle 格式。

import { l2Distance } from 'drizzle-orm';

// SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
db.select().from(items).orderBy(l2Distance(items.embedding, [3,1,2]))

// SELECT embedding <-> '[3,1,2]' AS distance FROM items;
db.select({ distance: l2Distance(items.embedding, [3,1,2]) })

// SELECT * FROM items ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;
const subquery = db.select({ embedding: items.embedding }).from(items).where(eq(items.id, 1));
db.select().from(items).orderBy(l2Distance(items.embedding, subquery)).limit(5)

// SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;
db.select({ innerProduct: sql`(${maxInnerProduct(items.embedding, [3,1,2])}) * -1` }).from(items)

// and more!

postgis

Drizzle 模式中没有用于创建扩展的特定代码。我们假设如果你使用 Postgis 类型、索引和查询,则你已安装 postgis 扩展的 PostgreSQL 数据库。

PostGIS 网站中所述:

PostGIS 通过添加对地理空间数据的存储、索引和查询支持,扩展了 PostgreSQL 关系数据库的功能。

如果你在 PostGIS 扩展中使用 introspectpush 命令,并且不希望包含 PostGIS 表,则可以使用 extensionsFilters 忽略所有 PostGIS 表。

列类型

geometry

将几何数据与其他数据一起存储

更多信息,请参阅 PostGIS 官方文档 文档.

const items = pgTable('items', {
  geo: geometry('geo', { type: 'point' }),
  geoObj: geometry('geo_obj', { type: 'point', mode: 'xy' }),
  geoSrid: geometry('geo_options', { type: 'point', mode: 'xy', srid: 4000 }),
});

mode

类型 geometry 有两种数据库映射模式:tuplexy

type

当前版本具有预定义类型:point,是 PostgreSQL PostGIS 扩展中的 geometry(Point) 类型。如果你想使用其他类型,你可以在其中指定任何字符串。

索引

使用可用的 Drizzle 索引 API,你应该能够为 PostGIS 编写任何索引。

示例

// CREATE INDEX custom_idx ON table USING GIST (geom);

const table = pgTable('table', {
  	geo: geometry({ type: 'point' }),
}, (table) => [
  index('custom_idx').using('gist', table.geo)
])