0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

padrino+PostgreSQLで作ったサイトを高速全文検索対応にする

Last updated at Posted at 2020-11-19

概要

Dockerコンテナ上で動かしているpadrino+postgresqlなサービスに全文検索機能をつけたいとおもった。
ここではpgroongaを用いる。
タイトルに高速といれたのは、同種の機能拡張pg_bigmより早いみたいなので、groongaを選定したことによる。
が、どちらかというと手軽さをとった。

準備

Dockerfileで指定しているpostgresイメージを、pgroongaに変更した。
PostgreSQL向けにpgroongaというgroonga用エクステンションがあることは知っていたが、pgroongaイメージはPostgreSQLを内包しており、差し替えるだけで全文検索対応したPostgreSQLとして利用できる。

docker/pgroonga/Dockerfile
FROM groonga/pgroonga:2.2.6-debian-12
#FROM postgres:12

docker-compose.yamlはdb部分だけは↓みたいな感じ。Windows上でつかっているので、別途 docker volume create --name pgdata1している。

docker-compose.yml
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フォルダに下記のようなスクリプトを配置。

lib/migrate_plugin_add_index.rb
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とかなんとかマイグレーションを作成。

005_add_fulltext_index.rb
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も出してみた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?