如何用 PostgreSQL 的 to_tsvector 与 GIN 索引在 Rails 中实现全文搜索
【免费下载链接】railsRuby on Rails项目地址: https://gitcode.com/GitHub_Trending/rai/rails
如果你的 Rails 应用使用 PostgreSQL 作为数据库,希望按自然语言关键词检索文本字段(而不是用LIKE '%...%'逐行匹配),Rails 官方指南在 Active Record and PostgreSQL 中给出了完整做法:在迁移里用to_tsvector表达式创建 GIN 索引,再用@@ to_tsquery在模型查询中做全文匹配。本文按指南原文给出两条可执行路径——对表达式直接建索引,以及在 PostgreSQL 12.0 以上版本改用存储的生成列——并说明各自的适用条件和验证方式。
前提条件
- 应用已按 配置 Rails 指南的 PostgreSQL 部分完成数据库配置,
config/database.yml中adapter为postgresql,例如:
development: adapter: postgresql encoding: unicode database: blog_development max_connections: 5- PostgreSQL 版本至少为 10.0,更低版本不被 PostgreSQL adapter 支持;
- 如果使用下文“生成列”方案,还需要 PostgreSQL 12.0 及以上版本(generated columns 从 12.0 开始支持)。
主路径:用 to_tsvector 表达式创建 GIN 索引
指南中的示例场景是一个带title和body文本字段的documents表。对应的迁移如下(文件路径取自文档示例,时间戳按你实际生成时的命名替换):
# db/migrate/20131220144913_create_documents.rb create_table :documents do |t| t.string :title t.string :body end add_index :documents, "to_tsvector('english', title || ' ' || body)", using: :gin, name: "documents_idx"这里to_tsvector('english', title || ' ' || body)把标题和正文拼在一起转成 tsvector,using: :gin指定用 GIN 索引加速后续的全文匹配。模型本身不需要特殊声明:
# app/models/document.rb class Document < ApplicationRecord end应用迁移:
$ bin/rails db:migrate写入数据并执行全文查询
迁移完成后,即可按指南给出的用法写入数据并查询(以下值为文档示例):
# 写入 Document.create(title: "Cats and Dogs", body: "are nice!") # 所有同时匹配 'cat' 与 'dog' 的文档 Document.where("to_tsvector('english', title || ' ' || body) @@ to_tsquery(?)", "cat & dog")验证方式:进入bin/rails console,执行上面的where查询,返回的ActiveRecord::Relation中应包含命中查询词的记录(例如刚创建的这条文档示例数据)。查询词用to_tsquery的参数表达,&表示逻辑与;'english'这个 text search configuration 在索引表达式和查询表达式中保持文档示例的写法即可。
可选方案:存储的生成列(PostgreSQL 12.0 及以上)
如果数据库版本满足 12.0 以上,指南提供了替代写法:把 tsvector 存成自动维护的生成列,再对列本身建 GIN 索引:
# db/migrate/20131220144913_create_documents.rb create_table :documents do |t| t.string :title t.string :body t.virtual :textsearchable_index_col, type: :tsvector, as: "to_tsvector('english', title || ' ' || body)", stored: true end add_index :documents, :textsearchable_index_col, using: :gin, name: "documents_idx" # Usage Document.create(title: "Cats and Dogs", body: "are nice!") ## all documents matching 'cat & dog' Document.where("textsearchable_index_col @@ to_tsquery(?)", "cat & dog")与主路径的区别在于:t.virtual ... stored: true会把 tsvector 物化为一个真实的列,索引建在列上(add_index :documents, :textsearchable_index_col, ...),查询条件也不再重复写表达式,而是直接引用列名textsearchable_index_col @@ to_tsquery(?)。验证方式同上:写入示例数据后,在bin/rails console中执行该where查询,检查返回的记录是否命中。
适用边界
- 两条路径都依赖
to_tsvector/to_tsquery与 PostgreSQL 全文检索能力,不适用于其他数据库 adapter;本文只覆盖 PostgreSQL。 - 主路径对任意 PostgreSQL 10.0+ 可用;生成列路径要求 12.0 及以上,版本不满足时请只用第一种写法。
- 指南原文未给出性能对比或查询结果的固定输出,以上命令的输出以你实际数据库中的数据为准。
更多 PostgreSQL 专属用法(数组、JSONB、UUID 主键、索引选项等)可继续阅读 guides/source/active_record_postgresql.md;数据库连接配置的完整选项见 guides/source/configuring.md 中的 “Configuring a PostgreSQL Database” 一节。
【免费下载链接】railsRuby on Rails项目地址: https://gitcode.com/GitHub_Trending/rai/rails
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考