第4章では、全文検索という「ふるい」について見てきました。
全文検索は頼れる仕組みですが、基本的には言葉の一致を手がかりにしています。
そのため、探す側の言葉と、メモに書かれている言葉がずれてしまうと、うまく見つからないことがあります。
そこで、この章では、言葉そのものの一致ではなく、意味や話題の近さで探す方法を扱います。
それが、松コースのベクトル検索です。
いきなり難しそうな名前が出てきましたが、この章で見るのは数式ではありません。
自分のメモをあとから探すときに、なぜベクトル検索が役に立つのか。
そして、何を期待しすぎてはいけないのか。
そのあたりを、利用者目線で見ていきます。
5-1 ベクトル検索とは何か
ベクトル検索は、単語がそのまま一致しているかどうかではなく、文章や話題の近さを手がかりにして探す方法です。
たとえば、「宣伝」で検索すれば、全文検索では「宣伝」と書かれたメモが見つかります。
けれども、同じような話題でも、本文に「広報」「告知」「作品を広める」「知ってもらう」と書かれていたら、検索結果に出てこないかもしれません。
人間から見れば、どれも近い話題です。
けれども、全文検索にとっては、文字が違えば別の言葉です。
第1章で触れたように、未来の自分は、今の自分とは違う語彙でメモを探すことがあります。
書いたときは「宣伝が苦手」と思っていた話を、後から「告知がつらい」「作品を広める方法」「広報できない」と探すかもしれません。
こうした語彙のずれを、少し吸収してくれるのがベクトル検索です。
ここで「ベクトル」という言葉が出てきました。
数学が得意な人なら、向きと大きさを持つ量、という説明を思い出すかもしれません。
ただ、この本では、そこまで踏み込みません。
ここでは、文章を検索用の位置情報に変換して、近くにありそうなものを探す仕組み、くらいに考えてください。
たとえば、保管庫の中のメモを、話題ごとに地図の上へ置いていくようなイメージです。
同人誌の宣伝が苦手というメモは、創作、同人活動、告知、広報の話題の近くに置かれる。
イヤーピースのメモは、イヤホンや耳型の話題の近くに置かれる。
この「文章を、近さを比べられる場所へ置き直す」ような変換を、埋め込みと呼びます。
英語では embedding です。
そのため、ベクトル検索は、埋め込み検索と呼ばれることもあります。
もちろん、実際に地図が見えているわけではありません。
機械の中では、文章が検索用の数値に変換されています。
けれども、利用者として大事なのは、細かい数学の定義や計算方法よりも、「近い話題を探せること」です。
全文検索は、書いてある言葉と、探す言葉が一致したときに強い。
ベクトル検索は、言葉が少し違っても、話題が近いものを拾いたいときに強い。
この違いを押さえておけば、まずは十分です。
ただし、ここで一つ注意があります。
ベクトル検索は、魔法の検索ではありません。
話題が近そうなものを拾うぶん、ぴったり一致していない候補も混ざります。
人間から見ると、「確かに少し近いけれど、今ほしいのはこれじゃない」という結果も出てきます。
つまり、ベクトル検索は「正解を一発で当てる道具」というより、「うろ覚えでも候補を広げてくれる道具」です。
全文検索が、文字の一致で細かくふるいにかける道具だとすれば、ベクトル検索は、意味の近さで周辺を探しに行く道具です。
どちらが上という話ではありません。
得意な場面が違うのです。
だから、保管庫を探すときには、全文検索だけでも、ベクトル検索だけでもなく、両方の性格を知っておくと便利です。
次の節では、このベクトル検索のために使われる、埋め込みモデルについて見ていきます。
5-2 埋め込みモデルとは何か
前の節では、ベクトル検索を「文章を検索用の位置情報に変換して、近くにありそうなものを探す仕組み」として説明しました。
では、その変換は誰がやっているのでしょうか。
それを担当するのが、埋め込みモデルです。
埋め込みモデルは、文章を検索用の数値に変換するAIモデルです。
前の節のたとえで言えば、保管庫の中のメモを、話題ごとの地図の上へ置いていく係です。
メモの本文や見出し、フロントマターなどを読み取り、その内容を検索用の数値の並びに変換します。
この数値の並びを使うことで、後から「この相談文に近いメモはどれか」「この文章と話題が近い記録はどれか」を探せるようになります。
ここで大事なのは、埋め込みモデルは、ChatGPTやClaudeのように会話の返事を書くためのモデルとは少し役割が違う、ということです。
ChatGPTやClaudeのようなLLMは、文章を読んで、返事や要約やアイデアを文章として出力するのが得意です。
一方、埋め込みモデルは、文章を読んで、検索に使いやすい数値へ変換するのが仕事です。
つまり、埋め込みモデルは「答える係」ではなく、「探しやすい形に変換する係」です。
そのため、埋め込みモデルに「このメモを読んで感想を書いて」と頼むわけではありません。
代わりに、「この文章は、検索用の地図の上ではどこに置かれるか」を決めてもらうようなものです。
たとえば、同人誌の宣伝が苦手というメモを埋め込みモデルに通すと、その文章は検索用の数値に変換されます。
後から「告知がつらい」「作品を広める方法」「同人活動の広報」といった言葉で探したとき、その数値の近さを手がかりに、関連しそうなメモとして拾える可能性が出てきます。
もちろん、埋め込みモデルが文章を人間のように理解している、と言い切る必要はありません。
利用者としては、文章を意味や話題の近さで比べるための、検索用の下ごしらえをしてくれるもの、と考えておけば十分です。
ここで、少し現実的な話もしておきます。
埋め込みモデルは、ChatGPTやClaudeのサブスクに、何でも自由に使える部品としてそのまま付いてくるものではありません。
クラウドのAPIとして提供されている埋め込みモデルを使う方法もあります。
また、PCの中で動かせるローカルの埋め込みモデルを使う方法もあります。
筆者は、自分の保管庫検索に、ローカルの埋め込みモデルを使っています。
理由はいくつかありますが、一番大きいのは、保管庫検索を何度も使う前提だからです。
毎回クラウドAPIに問い合わせるより、自分のPCの中で検索用の変換を済ませられる方が、使い倒しやすいと考えました。
また、埋め込みモデルは、会話用の大きなLLMに比べると軽いものも多く、用途を検索に絞ればローカルでも扱いやすい場合があります。
もちろん、だからといって、誰でも最初からローカル埋め込みを用意するべき、という話ではありません。
小さな保管庫なら、フロントマターや全文検索だけで十分なこともあります。
埋め込みモデルが必要になるのは、メモが増えてきて、しかも「言葉は覚えていないけれど、近い話題を探したい」という場面が増えてきたときです。
言い換えるなら、埋め込みモデルは、松コースのための下ごしらえ係です。
保管庫のメモを、後からうろ覚えで探せるように、あらかじめ検索用の形へ変換しておく。
その変換があるからこそ、ベクトル検索は意味や話題の近さを手がかりにできるのです。
次の節では、この変換を保管庫全体にかけるときに重要になる、チャンクという考え方を見ていきます。
5-3 チャンクという考え方
前の節では、埋め込みモデルについて見てきました。
埋め込みモデルは、文章を検索用の数値に変換するモデルです。
この変換があるから、ベクトル検索では、言葉そのものが一致していなくても、話題の近さを手がかりに探せるようになります。
では、保管庫の中の文章を埋め込みモデルに通すとき、何を一つの単位として扱えばよいのでしょうか。
ファイル一つを、そのまま一つの検索単位にすればよいのでしょうか。
それとも、もっと細かく分けた方がよいのでしょうか。
ここで出てくるのが、チャンクという考え方です。
チャンクとは、ざっくり言えば、検索や処理のために文章を分けた小さなかたまりのことです。
長いメモや原稿を、そのまま一つの検索単位にしてしまうと、いくつか困ることがあります。
たとえば、LLMとの雑談をまとめたサマリーには、イヤーピースの話から始まって、旅行の話、体調の話まで、一つの会話の流れとして入っていることがあります。
そのファイル全体を一つの単位として変換すると、検索用の数値には、いろいろな話題が混ざります。
後から「イヤーピース」で探したいのに、旅行や体調の話まで混ざった大きなかたまりとして扱われてしまうわけです。
これでは、検索結果として出てきても、どこが関係あるのか分かりにくくなります。
逆に、文章を細かく分けすぎても困ります。
一文だけ、一段落だけ、というように小さく切りすぎると、今度は文脈が足りなくなります。
その文章が何の話の一部なのか、前後を読まないと分からないことが増えるからです。
つまり、チャンクは大きすぎても、小さすぎても扱いにくいのです。
大きすぎると、話題が混ざる。
小さすぎると、文脈が切れる。
その間の、検索しやすい大きさに文章を分ける必要があります。
このとき、本文だけを切り出すのではなく、見出しやフロントマターの情報も一緒に持たせると便利です。
たとえば、ある段落だけを見ると「これは助かる」としか書いていない場合、その一文だけでは何の話か分かりません。
けれども、同じチャンクにファイル名、見出し、summary、topics などの情報が付いていれば、それがイヤーピースの話なのか、LLM検索の話なのか、創作の話なのかを判断しやすくなります。
第3章で扱ったフロントマターは、ここでも役に立ちます。
summary は、そのファイル全体が何の話かを示します。
topics は、そのファイルの中に出てくる具体的な話題名を示します。
見出しは、そのチャンクが本文のどの位置にあるのかを示します。
こうした情報を本文と一緒に持たせることで、チャンクはただの切れ端ではなく、「どのファイルの、どの話題に属する文章なのか」が分かる検索単位になります。
筆者の保管庫検索でも、本文を適度な長さに分けたうえで、見出しやフロントマターの情報を一緒に持たせています。
もちろん、チャンクの大きさに絶対の正解があるわけではありません。
短いメモが多い保管庫なら、ファイル単位でも困らないことがあります。
一方で、長い会話サマリーや原稿、調査メモが多い保管庫では、適度に分けた方が探しやすくなります。
大事なのは、検索したときに「この候補は何の話か」「どこを読めばよいか」が分かることです。
ベクトル検索は、近そうな候補を拾ってくれます。
けれども、その候補が大きすぎると、結局どこを読めばよいのか分からなくなります。
反対に、候補が小さすぎると、そこだけ読んでも意味が分からないことがあります。
だから、チャンクは、検索結果を人間やLLMが扱いやすくするための切り分けです。
文章を検索用の地図に置く前に、地図に置きやすい大きさへ分けておく。
それが、チャンクという考え方です。
次の節では、このチャンクを使ったベクトル検索と、第4章で扱った全文検索を、どう組み合わせるかを見ていきます。
5-4 全文検索とベクトル検索を組み合わせる
ここまで、全文検索とベクトル検索をそれぞれ見てきました。
全文検索は、書いてある言葉と、探す言葉が一致したときに強い検索です。
一方、ベクトル検索は、言葉が少し違っても、話題が近いものを拾いたいときに強い検索です。
では、保管庫を探すときには、どちらを使えばよいのでしょうか。
答えは、どちらか一方に決めなくてもよい、です。
全文検索とベクトル検索は、得意な場面が違います。
だから、両方の結果を組み合わせると、検索の取りこぼしを減らしやすくなります。
たとえば、特定の製品名や人名、作品名、ファイル名を探すときは、全文検索が強いです。
KZ SonataやSpinFitのような固有名詞は、文字が一致していれば見つけやすいからです。
一方で、「同人誌の宣伝が苦手だった話」「LLMに過去メモを探してほしい話」「右耳が小さくてイヤーピース選びが厳しかった話」のように、ふわっとした内容で探すときは、ベクトル検索が助けになります。
検索する側の言葉と、メモに書かれている言葉が少しずれていても、話題が近ければ候補に上がる可能性があるからです。
ただし、ベクトル検索だけに頼ると、今度は別の問題があります。
意味や話題の近さで拾うため、少し遠い候補も混ざります。
「確かに近いけれど、今ほしいのはこれではない」という結果が出ることもあります。
全文検索だけだと、言葉がずれたときに取りこぼす。
ベクトル検索だけだと、近そうで少し違う候補も混ざる。
だから、組み合わせます。
こうした組み合わせ方は、ハイブリッド検索と呼ばれることもあります。
筆者の保管庫でも、ハイブリッド検索を採用しています。
全文検索とベクトル検索、片方だけで探すのではなく、言葉の一致で見つかった候補と、意味の近さで見つかった候補を合わせて、最終的な検索結果として返す形です。
このとき、内部では検索結果の順位をまとめ直す処理が行われます。
たとえば、全文検索でも上位に出て、ベクトル検索でも上位に出た候補は、かなり有望です。
片方だけで上位に出た候補も、場合によっては役に立ちます。
こうした順位のまとめ方の一つに、RRFという考え方があります。
ただし、この本では、RRFの計算式までは扱いません。
大事なのは、検索のふるいを一段だけにしない、ということです。
文字が一致するものを探すふるい。
意味や話題が近いものを探すふるい。
この二つを重ねることで、単語一致だけでは拾えなかった候補と、意味検索だけではぼやけやすい候補の両方を扱えるようになります。
もちろん、組み合わせたからといって、常に完璧な検索結果になるわけではありません。
検索語が曖昧すぎれば、関係の薄い候補も出ます。
保管庫の中にそもそも該当するメモがなければ、当然見つかりません。
また、検索結果をどう並べるかによって、見え方も変わります。
それでも、全文検索とベクトル検索を組み合わせると、保管庫を探すときの手がかりは増えます。
正確な言葉を覚えているときは、全文検索が助けてくれる。
うろ覚えのときは、ベクトル検索が候補を広げてくれる。
両方に引っかかるものは、かなり有望な候補として扱える。
このように、検索の入口を一つに絞らず、複数の道から候補を集めるのが、松コースの強みです。
次の節では、ここまで見てきた松コースの限界について整理します。
5-5 松コースの限界
ここまで、ベクトル検索と、全文検索との組み合わせについて見てきました。
言葉がそのまま一致していなくても、話題の近さで候補を拾える。
全文検索と組み合わせれば、固有名詞にも、うろ覚えにも対応しやすくなる。
こう書くと、ベクトル検索はとても便利な仕組みに見えます。
実際、便利です。
ただし、松コースには松コースの限界があります。
まず、梅コースや竹コースに比べると、準備が大掛かりになりがちです。
フロントマターを付けるだけなら、マークダウンファイルを編集すれば始められます。
全文検索も、Obsidianの標準検索を使うだけなら、追加の仕組みはほとんど要りません。
一方で、ベクトル検索をするには、文章を埋め込みモデルに通し、検索用の数値に変換し、それを保存しておく場所が必要になります。
つまり、検索のための下ごしらえが増えます。
さらに、保管庫は一度作ったら終わりではありません。
新しいメモが増えます。
既存のメモを書き換えます。
不要になったメモを消すこともあります。
そのたびに、検索用の情報も更新する必要があります。
本文を直したのに、検索用の数値が古いままだと、検索結果が今の保管庫とずれてしまいます。
ファイルを消したのに、検索側に古い情報が残っていれば、もう存在しないメモが候補に出てくるかもしれません。
便利な検索を使うには、便利な検索を守り育て続ける必要があるのです。
実際、筆者も一度、検索用の索引が壊れて、全部作り直したことがあります。
幸い、壊れたのは検索用の索引だけでした。
保管庫のマークダウンファイル本体は無事だったので、索引は作り直せば済みます。
けれども、そういう世話が発生すること自体が、松コースの性格です。
また、ベクトル検索には、結果の理由を説明しにくい、という性格もあります。
全文検索なら、結果の理由を説明できます。
その文字列が、本文にあったから出てきた。
それだけのことですが、人間にとっては分かりやすい理屈です。
一方、ベクトル検索の結果は、「話題が近そうだったから」としか言えません。
なぜこの候補が上位なのか。
どのくらい近ければ出てくるのか。
それが、人間の感覚とぴったり一致するとは限りません。
5-1でも触れた通り、近そうで少し違う候補も混ざります。
そのうえ、なぜ混ざったのかを、すっきり説明できないのです。
だから、検索結果が本当に今の相談に関係あるかどうかは、最後に人間やLLMが判断する仕事として残ります。
ベクトル検索は、探す範囲を広げてくれる道具です。
正解だけをきれいに並べてくれる道具ではありません。
それを忘れないでいれば、うろ覚えから候補を拾い上げる道具として、十分に頼れます。
ただし、松コースは、そのぶん使う道具も、保守する情報も増えます。
だから、誰にでも最初から松コースを勧めたいわけではありません。
メモが少ないうちは、フロントマターとタグだけでも役に立つでしょう。
Obsidianの検索で困っていないなら、無理に松コースまで進まなくてもよいと思います。
ベクトル検索が欲しくなるのは、メモが増え、語彙のずれが増え、過去の自分やLLMが書いた記録を、うろ覚えでも探したくなってきたときです。
つまり、松コースは、梅や竹で足りなくなった人向けの贅沢コースです。
便利ですが、最初の一歩ではありません。
必要になったときに進めばよい段階です。
ここまでで、梅、竹、松の三つの段階を見てきました。
フロントマターで取っ手を付ける。
全文検索で言葉をふるいにかける。
ベクトル検索で意味の近さまで拾いに行く。
では、この検索の仕組みを、チャット中のLLM自身に使ってもらうにはどうすればよいのでしょうか。
次の章では、その先の実例として、筆者の保管庫MCPについて見ていきます。