全文検索

更新

SQLite FTS5 を使った全文検索の仕組みと、インデックスの再構築タイミング。

md2docs はサイト内全文検索を標準で備えています。検索エンジンや別サービスを用意せず、SQLite の FTS5 拡張で完結しています。

使い方

ヘッダ右側の 🔍 アイコン をクリックして検索ページに移動するか、/search?q=... に直接アクセスします。

  • キーワード: スペース区切りで複数語を入れると AND 検索 になります(例: インストール 動作確認
  • 検索対象: タイトル / 説明 (description) / 本文 / タグ
  • ハイライト: 結果のスニペット内でヒット箇所が <mark> で強調されます

キーボードショートカット

任意のページから検索ページの入力欄に飛べるショートカットを用意しています。

キー 動作
/ 検索ページへ遷移 → 入力欄にフォーカス(入力中フィールドでは無効)
⌘K / Ctrl+K 入力中でも検索ページへ遷移 → 入力欄にフォーカス

すでに /search を開いている場合は、ページ遷移ではなく入力欄に直接フォーカスが当たります。入力済みの語句に追記しやすいよう カーソルは自動的に末尾 に置かれます。

インデックスの仕組み

検索インデックスは var/fts.sqlite という SQLite データベースに保存されます。

項目 内容
エンジン SQLite FTS5(要 SQLite 3.20+)
トークナイザ unicode61(デフォルト同梱)+ PHP 側で 3-char トリグラムを生成
ランキング BM25 — title 5x / tags 3x / description 2x / body 1x
false positive 対策 trigram-AND マッチ後に PHP 側で「ユーザー原文」が実際に含まれるか確認

メモ

SQLite には 3.34 から trigram という専用トークナイザが追加されていますが、共有ホスティング (XSERVER の SQLite 3.26 等) では使えません。md2docs は どこでも動く ことを優先して PHP 側でトリグラムを生成し、unicode61 で索引する方式にしています。新しい SQLite でも問題なく動作します。

自動再構築

リクエスト時に contents/ 配下の .md ファイルの mtime をチェックし、最後にインデックスを作った時刻より新しい記事があれば自動で再構築します。記事を更新したら、何も操作しなくても次のアクセスで反映されます。

メモ

12 記事程度のサイトでビルドは数 ms 〜 10 ms 程度です。記事数が数百を超える規模になると、初回アクセスのレイテンシが気になる場合があります。その場合は次の手動リビルドをデプロイ後に走らせるとよいでしょう。

手動リビルド

何らかの理由でインデックスを強制的に作り直したい場合は CLI を使います。

php bin/build-search-index.php

デプロイ後の予熱や、トラブルシュート時にインデックスをまっさらにしたい時に使ってください。

サーバ環境の事前チェック

共有ホスティングへデプロイした直後、SQLite と FTS5 が想定どおり動くか確認したい場合は public/check-search-env.php を使います。SSH / HTTP どちらからでも 実行できます。

# サーバに SSH で入って
php public/check-search-env.php

# または、ブラウザから
# https://example.com/check-search-env.php

PHP / pdo_sqlite / SQLite バージョン / FTS5 + trigram / var/ の書き込み権限まで一気にチェックして、最後に「✓ 利用可能」/「✗ 課題あり」の判定が出ます。NG だった場合は site.yamlsearch: false に切り替えれば DB 不要構成で運用継続できます。

重要

確認が終わったら public/check-search-env.php をサーバから削除 してください。PHP / SQLite のバージョン等が公開された状態になるため、放置は不要な情報開示につながります。

メモ

XSERVER について — 標準で pdo_sqlite 拡張と FTS5 入りの SQLite (3.30+) が用意されているので、追加設定なしで全文検索が使えます。CI (.github/workflows/deploy.yml) でも同じスクリプトをデプロイ前に走らせて確認しています。

検索結果に表示されない場合

  • .md ファイルが contents/ 配下に置かれているか — 別ディレクトリの記事はインデックスされません
  • フロントマターに title があるか — タイトル不在の記事はリストアップされません
  • var/ ディレクトリに書き込み権限があるかvar/fts.sqlite を作れないと初回ビルドが失敗します

ヒント

サーバ環境で var/fts.sqlite の存在を確認したい場合は ls -la var/fts.* で見られます。var/fts.last_builtJSON でスキーマバージョンと最終ビルド時刻 を保持しているマーカーファイルです(スキーマを変更したら次回起動時に自動でリビルドされます)。

検索機能を無効にする (DB-free 運用)

「DB を一切使いたくない」「検索は外部サービスを使う」といった場合、config/site.yaml で機能ごと無効化できます。

site:
  search: false

false にすると以下の挙動になります。

  • var/fts.sqlite作られません(SearchRepository は初期化されない)
  • /search へのアクセスは 404 を返します
  • ヘッダの 🔍 アイコンと検索 JS の読み込みも すべて消えます
  • テーマには site.search (true/false) が渡るので、独自テーマでも {% if site.search %} で出し分けできます

メモ

既に作られた var/fts.sqlite は残ったままになりますが参照されません。ディスクから消したい場合は rm var/fts.sqlite var/fts.last_built を手動で実行してください。

仕様の制限

  • スニペットとハイライトはすべて PHP 側で生成します(FTS5 の snippet() highlight() は使わない)。先頭ヒット周辺 約 220 文字に切り出し、ユーザー原文のヒット箇所を <mark> で包みます
  • ステミング(語形変化の正規化)は行いません。docsdoc は別の語として扱われます
  • 1 文字 / 2 文字の検索語はトリグラム化せずそのまま phrase マッチに使います
  • FTS5 の演算子(ORNEAR*- など)はユーザー入力時には無効化されます。各語はフレーズクォート ("...") で囲まれて FTS5 に渡されます

前のページ

← お気に入り