Slide 1

Slide 1 text

Tomohisa Oda / July 21, 2026 GoとClickHouseで作る RAG Application Fukuoka.go #23

Slide 2

Slide 2 text

Fukuoka.go #23 @linyows Blog: tomohisaoda.com Affiliation: Sakura internet, Inc.

Slide 3

Slide 3 text

Fukuoka.go #23 共有メールホスティングにおける輻輳影響 を局所化する透過型SMTPプロキシの提案

Slide 4

Slide 4 text

Fukuoka.go #23 Warp Architecture: https://warp.linyo.ws

Slide 5

Slide 5 text

Fukuoka.go #23 はじめに

Slide 6

Slide 6 text

Fukuoka.go #23 メール技術は人気がない ๏ メールは古いオープンなメッセージングシステム ๏ 分散システムで複数のプロトコルの組み合わせで成り立つ ๏ 生活で使う身近な存在なはずだが、メール技術が好きだと言う若者に出会った ことがない ๏ 無料かつ高品質?なGmailの存在が大きいのかもしれない ๏ 日本ではLINEのようなクローズドなサービスが好まれるので、普通の人のメー ルは受信が中心

Slide 7

Slide 7 text

Fukuoka.go #23 何をやっているか ๏ 次世代のWebmailサービスを開発している ๏ Gmailの代わりになることを想定 ๏ メールサーバはオールインワンMTAのStalwartを使用 ๏ 「検索:stalwart」→ これからメールサーバをつくるならStalwart ๏ StalwartとWebmailはJMAP:JSON Meta Application Protocolを使用する ๏ Webmailにはスマートな検索が必要

Slide 8

Slide 8 text

Fukuoka.go #23 Stalwartの全文検索Storages ๏ FoundationDB, RocksDB, SQLite ๏ PostgreSQL ๏ MySQL ๏ ElasticSearch ๏ Meilisearch

Slide 9

Slide 9 text

Fukuoka.go #23 検索パイプラインの分類 ๏ テキスト解析:トークナイズ・ステミング・サブワード化 ๏ インデックス構造:転置インデックス・グラフ・ツリー・量子 化・ハッシュ ๏ マッチング:ブールモデル・語検索・フレーズ検索・意味一致 ๏ ランキング:スコアリング・ランク融合

Slide 10

Slide 10 text

Fukuoka.go #23 Storage テキスト解析 マッチング スコアリング RocksDB, FoundationDB, SQLite Stalwart実装 Stalwart実装 なし PostgreSQL PG実装 PG実装 なし MySQL Stalwart実装 MySQL実装 なし ElasticSearch ES実装 ES実装 ES実装(BM25) Meilisearch MS実装 MS実装 MS実装(バケットソート)

Slide 11

Slide 11 text

Fukuoka.go #23 スマートな検索を提供する ๏ レキシカル検索:全文検索、検索ワードがわかっているやつ ๏ セマンティック検索:意味検索、記憶が曖昧で言い換えるや つ(ただしChat形式ではない) 両方に対応するハイブリッド検索を提供する → スマートな検索

Slide 12

Slide 12 text

Fukuoka.go #23 セマンティック検索を作る

Slide 13

Slide 13 text

Fukuoka.go #23 RAG Storeを選定する ๏ セマンティック検索にはEmbeddingモデルを使ったベクトルデータを作成しDBに保存す る ๏ ベクトル型とHNSW(Hierarchical Navigable Small World)インデックスに対応の DBが必要 ๏ アカウント数、データ量が多い大規模を想定 ๏ 専用ベクトルDBはオンメモリで処理し、列指向DBのClickhouseはディスクストレージを 活用するので比較的安価 ๏ FromやDateでの絞り込みによる構造化検索も必要、ということでClickhouseを使用する

Slide 14

Slide 14 text

Fukuoka.go #23 System Architecture ๏ EmbeddingモデルはさくらのAI Engineで multilingual-e5-large を使う

Slide 15

Slide 15 text

Fukuoka.go #23 Go実装:chunk分割 ๏ htmlタグ、引用、署名を除去 ๏ 段落 → 改行 → Max文字数の順で分割 ๏ ISO-2022-JPなどはサーバ側で全て UTF-8:JMAPの仕様

Slide 16

Slide 16 text

Fukuoka.go #23 Go実装:Clickhouse ๏ ドライバはClickhouse謹製の github.com/ClickHouse/ clickhouse-go/v2 ๏ 標準のnet/httpでも良いが、上のド ライバはバイナリ転送やOTEL対応 やTCPでのコネクションプールを やってくれるので便利 ๏ nativeインターフェース以外に database/sql 互換インターフェース ももっている

Slide 17

Slide 17 text

Fukuoka.go #23 ハイブリッド検索にする

Slide 18

Slide 18 text

Fukuoka.go #23 Go実装:異なる検索結果を一緒にする ๏ レキシカル検索結果はスコアリング順、セマンティック検索 の結果はコサイン距離順で、同じ順序でマージできない ๏ RRF:Reciprocal Rank Fusion(相互ランク融合)という アルゴリズムがあり、順位だけを使ってスコアリングする手 法を使う

Slide 19

Slide 19 text

Fukuoka.go #23

Slide 20

Slide 20 text

Fukuoka.go #23 集合Mに含まれる 要素mの全ての総和 定数 順位

Slide 21

Slide 21 text

Fukuoka.go #23 Go実装:RRFの簡単な例 ๏ レキシカル検索(日付降順): [A, B, C] セマンティック検索(距離昇順): [B, D, A] ๏ スコア(k=60): A = 1/61 + 1/63 ≈ 0.03226 B = 1/62 + 1/61 ≈ 0.03252 C = 1/63 ≈ 0.01587 D = 1/62 ≈ 0.01613 ๏ RRF: B, A, D, C ๏ 両方に出たアイテムは点が2回加算されて上位に来る ๏ ただ、ベクトル検索はどんなクエリにも必ず何かを返すので、絶対的な距離の閾値による足切りが必要

Slide 22

Slide 22 text

Fukuoka.go #23 まとめ

Slide 23

Slide 23 text

Fukuoka.go #23 まとめ ๏ Stalwartにおける検索バックエンドはいろんな選択肢がある ๏ 単純なレキシカル検索に加え、セマンティック検索をGoと ClickhouseでRAGアプリの構築例を紹介した ๏ また、異なる順位をマージにRRFを使用している 検索技術に詳しい人いろいろ教えてください ><

Slide 24

Slide 24 text

Fukuoka.go #23 Hiring: さくらインターネットでは Goを使ったクラウドのコン ポーネントの開発や、開発チームのマネージメントをしてくれ る仲間を探しています!気軽にお声かけください!