🔍

Prisma+PostgreSQLで日本語全文検索を実現する方法

2024/10/25に公開

はじめに

日本語は特有の言語的な問題があり、PrismaやPostgreSQLの標準の全文検索機能だと、なかなか意図した動作をしてくれません。そのため、日本語の全文検索を高速に実現する方法を探している方も多いのではないでしょうか。そこで今回は、その一つの解決策として「pg_bigm」を使った方法をシェアしたいと思います!

この記事では、PrismaとPostgreSQLを使って、日本語の全文検索を効率的に実現するためのアプリを作成する方法を紹介します。この記事や動画をみることで、必要な設定や手順が概要として理解できるかと思います。

https://youtu.be/TowrKeRVaI8

とにかくソースだけ見れたら良い!って人は以下からどうぞ:

https://github.com/craftell/study-prisma-jp-full-text-search

1. 導入と概要

動画はこちら

  • 日本語の特有の言語的な問題により、PrismaやPostgreSQLの標準の全文検索機能では十分な結果が得られないことがあります。
  • 「pg_bigm」を使って、日本語の全文検索を高速に実現する方法を紹介します。
  • PrismaとPostgreSQLを使ったアプリの作成手順を解説し、必要な設定や手順の概要を説明します。

2. Dockerのセットアップ

動画はこちら

  • Dockerを使用してPostgreSQLのセットアップを行います。
  • 公式のpostgresではpg_bigmが含まれていないので、Dockerfileを自作します

3. スキーマとシードの作成

動画はこちら

  • Prismaを使ってデータベースのスキーマを定義し、マイグレーションを実行してサンプルデータを投入します。これにより、全文検索を行うための準備が整います。

Prismaのスキーマはいたってシンプルです(Articleテーブルが一つあるだけ)。

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Article {
  id Int @id @default(autoincrement())
  title String
  body String
}

4. PrismaでPostgreSQLの拡張機能を追加

動画はこちら

  • Prisma経由でPostgreSQLに「pg_bigm」拡張機能を追加します。

preview機能ではあるものの、公式ドキュメントにやり方が書かれています。

https://www.prisma.io/docs/orm/prisma-schema/postgresql-extensions

  • PrismaのSchemaやmigration機能を使ってPostgreSQLの拡張機能を宣言的に定義し、データベースの状態とコードを同期させます。

スキーマは最終的に以下のようになります

generator client {
  provider = "prisma-client-js"
  previewFeatures = ["postgresqlExtensions"] // 追加
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  extensions = [pg_bigm] // 追加
}

model Article {
  id Int @id @default(autoincrement())
  title String
  body String

  @@index([body(ops: raw("gin_bigm_ops"))], type: Gin) // 追加
}

5. データベースへのパフォーマンス検証クエリ

動画はこちら

  • 実際にクエリを実行し、pg_bigmを使ったインデックス設定によるパフォーマンス向上を検証します。
  • シーケンシャルスキャンと比較し、pg_bigmを使うことで劇的に検索スピードが向上することを確認できます。

200万件のデータから1件に絞り込むクエリを実行したときのパフォーマンス

pg_bigram適用時(bitmapscan有効)

強制的にSequential Scanを実行時

6. 簡単な検索アプリの作成

動画はこちら

  • Prismaを使って簡単な検索アプリを作成し、pg_bigmを活用して日本語の全文検索を行います。
  • バイグラムの仕組みにより、日本語の文章でも精度の高い検索が可能になります。

実装したコード

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient({
  log: ['query'],
});

export async function searchArticles(
  keyword1: string,
  keyword2: string,
  keyword3: string,
  keyword4: string,
  keyword5: string
) {
  // await prisma.$queryRawUnsafe('SET enable_bitmapscan TO off;');
  console.time('searchArticles');
  const articles = await prisma.article.findMany({
    where: {
      AND: [
        { body: { contains: keyword1 } },
        { body: { contains: keyword2 } },
        { body: { contains: keyword3 } },
        { body: { contains: keyword4 } },
        { body: { contains: keyword5 } },
      ],
    },
  });
  console.timeEnd('searchArticles');
  // await prisma.$queryRawUnsafe('SET enable_bitmapscan TO on;');

  console.log(`Found ${articles.length} articles`);
  return articles;
}

searchArticles('めいしょ', '騎兵', 'せいめい', '誇張', '栄誉');

pg_bigm有効時(bitmapscan有効)

強制的にSequential Scanを実行時

7. まとめ

動画はこちら

  • PrismaとPostgreSQLで日本語の全文検索を効率的に行うには、pg_bigmを使ったインデックスの設定が非常に有効
    • 日本語特有の単語区切りの問題を克服し、高速な検索を実現することができる
  • Prismaの宣言的なスキーマやmigration機能を活用することで、データベースの状態をコードベースで管理できるため、拡張機能の追加やインデックスの管理も非常に簡単

Discussion