IDEAL-CODE-LIFE
← posts

2026.10.15 · tech · 5 min

EmDash で日本語検索が 0 件になるので、プラグインで直した

WordPress + Astro で作っていた自分のサイトを、Cloudflare の CMS「EmDash」に移しています。その途中で、日本語の検索がまったく効かないことに気づきました。

「検索」というタイトルの記事を「検索」で探しても、結果は 0 件です。

記事タイトル: 日本語検索について
検索ワード:   検索
結果:         No results for "検索"

原因を調べて、辞書なしで動くプラグインを作って直したので、その記録です。

EmDash の検索の仕組み

EmDash は Astro ベースのオープンソースの CMS で、2026 年 9 月に 1.0 が出ました。記事の検索には SQLite の全文検索機能(FTS5)を使っています。

全文検索は、保存するときに文章を「単語」に切り分けて索引を作り、検索ワードと同じ単語があるかで探す仕組みです。EmDash は、この切り分け方の初期設定が porter unicode61 になっています。

// emdash/src/search/fts-manager.ts
const DEFAULT_SEARCH_TOKENIZER: SearchTokenizer = "porter unicode61";

0 件になる理由

unicode61 は、スペースと句読点で文章を区切ります。英語ならそれで単語になりますが、日本語にはスペースがありません。なので、句読点までの一続きがまるごと 1 つの「単語」になります。

元の文:     EmDash の日本語全文検索の挙動を検証します。
切り分け後: ["emdash", "の日本語全文検索の挙動を検証します"]

この状態で「検索」を探しても、「検索」という単語は索引のどこにもありません。だから 0 件になります。

本家にも同じ報告が上がっていました(emdash-cms/emdash#2775)。この記事を書いている時点では、まだ直っていません。

trigram に切り替えるだけではダメだった

EmDash では、切り分け方を trigram にも変えられます。文章を 3 文字ずつずらして切る方式で、日本語ではよく使われる回避策です。

ただ、3 文字ずつなので、2 文字以下の検索ワードは引っかかりません。

料金     (2文字) → 0件
の料金   (3文字) → 1件
従量課金 (4文字) → 1件

日本語の検索ワードは「料金」「予約」「会社」「採用」のような 2 文字がとても多いので、これだと実用になりません。それに、英語の単語の語形をそろえる処理(search と searching を同じ扱いにするなど)も効かなくなります。

直し方: 2 文字ずつの索引を別に作る

考え方は単純で、2 文字ずつずらして切ったものを、記事とは別の欄に入れておきます。

元の文: 日本語検索について
索引:   日本 本語 語検 検索 索に につ つい いて

検索するときも、検索ワードを同じように 2 文字ずつに切ります。そのうえで「この順番で並んでいること」という条件で探します。

検索ワード: 日本語 → 「日本」「本語」がこの順で並んでいる

これで「この文字列が含まれているか」と同じ意味の検索になります。2 文字の「料金」も、索引の中にそのままあるので見つかります。

切り分けた結果は記事の中の検索用の欄に入れるだけなので、検索そのものは EmDash 本体の仕組みをそのまま使えます。並び順(関連度順)や、公開・非公開の扱いは、本体がやってくれます。

落とし穴: 区切りをまたいで当たってしまう

このままだと、困ったケースが出ます。

本文:   本社は東京、京都、大阪の三拠点です。
索引:   ... 東京 京都 大阪 ...

「東京」と「京都」が、索引の中で隣り合っています。そのため、本文に「東京都」という言葉はないのに、「東京都」で検索すると当たってしまいます。

これを防ぐために、区切りのところに目印の文字を 1 つ挟みました。目印が間に入れば、「東京」と「京都」は隣り合わなくなります。

索引: ... ǁ東京 ǁ ǁ京都 ǁ ǁ大阪 ...

目印には ǁ という、普通の文章にはまず出てこない文字を使っています。索引の各トークンの頭にも付けているのは、本文の欄の切り分け結果と混ざらないようにするためです。

結果

検索ワード

直す前

直した後

検索

0 件

当たる

料金

0 件

当たる

挙動(文の途中の語)

0 件

当たる

東京都(本文は「東京、京都」)

―

当たらない(正しい)

テスト(半角)で「テスト」

0 件

当たる

英語だけの検索ワードは、これまでどおり本体の検索に任せています。

できないこと

  • 「京都」で探すと「東京都」にも当たります。文字列が含まれているかどうかで探しているので、単語の区切りまでは分かりません。
  • 「出来る」と「できる」、「解約する」と「解約します」は別物として扱います。ここをそろえるには辞書が必要です。
  • 索引の分だけ、データは元の文章の 3〜4 倍くらいに増えます。

ちゃんとした日本語検索がほしいなら、辞書を使う形態素解析や、専用の検索サービスを使うことになります。今回のは、個人ブログくらいの規模で、追加のサービスなしに「ちゃんと引ける」状態にするための方法です。

Claude Code と作って分かったこと

このプラグインは Claude Code と一緒に作りました。途中で何度か「できました」と言われたあとに、壊れているところが見つかっています。

  • 自分で用意した都合のいいテストデータだけで確認していて、本番の動きと違っていた
  • テストが EmDash 本体の処理の一部を飛ばしていて、複数の語で探すと全部 0 件になっていた
  • 記事が 5 件しかない環境で試していたので、件数が増えたときだけ起きる不具合が見えていなかった

どれも、テストは全部通っている状態で見つかりました。テストが通っていることと、正しく動いていることは別だというのは、今回あらためて実感したところです。

---

本家の issue(#2775)はまだオープンです。同じところで困っている人の参考になればうれしいです。