Docusaurus v3 の全文検索を DuckDB Wasm + FTS 拡張で実装した

こんにちは。ソフトウェアエンジニアの id:masutaka26 です。

ROUTE06 では全社ワークスペースに GitHub を利用しています。

note.route06.co.jp

ストック情報としての社内ドキュメントは GitHub Pages で社内限定で公開されており、静的サイトジェネレーターとして Docusaurus を利用しています。

検索精度への課題

今までは Docusaurus の Community plugins でも紹介されている @easyops-cn/docusaurus-search-local を使用していました。

フロントエンドだけで動作し、設定もお手軽なのは良いのですが、検索精度に難があり、一部ではリポジトリを clone して手元で grep することが常態化していました。

参考までに docusaurus.config.js の設定内容です。

  themes: [
    [
      require.resolve("@easyops-cn/docusaurus-search-local"),
      /** @type {Partial<import("@easyops-cn/docusaurus-search-local").PluginOptions>} */
      ({
        hashed: true,
        language: ["en", "ja"],
      }),
    ],
  ],

リポジトリをざっと眺めた限りでは、検索精度が上がりそうなオプションは見当たりません。日本語だと removeDefaultStopWordFilter, zhUserDict, zhUserDictPath は関係なさそうです。

DuckDB Wasm で検索フォームを実装した

今回 DuckDB をリサーチする機会があったため、成果物として DuckDB Wasm で検索フォームを実装しました。以下がサンプルコードです。デモサイトもあります。

github.com

正式な Docusaurus の plugin として作ったわけではないため、あくまでサンプルコードとして参考になれば幸いです。

DuckDB とは

DuckDB は OSS であり、軽量で高速な列指向のデータベースです。SQLite と似ていますが、SQLite は行指向データベースです。

DuckDB では Wasm も提供されており、フロントエンドのみで DuckDB を動作させることが出来ます1

Core Extension も FTS (Full-Text Search) や VSS (Vector Similarity Search) などを利用可能です。

検索フォームの実装概要

実装は素朴です。

  1. デプロイ前に static/docs.json を生成する

     npm run collect-docs
    
  2. デプロイされると GitHub Pages の /docs.json として配置される

  3. /search/ を訪問すると、CDN 上の DuckDB Wasm を読み込み、DuckDB を初期化する
    1. DuckDB fts 拡張のインストール&ロード
    2. /docs.json を読み込み、DuckDB 内の docs.json として登録
    3. documents テーブルの作成
    4. DuckDB 内の docs.json を documents テーブルに一括挿入
    5. documents テーブルのインデックス作成
  4. 作成したインデックスに対して、検索 (SELECT) を実行する

後述する PoC でわかち書きも検討しましたが、社内ドキュメント 500 記事程度だと、そこまで検索精度が変わらなかったので、現在は導入していません。

PoC で検討したこと

検索フォーム実装前に PoC (Proof of Concept) として、以下の検索を検討しました。前述のリポジトリ poc/ に、実際に動作するコードがあります。

  • 全文検索
  • 日本語全文検索(わかち書き版)
    • 検索対象のドキュメントは予め Lindera CLI でわかち書き
    • 検索クエリは Lindera Wasm でわかち書き
  • ベクトル検索
    • 要 OpenAI API キー

最終的に、わかち書きなしの「全文検索」を採用しました。CLI 版と Wasm 版の Lindera を Docusaurus に組み込む手間の割に、そこまで検索精度が変わらなかったからです。

まとめ

Docusaurus v3 の全文検索を DuckDB Wasm + FTS 拡張で実装し、検索精度の課題を解決することが出来ました。

DuckDB も Wasm も初見で、初めは全く分からない状態でしたが、Claude Code のおかげでなんとか形になりました。

DuckDB Wasm を使うと、フロントエンドのみでデータベースを構築できます。MySQL や BigQuery と違って、権限を気にしなくて済むため、今回のような小規模のデータには最適だと感じました。

検索対象が増えると、わかち書きを含めた検索精度のチューニングが必要になりそうですが、今は必要なさそうです。

参考


  1. SQLite も Wasm 版が提供されているようです