概要
Dockerコンテナ上で動かしているpadrino+postgresqlなサービスに全文検索機能をつけたいとおもった。
ここではpgroongaを用いる。
タイトルに高速といれたのは、同種の機能拡張pg_bigmより早いみたいなので、groongaを選定したことによる。
が、どちらかというと手軽さをとった。
準備
Dockerfileで指定しているpostgresイメージを、pgroongaに変更した。
PostgreSQL向けにpgroongaというgroonga用エクステンションがあることは知っていたが、pgroongaイメージはPostgreSQLを内包しており、差し替えるだけで全文検索対応したPostgreSQLとして利用できる。
FROM groonga/pgroonga:2.2.6-debian-12
#FROM postgres:12
docker-compose.yamlはdb部分だけは↓みたいな感じ。Windows上でつかっているので、別途 docker volume create --name pgdata1
している。
version: '2'
services:
db:
build: docker/pgroonga
container_name: pgoongadb
ports:
- "15432:5432"
environment:
- POSTGRES_USER=sa
- POSTGRES_PASSWORD=sa
- POSTGRES_DB=pgdb
volumes:
- pgdata1:/var/lib/postgresql/data
volumes:
pgdata1:
external: true
みてのとおり、Dockerfileを準備するまでもなく postgresをgroonga/pgroongaにしただけである。
(あとでmecab-ipadic-neologdを使うつもりでDockerfileを分けている)
2022.2.20追記:DB構築後にextensionを有効化しておく必要がある
CREATE EXTENSION pgroonga
こまったこと
データベースは上記で準備できた。
しかし、肝心の全文検索むけインデックスをpadrinoでいい感じに作成する方法がわからなかった。
ActiveRecordのadd_indexではチュートリアルにあるようなwith~的な記述が出来ない。
事例を検索してみたが見つからない。ActiveGroongaというのもあったが、それはちょっと違う。
groongaのコミュニティに相談したところ、須藤さんよりredmineでの事例を教えていただく。
またpadrinoでもこうすれば動くよ、というアドバイスもいただき、試した。
解決編
padrinoのプロジェクト内にある、libフォルダに下記のようなスクリプトを配置。
module Migration
module PostgreSQLAdapterOptionable
def add_index_options(table_name, column_name, with: nil, **options)
result = super(table_name, column_name, **options)
result[3] += " WITH (#{with})" if with
result
end
end
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(PostgreSQLAdapterOptionable)
end
上記プラグインを追加した状態で、padrino g migration add_fulltext_indexとかなんとかマイグレーションを作成。
class AddFulltextIndex < ActiveRecord::Migration[5.2]
def self.up
add_index(:contacts, :name, using: 'pgroonga', with: "tokenizer='TokenMecab(\"use_reading\", true)'")
add_index(:contacts, :description, using: 'pgroonga', with: "tokenizer='TokenMecab'")
add_index(:contacts, :tel, using: 'pgroonga', with: "normalizer='NormalizerNFKC100(\"unify_hyphen_and_prolonged_sound_mark\", true)',tokenizer='TokenNgram(\"loose_symbol\", true,\"loose_blank\", true)'")
end
def self.down
end
end
rake db:migrateすると無事、以下のようなSQLが発行され、create indexされた。
add_index(:contacts, :name, {:using=>"pgroonga", :with=>"tokenizer = 'TokenMecab(\"use_reading\", true)'"})
DEBUG - (47.6ms) CREATE INDEX "index_contacts_on_name" ON "contacts" USING pgroonga ("name") WITH (tokenizer = 'TokenMecab("use_reading", true)')
試しにテストデータをつっこんでDataGripのクエリコンソールで、「東京都生まれヒップホップ育ち」みたいなデータを持つカラムに対し検索を実行。正しくおもったとおり動作。
select * from contacts where description &@ '京都' -- > なし
select * from contacts where description &@ '東京' -- > 検索結果 ○
まとめ
- Docker上で動かしているなら、イメージをpostgresからpgroongaにするだけで全文検索対応にできる
- プラグイン用ライブラリを1ファイル置いておけばpadrinoでもadd_indexするmigrationでインデックス作成できる
調べてわからなかったらコミュニティに聞いてみるのも手。場当たり対応でなくrails(ActiveRecord)側にもリクエストしておいたほうがいいかもという話をもらって、添削してもらいつつでissueも出してみた。