跳转到主要内容

分词词表模型

预训练模型(llmlingua2、bert_base_uncased、wiki_tocken、gemma2b)、自定义语料训练模型、HuggingFace 分词器与 Lindera 模型。

在 pg_tokenizer 中,模型(Model) 负责将字符串词元(或原始文本)映射为整数词元 ID(INT[])。你可以直接选用四个内置预训练模型、在 PostgreSQL 表上训练自定义词表模型、导入任意 HuggingFace tokenizer.json,或者使用 Lindera 形态学分析模型。

1. 内置预训练模型

模型名称 来源 / 架构 是否需要 text_analyzer? 内存占用 适用场景
llmlingua2 microsoft/llmlingua-2-xlm-roberta-large-meetingbank(XLM-RoBERTa 多语言子词模型) 否(禁止) ~200 MB(默认预加载) 开箱即用的多语言通用文本分词,无需训练自定义词表。
bert_base_uncased google-bert/bert-base-uncased(WordPiece,30,522 词表) 否(禁止) ~15 MB 通用英文文本;启动极快且词表紧凑。
wiki_tocken Snowolf/wiki-tocken(内置英文维基百科词元词典) 是(必需) ~30 MB 配合自定义词干提取器、停用词与同义词使用的英文全文检索。
gemma2b google/gemma-2b(SentencePiece BPE,256k 词表) 否(禁止) ~100 MB 代码、技术标识符以及多语言大语言模型工作负载。

示例:使用 bert_base_uncased 或 llmlingua2

SELECT create_tokenizer('bert_tok', $$
model = "bert_base_uncased"
$$);

SELECT tokenize('VectorChord-BM25 brings Block-WeakAnd to PostgreSQL.', 'bert_tok');

2. 自定义语料库模型(create_custom_model)

为了获得最高的 BM25 相关性精度与最小的内存占用,你可以直接基于自己的业务表列构建自定义词表模型。不同于大语言模型子词分词器(会将罕见的领域专有名词切碎为多个子词元),自定义模型会为 text_analyzer 产出的每个唯一归一化词元分配独立的 1:1 整数 ID,且在内存中仅占用几兆字节。

方式 A:一步到位辅助函数(create_custom_model_tokenizer_and_trigger)

该便捷函数会一步完成创建自定义模型、创建分词器、为所有存量行回填目标 bm25vector 列,并安装一个 BEFORE INSERT OR UPDATE 触发器——当数据行发生变化时,自动学习新词元并更新 bm25vector 列:

-- 1. 定义文本分析流水线
SELECT create_text_analyzer('my_analyzer', $$
character_filters = ["to_lowercase"]
pre_tokenizer = "unicode_segmentation"
token_filters = [
    "skip_non_alphanumeric",
    { stopwords = "nltk_english" },
    { stemmer = "english_porter2" },
]
$$);

-- 2. 创建模型与分词器、回填向量并挂载触发器
SELECT create_custom_model_tokenizer_and_trigger(
    tokenizer_name     => 'my_tokenizer',
    model_name         => 'my_model',
    text_analyzer_name => 'my_analyzer',
    table_name         => 'documents',
    source_column      => 'passage',
    target_column      => 'embedding'
);

方式 B:分步创建(不使用触发器的 create_custom_model)

如果你不希望挂载自动触发器(或者希望自行控制何时计算并回填 embedding 列):

-- 1. 基于现有表列构建自定义词表模型
SELECT create_custom_model('my_model', $$
table = "documents"
column = "passage"
text_analyzer = "my_analyzer"
$$);

-- 2. 创建引用该分析器与自定义模型的分词器
SELECT create_tokenizer('my_tokenizer', $$
text_analyzer = "my_analyzer"
model = "my_model"
$$);

-- 3. 手动回填或刷新词频向量列
UPDATE documents SET embedding = tokenize(passage, 'my_tokenizer');

3. 导入 HuggingFace 分词器(create_huggingface_model)

你可以使用 create_huggingface_model 将任意 HuggingFace tokenizers 的 JSON 配置文件(tokenizer.json)导入 PostgreSQL。

在 psql 中,可以使用 \set 直接从 HuggingFace Hub 下载 tokenizer.json 到变量中并传给 create_huggingface_model:

\set content `wget -q -O - https://huggingface.co/google-bert/bert-base-uncased/resolve/main/tokenizer.json`
SELECT create_huggingface_model('bert_import', :'content');

SELECT create_tokenizer('bert_import_tok', $$
model = "bert_import"
$$);

也可以直接将 tokenizer.json 文件的完整内容作为美元符号引用的字符串传入:

SELECT create_huggingface_model('bge_m3_model', $$
{
  "version": "1.0",
  ...
}
$$);

SELECT create_tokenizer('bge_m3_tok', $$
model = "bge_m3_model"
$$);

4. Lindera 形态学分词模型(create_lindera_model)

对于日文、韩文、中文等需要形态学词典分析的东亚语言,pg_tokenizer 集成了 lindera。

说明

如果你从源码编译 pg_tokenizer,请在编译时通过 --features 启用所需的 Lindera 词典特性:

cargo pgrx install --release --features "lindera-ipadic lindera-ipadic-neologd lindera-unidic lindera-ko-dic lindera-cc-cedict"

以下完整示例展示了基于 ipadic 词典配置日文叠字符(Iteration Mark)规范化、NFKC Unicode 规范化、字符映射、复合词合并、数词归一化、日文停用词性(Stop-tags)过滤、片假名词干提取以及变音符号移除:

SELECT create_lindera_model('japanese_ipadic', $$
[segmenter]
mode = "normal"
  [segmenter.dictionary]
  kind = "ipadic"

[[character_filters]]
kind = "japanese_iteration_mark"
  [character_filters.args]
  normalize_kanji = true
  normalize_kana = true

[[character_filters]]
kind = "unicode_normalize"
  [character_filters.args]
  kind = "nfkc"

[[character_filters]]
kind = "mapping"
  [character_filters.args.mapping]
  "リンデラ" = "Lindera"

[[token_filters]]
kind = "japanese_compound_word"
  [token_filters.args]
  kind = "ipadic"
  tags = [
    "名詞,数",
    "名詞,接尾,助数詞",
  ]
  new_tag = "名詞,数"

[[token_filters]]
kind = "japanese_number"
  [token_filters.args]
  tags = ["名詞,数"]

[[token_filters]]
kind = "japanese_stop_tags"
  [token_filters.args]
  tags = [
    "接続詞",
    "助詞",
    "助詞,格助詞",
    "助詞,格助詞,一般",
    "助詞,格助詞,引用",
    "助詞,格助詞,連語",
    "助詞,係助詞",
    "助詞,副助詞",
    "助詞,間投助詞",
    "助詞,並立助詞",
    "助詞,終助詞",
    "助詞,副助詞/並立助詞/終助詞",
    "助詞,連体化",
    "助詞,副詞化",
    "助詞,特殊",
    "助動詞",
    "記号",
    "記号,一般",
    "記号,読点",
    "記号,句点",
    "記号,空白",
    "記号,括弧閉",
    "その他,間投",
    "フィラー",
    "非言語音",
  ]

[[token_filters]]
kind = "japanese_katakana_stem"
  [token_filters.args]
  min = 3

[[token_filters]]
kind = "remove_diacritical_mark"
  [token_filters.args]
  japanese = false
$$);

SELECT create_tokenizer('jp_tok', $$
model = "japanese_ipadic"
$$);

5. 模型预加载(add_preload_model)

大型模型(如约 200 MB 的 llmlingua2、约 100 MB 的 gemma2b、japanese_ipadic)在每个新建的 PostgreSQL 后端进程首次查询时,需要数秒钟时间和可观的内存来加载。通过在 shared_preload_libraries 启动阶段预加载模型,PostgreSQL 只需在 postmaster 主进程中加载一次模型,即可通过写时复制(Copy-on-Write)内存在所有后端连接之间共享(llmlingua2 默认已加入预加载列表):

-- 将模型加入预加载列表(持久化保存在 $PGDATA/pg_tokenizer/preload_models)
SELECT add_preload_model('my_model');

-- 查看当前已配置的预加载模型列表(默认为 {llmlingua2})
SELECT list_preload_models();

-- 从预加载列表中移除模型(例如不使用 llmlingua2 时可释放约 200 MB 内存)
SELECT remove_preload_model('llmlingua2');

调用 add_preload_model(...) 后(请确保已在 postgresql.conf 中设置 shared_preload_libraries = 'pg_tokenizer.so'),重启 PostgreSQL 即可使预加载对所有后端连接生效。