Drizzle | 全文搜索与生成列
本指南假定您熟悉

本指南演示了如何使用 Drizzle 和生成列在 PostgreSQL 中实现全文搜索。生成列是一种特殊列,其值始终根据其他列计算得出。它的好处在于,您无需在每次查询表时都计算该列的值。

schema.ts
migration.sql
import { SQL, sql } from 'drizzle-orm';
import { index, pgTable, serial, text, customType } from 'drizzle-orm/pg-core';

export const tsvector = customType<{
data: string;
}>({
dataType() {
  return `tsvector`;
},
});

export const posts = pgTable(
'posts',
{
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  body: text('body').notNull(),
  bodySearch: tsvector('body_search')
    .notNull()
    .generatedAlwaysAs((): SQL => sql`to_tsvector('english', ${posts.body})`),
},
(t) => [
  index('idx_body_search').using('gin', t.bodySearch),
]
);

当您向表中插入一行时,生成列的值会根据您在创建列时提供的表达式计算得出。

import { posts } from './schema';

const db = drizzle(...);

const body = "Golden leaves cover the quiet streets as a crisp breeze fills the air, bringing the scent of rain and the promise of change"

await db.insert(posts).values({
    body,
    title: "The Beauty of Autumn",
  }
).returning();
[
  {
    id: 1,
    title: 'The Beauty of Autumn',
    body: 'Golden leaves cover the quiet streets as a crisp breeze fills the air, bringing the scent of rain and the promise of change',
    bodySearch: "'air':13 'breez':10 'bring':14 'chang':23 'cover':3 'crisp':9 'fill':11 'golden':1 'leav':2 'promis':21 'quiet':5 'rain':18 'scent':16 'street':6"
  }
]

您可以使用这种方式,通过 Drizzle ORM 和生成列在 PostgreSQL 中实现全文搜索。@@ 运算符用于直接匹配。

const searchParam = "bring";

await db
  .select()
  .from(posts)
  .where(sql`${posts.bodySearch} @@ to_tsquery('english', ${searchParam})`);
select * from posts where body_search @@ to_tsquery('english', 'bring');

这是一个更高级的包含生成列的 Schema。search 列由 titlebody 列生成,并且 setweight() 函数用于为全文搜索分配不同的列权重。这通常用于标记来自文档不同部分(如标题与正文)的条目。

schema.ts
migration.sql
import { SQL, sql } from 'drizzle-orm';
import { index, pgTable, serial, text, customType } from 'drizzle-orm/pg-core';

export const tsvector = customType<{
data: string;
}>({
dataType() {
  return `tsvector`;
},
});

export const posts = pgTable(
'posts',
{
 id: serial('id').primaryKey(),
 title: text('title').notNull(),
 body: text('body').notNull(),
 search: tsvector('search')
   .notNull()
   .generatedAlwaysAs(
      (): SQL =>
       sql`setweight(to_tsvector('english', ${posts.title}), 'A')
        ||
        setweight(to_tsvector('english', ${posts.body}), 'B')`,
   ),
},
(t) => [
  index('idx_search').using('gin', t.search),
],
);

您可以使用这种方式进行全文搜索查询。

const search = 'travel';

await db
  .select()
  .from(posts)
  .where(sql`${posts.search} @@ to_tsquery('english', ${search})`);
select * from posts where search @@ to_tsquery('english', 'travel');