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?

プリザンターのPostgreSQL全文検索を見直す ― pg_bigmの導入方法(Windows・AlmaLinux・Docker)

0
Posted at

はじめに

プリザンターでレコードが増えてくると、全文検索に時間がかかることがあります。PostgreSQLを使っているなら、日本語の部分一致検索を高速化できる拡張機能のpg_bigmが候補になります。

ただし、プリザンターの標準検索は、pg_bigmをインストールするだけでは高速化できません。 検索に使う演算子とインデックスの組み合わせを確認する必要があります。

この記事では、まず標準検索との関係を整理し、そのうえで次の3パターンの導入方法と、インデックスの効果を確かめるSQLを紹介します。

  • WindowsオンプレミスのPostgreSQL
  • AlmaLinuxオンプレミスのPostgreSQL
  • Dockerで動かすPostgreSQL

プリザンターの実装確認はバージョン1.5.8.1を対象にしています。Dockerの手順と検証用SQLは、PostgreSQL 17.11・pg_bigm 1.2(v1.2-20250903)で実行しました。Windows・AlmaLinuxのオンプレミス手順は配布元資料に基づく手順例で、実機での動作確認は未実施です。プリザンターの画面検索を高速化した実測結果ではありません。

最初に、プリザンターが使っている検索方式を確認する

標準のフルテキスト検索はpg_trgmを使う

プリザンター1.5.8.1では、PostgreSQLのフルテキストインデックスを次のSQLで作成しています。

App_Data/Definitions/Sqls/PostgreSQL/CreateFullText.sql
create index if not exists "ftx" on "Items" using gin ("FullText" gin_trgm_ops);

プリザンターのインデックス作成SQL

gin_trgm_opsは、3文字のまとまりを使う拡張機能pg_trgmの演算子クラスです。演算子クラスは、インデックスでどのような比較を扱うかを定義します。

検索条件を組み立てる実装では、"Items"."FullText" %> 検索語という形を使います。%>はpg_trgmの語の類似度による判定で、LIKE '%検索語%'による部分一致とは検索の意味が異なります。検索条件の実装、PostgreSQLの演算子の説明

また、通常の部分一致用のSQLにはILIKEを使います。こちらも、pg_bigmのLIKE用インデックスをそのまま利用する条件にはなりません。部分一致演算子の実装

検索条件 対応するインデックスの例 pg_bigm導入時の扱い
標準フルテキスト検索の%> gin_trgm_ops 標準インデックスを維持する
通常の部分一致検索のILIKE gin_trgm_ops gin_bigm_opsへの単純置き換えはできない
独自SQLのLIKE gin_bigm_ops pg_bigmによる高速化を検証できる

ftxを削除してgin_bigm_opsで作り直しても、標準検索の%>には対応しません。pg_trgmと既存のftxは残してください。pg_bigm 1.2とpg_trgmは同じDBで共存できます。

標準検索を速くしたい場合の確認順序

最初に、プリザンターが接続しているDBでインデックスを確認します。

SELECT schemaname, indexname, indexdef
FROM pg_indexes
WHERE tablename = 'Items';

FullText列に対するgin_trgm_opsのインデックスがあるか確認します。名前だけで判断せず、定義も見てください。

公式マニュアルでは、初期構築時のプリザンターが1.4.6以前の場合、後からバージョンアップしてもフルテキストインデックスの生成手順が必要と説明されています。該当する環境は、まずPostgreSQL フルテキストインデックスを生成するの手順を確認してください。

そのうえで、遅い操作で発行されるSQLの実行計画、データ量、検索語、統計情報を調べます。標準検索の改善と、独自のLIKE検索へのpg_bigm導入を切り分けると、対策を選びやすくなります。

pg_bigmの導入で行うこと

pg_bigmは文字列を2文字ずつのまとまりに分け、GINインデックスに登録します。GINは、文字のまとまりから、それを含むレコードを探すための索引です。日本語の短い検索語を含む部分一致検索で効果を期待できますが、速くなるかどうかは検索語やヒット件数にも左右されます。pg_bigm公式ドキュメント

導入は次の3段階です。

  1. PostgreSQLサーバにライブラリと拡張定義ファイルを配置する。
  2. 利用するDBごとにCREATE EXTENSION pg_bigmを実行する。
  3. 検索対象の列にgin_bigm_opsのインデックスを作成する。

配置先はDBサーバです。 プリザンターのWebサーバとDBサーバを分けている場合、Webサーバにファイルを置いてもDB側では使えません。

以下はPostgreSQL 17を例にします。既存環境ではメジャーバージョンを合わせ、設定変更・インデックス作成前にDBと設定ファイルのバックアップを取得してください。

Windowsオンプレミスに導入する

1. Windows向けのビルドを用意する

上流のpg_bigm公式ドキュメントが挙げる動作確認OSはLinuxとmacOSです。Windowsでは、別の開発者によるHiraokaHyperTools/pg_bigmのWindows向け配布を利用する方法があります。

同リポジトリのREADMEでは、PostgreSQL 9.6~18.0向けの配布と、20260107.7zの展開・コピー手順が案内されています。利用するPostgreSQLのメジャーバージョンとCPUアーキテクチャに合うフォルダを選びます。

このWindows向けバイナリは、上流のpgbigm/pg_bigmプロジェクトが配布する公式Windowsパッケージではありません。採用前に配布元、含まれるソースの版、依存ランタイム、運用中のPostgreSQLとの組み合わせを確認してください。上流の同名バージョンと修正内容が同じとは限りません。

2. PostgreSQLの配置先を確認してコピーする

PowerShellでPostgreSQLのパスを確認します。以下は標準的な配置例です。

$pgRoot = 'C:\Program Files\PostgreSQL\17'
& "$pgRoot\bin\pg_config.exe" --version
& "$pgRoot\bin\pg_config.exe" --pkglibdir
& "$pgRoot\bin\pg_config.exe" --sharedir

管理者権限で、配布アーカイブ内のPostgreSQL 17・x64向けフォルダの中身を$pgRootへ、ディレクトリ構造を保ってコピーします。主な配置先は次のとおりです。

ファイル 配置先の例
pg_bigm.dll C:\Program Files\PostgreSQL\17\lib
pg_bigm.control C:\Program Files\PostgreSQL\17\share\extension
pg_bigm--*.sql C:\Program Files\PostgreSQL\17\share\extension

既に読み込み済みのDLLを更新する場合は、対象のPostgreSQLサービスを停止してから差し替えます。

3. プリロードを設定してDBに登録する

psqlまたはpgAdminで、接続先サーバの設定ファイルと既存値を確認します。

SHOW config_file;
SHOW shared_preload_libraries;

本記事では上流ドキュメントのプリロード方式に合わせます。確認したpostgresql.confで、既存のライブラリを残してpg_bigmを追加します。次は既存値が空の場合の例です。

postgresql.conf
shared_preload_libraries = 'pg_bigm'

既にpg_stat_statementsがある場合は、'pg_stat_statements,pg_bigm'のように併記します。管理者PowerShellでサービス名を確認し、対象だけを再起動します。

Get-Service -Name '*postgres*'
# 実際のサービス名に合わせて変更する
Restart-Service -Name 'postgresql-x64-17'

続いて対象DBに接続します。DB名は環境に合わせて変更してください。

& "$pgRoot\bin\psql.exe" -h localhost -U postgres -d 'Implem.Pleasanter'

接続後、後述の「共通:対象DBに登録する」を実行します。

AlmaLinuxオンプレミスに導入する

1. PostgreSQLと開発用ファイルをそろえる

ここでは、AlmaLinux 9・x86_64にPGDG版PostgreSQL 17が導入済みであることを前提にします。PGDGはPostgreSQLプロジェクトが提供するパッケージリポジトリです。PostgreSQL公式のRed Hat系向け導入案内

OS標準パッケージとPGDG版では、パッケージ名・配置先・サービス名が異なります。既存DBに対してinitdbを実行する必要はありません。

/usr/pgsql-17/bin/pg_config --version
sudo dnf install -y gcc make git postgresql17-devel

開発用パッケージの依存関係が見つからない場合は、利用中のAlmaLinuxの版に対応するCRB等のリポジトリ設定を確認します。別バージョンの開発用パッケージで代用しないでください。

2. ソースからビルドして配置する

新しい作業ディレクトリで、使用するリリースを固定して取得します。

git clone --depth 1 --branch v1.2-20250903 \
  https://github.com/pgbigm/pg_bigm.git
cd pg_bigm

make USE_PGXS=1 PG_CONFIG=/usr/pgsql-17/bin/pg_config
sudo make USE_PGXS=1 PG_CONFIG=/usr/pgsql-17/bin/pg_config install

PG_CONFIGは、拡張を導入するPostgreSQLと同じ版のコマンドを指定します。ビルドにはPostgreSQLの拡張用ビルド環境であるPGXSを使います。pg_bigmのビルド手順

3. プリロードを設定する

接続先の設定ファイルと現在値を確認します。

sudo -u postgres /usr/pgsql-17/bin/psql -d postgres \
  -c 'SHOW config_file;' -c 'SHOW shared_preload_libraries;'

確認したpostgresql.confに、Windowsの例と同じ要領でpg_bigmを追加します。既存値が空の場合は次の設定です。

postgresql.conf
shared_preload_libraries = 'pg_bigm'

サービスを再起動し、対象DBへ接続します。

sudo systemctl restart postgresql-17
sudo systemctl status postgresql-17 --no-pager
sudo -u postgres /usr/pgsql-17/bin/psql -d 'Implem.Pleasanter'

後述の共通手順で拡張を登録します。

Dockerに導入する

1. 拡張を含むDBイメージをビルドする

実行中のコンテナ内だけに追加すると、コンテナの作り直しでファイルが失われます。pg_bigmを含むPostgreSQLイメージを作成します。

以下はDebianベースのpostgres:17-bookworm用です。Alpineベースではビルド環境やCライブラリが異なるため、この成果物をそのままコピーしないでください。

Dockerfile
FROM postgres:17-bookworm AS builder
ARG PG_BIGM_VERSION=v1.2-20250903
RUN apt-get update \
    && apt-get install -y --no-install-recommends build-essential ca-certificates git postgresql-server-dev-17 \
    && git clone --depth 1 --branch "${PG_BIGM_VERSION}" https://github.com/pgbigm/pg_bigm.git /src/pg_bigm \
    && make -C /src/pg_bigm USE_PGXS=1 PG_CONFIG=/usr/lib/postgresql/17/bin/pg_config \
    && make -C /src/pg_bigm USE_PGXS=1 PG_CONFIG=/usr/lib/postgresql/17/bin/pg_config DESTDIR=/stage install

FROM postgres:17-bookworm
COPY --from=builder /stage/ /

ビルド段階で生成した拡張ファイルだけを実行用イメージへコピーします。本番運用では、検証したベースイメージのdigestも記録・固定すると、再ビルド時の差を管理しやすくなります。

2. 独立した検証用DBを起動する

次のComposeは新規の検証用DBです。プリザンター本体や既存DBの移行は含みません。

compose.yaml
services:
  db:
    build: .
    image: qiita-pg-bigm:17
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}
      POSTGRES_DB: bigm_lab
    command: ["postgres", "-c", "shared_preload_libraries=pg_bigm"]
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d bigm_lab"]
      interval: 5s
      timeout: 5s
      retries: 12
volumes:
  pgdata:

同じディレクトリに.envを作成し、POSTGRES_PASSWORDへ自分で決めたパスワードを設定します。.envはGit管理から除外してください。

.env
POSTGRES_PASSWORD=ここを自分のパスワードに置き換える
docker compose up -d --build --wait
docker compose exec db psql -U postgres -d bigm_lab

起動後に共通手順で拡張を登録します。Windowsホストから実行する場合も、このイメージはLinuxコンテナとして動かします。

既存DBに適用するときは、そのDBと同じPostgreSQLメジャーバージョンでイメージを作成します。メジャーバージョンの異なるデータボリュームを付け替えてもDBのアップグレードにはなりません。また、既存のshared_preload_librariesの値は保持してください。

公式イメージのPOSTGRES_DBや/docker-entrypoint-initdb.dによる初期化は、データディレクトリが空のときに実行されます。既存ボリュームでは、対象DBに接続して拡張登録を実行してください。PostgreSQL公式Dockerイメージの説明

プリザンターのDBをCodeDefinerで新規作成する構成では、DB作成後に実際のプリザンター用DBへ拡張を登録します。postgresや検証用のbigm_labに登録しただけでは、別DBであるプリザンター用DBでは利用できません。

共通:対象DBに登録する

対象DBに管理者権限で接続し、配置とプリロードを確認します。

SELECT current_database(), version();
SHOW shared_preload_libraries;

SELECT name, default_version, installed_version
FROM pg_available_extensions
WHERE name = 'pg_bigm';

CREATE EXTENSION IF NOT EXISTS pg_bigm;

SELECT extname, extversion
FROM pg_extension
WHERE extname IN ('pg_bigm', 'pg_trgm');

pg_available_extensionsに表示されるのは、サーバが拡張の定義ファイルを見つけられる状態です。pg_extensionに表示されて、初めて接続中のDBに登録されています。

インデックスの効果をSQLで確かめる

1. 検証データを作る

本番のプリザンター用テーブルを変更せず、検証用DBで試します。10万件のうち100件に「東京」を含むデータです。

CREATE TABLE bigm_demo (
    id integer PRIMARY KEY,
    body text NOT NULL
);

INSERT INTO bigm_demo
SELECT n,
       CASE WHEN n % 1000 = 0
           THEN '東京都の契約書 ' || n
           ELSE '大阪府の請求書 ' || n
       END
FROM generate_series(1, 100000) AS n;

ANALYZE bigm_demo;

EXPLAIN (ANALYZE, BUFFERS)
SELECT id FROM bigm_demo
WHERE body LIKE likequery('東京');

likequery()は、入力を部分一致用のパターンに変換し、%や_なども文字として検索できるようエスケープする関数です。アプリケーションから使う場合、検索語は別途SQLパラメータで渡してください。

2. GINインデックスを作成して比較する

CREATE INDEX bigm_demo_body_idx
ON bigm_demo USING gin (body gin_bigm_ops);

ANALYZE bigm_demo;

EXPLAIN (ANALYZE, BUFFERS)
SELECT id FROM bigm_demo
WHERE body LIKE likequery('東京');

SELECT count(*) FROM bigm_demo
WHERE body LIKE likequery('東京');

今回のDocker検証では、次の結果になりました。

条件 実行計画の主な処理 取得件数 実行時間
インデックス作成前 Seq Scan 100件 7.013 ms
インデックス作成後 Bitmap Index ScanとBitmap Heap Scan 100件 0.165 ms

これは小さな検証データでの単回測定です。プリザンターの画面表示時間や実データで同じ改善率になることを示すものではありません。評価時は同じ条件で複数回実行し、キャッシュの影響や更新処理の負荷も確認してください。

3. 検索条件が違うと効果も変わる

同じDBでpg_trgmも登録し、条件を変えてみます。

CREATE EXTENSION IF NOT EXISTS pg_trgm;

EXPLAIN
SELECT id FROM bigm_demo WHERE body ILIKE '%東京%';

EXPLAIN
SELECT id FROM bigm_demo WHERE body %> '東京';

今回の検証では、どちらもSeq Scanでした。gin_bigm_opsを作っても、この2つの条件を処理するインデックスにはなりません。これが、プリザンターの標準検索をインデックスの差し替えだけで高速化できない理由です。

大文字・小文字を区別しない独自検索を設計する場合は、たとえばlower(body)の式にインデックスを作り、検索側もlower(body) LIKE likequery(lower(検索語))にそろえる方法があります。ただし、照合順序なども含めて、既存のILIKEと同じ結果になるか検証が必要です。

プリザンターで活用する際の判断ポイント

標準検索への組み込みは別の改修になる

この記事で確認したのは、pg_bigmの導入とLIKE検索の高速化です。標準検索をpg_bigmで処理するには、検索SQLやインデックス管理の変更が必要で、標準設定の切り替えだけでは完了しません。

独自検索を実装する場合も、次の点を確認します。

  • LIKEへの変更で、類似検索・英字の大小・複数語・否定条件の結果がどう変わるか。
  • 検索結果にプリザンターのテナント境界とレコードのアクセス権を適用できているか。
  • レコード更新時に検索対象データが更新されるか。
  • CodeDefinerやバージョンアップ後に、独自インデックスが維持されるか。

Rds.jsonには手動インデックスを扱うためのDisableIndexChangeDetectionがあります。ただし、これはインデックスの差異検出を抑制する設定で、検索をpg_bigmへ切り替える設定ではありません。標準のインデックス更新にも影響するため、独自インデックスの保守方針と合わせて判断します。Rds.jsonの公式説明

検索以外の負荷も確認する

GINインデックスにはディスク容量と更新コストがかかります。大量インポートや頻繁な更新がある環境では、検索時間だけでなく、登録・更新時間も比較します。

ヒットする割合が大きい場合やテーブルが小さい場合は、インデックスがあってもSeq Scanが選ばれることがあります。インデックス利用の有無だけでなく、実行時間・読み取ったページ数・検索結果の一致を確認してください。

うまく動かないときの確認箇所

症状 確認すること
extension "pg_bigm" is not available 接続先DBサーバの拡張ディレクトリにpg_bigm.controlとSQLがあるか
共有ライブラリやDLLを読み込めない PostgreSQLのメジャーバージョン、CPUアーキテクチャ、配置先、依存ライブラリが合っているか
設定変更後にPostgreSQLが起動しない サーバログを確認し、プリロード指定と実際のライブラリ配置を照合する
gin_bigm_opsが見つからない 接続中のDBにCREATE EXTENSION済みか、拡張を配置したスキーマが検索パスにあるか
インデックスが使われない 条件がLIKEか、対象列・式が一致しているか、統計情報が更新されているか
コンテナ再作成で拡張が使えなくなった 実行用イメージに拡張ファイルが含まれているか

EXPLAIN ANALYZEは実際にSQLを実行します。本番で重い検索を調べる際は、実行する時間帯と負荷を考慮してください。

まとめ

  • プリザンター1.5.8.1の標準フルテキスト検索はpg_trgmと%>を使います。まず標準インデックスftxの有無と実行計画を確認します。
  • pg_bigmの導入は、Windowsでは対応バイナリの配置、AlmaLinuxでは対応する開発環境でのビルド、Dockerでは拡張を含むイメージの作成が基本です。
  • 拡張のファイル配置・対象DBへの登録・対応するインデックスの作成は、それぞれ別の作業です。
  • pg_bigmによるLIKE検索の高速化を検証できましたが、プリザンターの標準検索に組み込むには、検索仕様とアプリケーション側の対応を含めた検討が必要です。
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?