MisskeyにPGroongaを導入してAND/OR/NOT検索を行う&cwも検索に含める

Ubuntu22.04LTS / PostgresSQL15 / Misskey v13.14.2

※2023/09/26更新 Misskey内で完結するように割と修正

Misskey内の検索を強化したいもののMeilisearchの形態素分析がいまいちで検索したい語が探せない(「あんぱん」で「あんぱんまん」がヒット出来ない)ので、PostgresSQL拡張の日本語全文検索拡張PGroongaの導入メモです。

またnote.textだけでなくnote.cwの注意書き部分も検索範囲にします。

PGroongaを使って自鯖のMisskeyで快適にエゴサする tamainaさんの記事を参考にさせて頂いています。

続きを読む

PGroongaを追加したPostgresDBをコンテナを作成

PGroonga入りのPostgreSQLのDockerfileを作成してMisskeyのDocker composeに導入します。

PGroongaのDockerfileの作成

misskeyフォルダ内にpg.Dockerfileを作成します

pg.Dockerfile

FROM postgres:15-bookworm

# Add Tini
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

# PGroonga install
ENV PGROONGA_VERSION=3.1.1-1
RUN \
    apt update && \
    apt install -y -V wget && \
    wget https://apache.jfrog.io/artifactory/arrow/debian/apache-arrow-apt-source-latest-bookworm.deb && \
    apt install -y -V ./apache-arrow-apt-source-latest-bookworm.deb && \
    rm apache-arrow-apt-source-latest-bookworm.deb && \
    wget https://packages.groonga.org/debian/groonga-apt-source-latest-bookworm.deb && \
    apt install -y -V ./groonga-apt-source-latest-bookworm.deb && \
    rm groonga-apt-source-latest-bookworm.deb && \
    apt update && \
    apt install -y -V \
    postgresql-15-pgdg-pgroonga=${PGROONGA_VERSION} \
    groonga-normalizer-mysql \
    groonga-token-filter-stem \
    groonga-tokenizer-mecab && \
    apt clean && \
    rm -rf /var/lib/apt/lists/*

CMD ["docker-entrypoint.sh", "postgres"]

適当なpgroongaフォルダにDockerfileという名前のファイルを作成し、PGroonga/Docker から適切なDockerfileを選んで内容をコピペで貼り付け、下記コマンド実行でコンテナイメージを作成します

Misskeyの設定

Misskeyのdocker-compose.ymlの更新

Misskeyのフォルダに移動し、docker-compose.ymlのPostgreSQLのイメージ欄を変更します

  db:
    restart: always
    image: misskey-db:latest       ←変更
    build:                         ←追加
      context: .                   ←追加
      dockerfile: pg.Dockerfile    ←追加
// 以下略

マイグレーションファイルの作成

データベースにインデックスを追加します。巻き戻しが効くようにTypeORMのマイグレーションファイルを作成して適用します。

note.textカラムとnote.cwカラムに適用します。複数のカラムにまたがったインデックスを使用します。精度を上げるなら各カラムのインデックスも作った方が良いかも(容量は食いますがおひとりさま用サーバーなので…)

念のためこの段階でDBのバックアップは取っておくこと。

sudo docker compose run --rm web pnpm dlx typeorm migration:generate -d ./packages/backend/ormconfig.js ./packages/backend/migration/AddPgroongaIndexes

…でマイグレーションファイルを作成しようとしたらDockerコンテナ内なのですぐ消えてしまうのでありました…。(それはそう)

代わりに/packages/backend/migration/1691850149834-AddPgroongaIndexes.jsファイルを手動で作成して以下を入力(タイムスタンプは↑で失敗したときのを流用)

export class AddPgroongaIndexes1691850149834 {
    name = 'AddPgroongaIndexes1691850149834'
    async up(queryRunner) {
        await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS pgroonga;`);
        await queryRunner.query(`CREATE INDEX idx_note_text_cw_pgroonga ON note USING pgroonga(text, cw);`);
    }
    async down(queryRunner) {
        await queryRunner.query(`DROP INDEX idx_note_text_cw_pgroonga;`);
    }
}

下記を実行してDBのマイグレーションを行います。

sudo docker compose build
sudo docker compose run --rm web pnpm migrate
// 上手く行かなかったらこちらで
// sudo docker compose run --rm web pnpm run init

Misskey本体の書き換え

ユーザー検索には適用せずノート検索だけに利用するのでNote絡みの部分のみ変更します。

packages/backend/src/models/entities/Note.ts

10行目付近、インデックスを追加させます

@Entity('note')
@Index('idx_note_text_cw_pgroonga', ['text', 'cw'], { using: 'pgroonga' })
export class Note {
    // ~~ 以下略 ~~

packages/backend/src/core/SearchService.ts

185行目付近のelseブロック付近、ILIKE検索部を&@~演算子に書き換え、CWも検索範囲に

			query
				.andWhere('(note.text &@~ :q OR note.cw &@~ :q)', { q: q })

PGroonga拡張の「&@~」演算子を使うことで「AB CB」や「A OR B」のような検索が行えるようになります。

あとは通常通りビルドすると完了です🎉

できたよ~~

AND検索

OR検索

NOT検索(除外検索)

CWの注釈もヒット

日本語全文高速検索になるとどの程度かわかりませんが、とりあえずおひとりさま用サーバーで簡易的にAND/OR/NOT検索が付けられるのは嬉しいです。YATTA~~🌸

とりあえずは目的完了です。

課題点

上記だとcwとtextに跨がったAND検索は出来ない(cwに「ひよこ」textに「にわとり」を「ひよこ にわとり」でヒットできない)ので、この辺はsearchNoteメソッドをもうちょっと弄りたいかもです。

追記

PostgreSQLのDockerfileを作ってMisskeyと一緒にビルドするようにしました。docker-compose.ymlの下記をimageから書き換えしておくこと。

  db:
    restart: always
    build:
      context: .
      dockerfile: Dockerfile-pg
    networks:
      - internal_network