,对于text类型可以无需强类型转换(::tsvector或to_tsvector(config_name, text)),所以这个操作符实际支持的参数类型是这样的: tsvector @@ tsquery INDEX pgweb_idx ON pgweb USING GIN(to_tsvector('english', title || ' ' || body)); 还可以单独创建一个tsvector列 使用了to_tsvector()函数的双参数版本指定了全文检索配置,因此必须使用to_tsvector()相同全文检索配置才能命中索引。 比即,WHERE to_tsvector('english', body) @@ 'a & b' 可以使用该索引,但WHERE to_tsvector(body) @@ 'a & b'不能。 在使用一个单独的列来存储tsvector表示时,有必要创建一个触发器在title或body改变时保证tsvector列为当前值。详见文档。
方案二:结合全文检索(tsvector) PostgreSQL 内置全文搜索(Full Text Search)可与 trigram 互补。 可通过将文本字段转换为 tsvector 实现更灵活的匹配: ALTER TABLE users ADD COLUMN name_tsv tsvector GENERATED ALWAYS AS (to_tsvector('simple', name)) STORED; CREATE INDEX idx_users_name_tsv ON users USING gin(name_tsv); GENERATED ALWAYS AS (to_tsvector('chinese', name)) STORED; CREATE INDEX idx_users_zh_tsv ON users 十一、实战建议总结 场景 推荐方案 说明 少量中文名、地名 ✅ pg_trgm 简单高效 中等量文本搜索 ✅ tsvector('simple') 基础全文索引 中文内容库(>百万行) ✅ zhparser
|\《|\》]' ,'','g'); $$ language sql strict immutable; 4.2 每两个字符做为一个词处理,将字符串转换为tsvector drop function if exists str_to_tsvector(text); create or replace function str_to_tsvector(text) returns tsvector as $$ declare v_count integer; v_txt text; v_txts text[]; v_result tsvector; begin v_txt ..v_count loop v_txts := array_append(v_txts, substring(v_txt,i,2)); end loop; --tsvector from unnest(v_txts) as f group by f ),cte2 as( select f from cte1 order by f )select array_to_tsvector
首先,我们需要使用PostgreSQL连接函数||和转换函数to_tsvector()将所有列放在一起。 这是因为函数to_tsvector()规范化每个单词以允许我们找到相同单词的变体形式,然后按字母顺序对结果进行排序。这个数字就是document中单词的位置。 函数to_tsquery()将参数(可以是直接或稍微调整的用户搜索)转换为文本搜索条件,该条件将以与to_tsvector()执行相同的方式减少输入。 该@@运营商标识,如果tsvector匹配的tsquery或其他tsvector。它返回true或false,这使其易于作为WHERE标准的一部分使用。 sammy=# ALTER TABLE news ADD "document" tsvector; 我们现在需要使用不同的查询将数据插入表中。
但填充数组字段需要调用 SELECT to_tsvector('parser', 'nane') 查询后使用脚本处理结果后再写入数组,比较麻烦。 修改 tsvector 分词向量字段,手动向此字段添加前缀词的分词向量。但分词向量不同于文本,不能直接拼接。 最好的方案当然是最后一种,改动最小,于是我就查询了一下 PostgreSQL 向量拼接,还是找到了向量拼接的方法,使用 ::tsvector 将字符串强转成向量,再使用 || 拼接到原来的分词向量上,SQL 语句类似 SELECT to_tsvector('parser', 'keyword') || 'prefix'::tsvector。
// 设置分词规则 (n 名词 v 动词等,详情阅读下面的文档) 给某一列的分词结果添加 gin 索引 create index idx_name on table using gin(to_tsvector #重要单字复合: 4 zhparser.multi_zall = false #全部单字复合: 8 SQL 查询中我们可以使用最简单的 SELECT * FROM table WHERE to_tsvector 的返回结果为 '国家' & '大剧院' & '大剧' & '剧院' ,当然我们也可以使用 & | 符号拼接自己需要的向量;在查询 长句 时,可以使用 SELECT * FROM table WHERE to_tsvector 我们接着对分词效果和效率进行优化: 存储分词结果 我们可以使用一个字段来存储分词向量,并在此字段上创建索引来更优地使用分词索引: ALTER TABLE table ADD COLUMN tsv_column tsvector ; // 添加一个分词字段 UPDATE table SET tsv_column = to_tsvector('parser_name', coalesce(field,''));
/ 设置分词规则 (n 名词 v 动词等,详情阅读下面的文档) 给某一列的分词结果添加 gin 索引 create index idx_name on table using gin(to_tsvector 重要单字复合: 4 zhparser.multi_zall = false #全部单字复合: 8 SQL 查询中我们可以使用最简单的 SELECT * FROM table WHERE to_tsvector 的返回结果为 '国家' & '大剧院' & '大剧' & '剧院' ,当然我们也可以使用 & | 符号拼接自己需要的向量;在查询 长句 时,可以使用 SELECT * FROM table WHERE to_tsvector 我们接着对分词效果和效率进行优化: 存储分词结果 我们可以使用一个字段来存储分词向量,并在此字段上创建索引来更优地使用分词索引: ALTER TABLE table ADD COLUMN tsv_column tsvector ; // 添加一个分词字段 UPDATE table SET tsv_column = to_tsvector('parser_name', coalesce(field,''));
NOT EXISTS vector; CREATE TABLE documents ( id serial PRIMARY KEY, content text, content_tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED, embedding vector(384) -- 假设用 OpenAI
全文搜索比较: -- PostgreSQL CREATE INDEX idx_fts ON articles USING gin(to_tsvector('english', content)); SELECT title FROM articles WHERE to_tsvector('english', content) @@ to_tsquery('english', 'database & performance
特殊类型 -- 特殊类型 uuid -- 通用唯一标识符 xml -- XML 数据 tsvector -- 文本搜索向量 tsquery - special_example ( user_uuid UUID DEFAULT gen_random_uuid(), document XML, search_index TSVECTOR
section_path VARCHAR(255) NOT NULL, -- 如"2.3.1>2.3>2" chunk_content TEXT NOT NULL, clean_content TSVECTOR idx_section ON knowledge_chunks (book_id, section_path); 关键设计要点: 分层存储:section_path字段使用特殊符号记录章节层级关系 内容优化:TSVECTOR
search_stmt = f""" SELECT id, title, department, tags, ts_rank(to_tsvector ('english', title), plainto_tsquery('english', :query)) as title_rank, ts_rank(to_tsvector tag_rank FROM document_metadata WHERE is_active = 1 AND ( to_tsvector ('english', title) @@ plainto_tsquery('english', :query) OR to_tsvector('english', array_to_string
安装复杂度 简单 需启用扩展 中文支持 ✅ ✅(推荐 UTF8 编码) ✅ 实战建议 对模糊查询频繁的字段(如用户名、标题、商品名),强烈推荐使用 pg_trgm; 对搜索引擎类业务,可与 全文检索(tsvector
在JSON列上的全文索引与其他列是类似的,因此我们的查询需要使用to_tsquery函数和to_tsvector函数的文本搜索的语法。
同时匹配JSON字段:-- 假设order_data里有个notes字段存用户备注CREATE INDEX idx_notes_fulltext ON orders USING GIN ( to_tsvector ('english', order_data ->> 'notes') || to_tsvector('simple', order_data -> 'items' ->> 'sku'));-- item ->> 'sku' as skuFROM orders, jsonb_array_elements(order_data -> 'items') as itemWHERE to_tsvector 范围查询WHERE (order_data -> 'payment' ->> 'amount')::DECIMAL BETWEEN 100 AND 1000-- 模糊匹配(配合全文检索)WHERE to_tsvector
测试 SELECT to_tsvector('chinese_zh', '上海自来水来自海上'); -- 分词结果:'上海':1 '来自':3 '自来水':2 -- 4.
PostgreSQL 全文检索的搜索过程实际上使用一个 tsvector 和 tsquery 进行匹配,tsvector 代表了文档,而 tsquery 代表了检索条件,匹配的运算符是“@@”。 postgres=# select 'We Love PostgreSQL Database'::tsvector; tsvector ----
这里我将使用pgvector ,GIN/Gist+tsvector,先进行第一期的Hybird的介方案介绍。
tsvector类型:表示一个为文本搜索优化的形式下的文档,去除重复分词后按分词顺序存储,可以存储位置信息和权重信息。 tsquery类型:表示一个文本查询,存储查询的分词,可存储权重信息。
VARCHAR(43) INET VARCHAR(43) MACADDR VARCHAR(17) UUID VARCHAR(36) XML LONGTEXT JSON LONGTEXT TSVECTOR