よくある質問
用語が分からない場合
GTID、binlog、N-gram、BM25、Roaring Bitmapなどの用語は用語集でも説明しています。初めて読む場合は、FAQとあわせて参照してください。
MySQL FULLTEXTの問題
MySQL FULLTEXTが遅いのはなぜですか?
ディスクI/O、非圧縮の転置リスト、キャッシュ依存、並列アクセス時の伸びにくさが主な原因です。詳しくはMySQL FULLTEXTが遅い理由をご覧ください。
解決策: MygramDBは検索インデックスをメモリ上に保持します。ベンチマークでは主要クエリでサブミリ秒級のレスポンスを示しています。数値はベンチマークを参照してください。
MySQL FULLTEXTが負荷時にタイムアウトします。どう対処すべきですか?
MygramDBを検索レプリカとして追加してください。110万件のWikipedia記事でのベンチマークでは、MySQL FULLTEXTが2-8 QPSにとどまるのに対し、MygramDBは2,634-11,766 QPSを達成します。
アプリケーションを大きく変更せずにMySQL FULLTEXTを高速化できますか?
書き込み処理や正本データの置き場所は変えずに導入できます。MygramDBはbinlogレプリケーションでMySQLと同期するため、アプリケーションは通常通りMySQLに書き込み、検索クエリだけをMygramDBにルーティングします。セットアップはクイックスタートをご覧ください。
変更が必要な部分
MySQLへの書き込み処理は変えずに済みます。ただし、検索リクエストの向き先はMygramDBのTCP APIまたはHTTP APIへ変更する必要があります。
他の選択肢との比較
Elasticsearchの代わりにMygramDBを使うべきですか?
詳しくは比較ページをご覧ください。端的に言えば、データがRAMに収まりMySQL/MariaDBとのシンプルな連携が必要ならMygramDB。複数ノードにまたがる分散検索、ペタバイト規模のデータ、より高度な分析・集計機能が必要ならElasticsearch。
MeilisearchやTypesenseとの違いは?
MeilisearchやTypesenseは、タイポ補正・ファセット検索・管理UIを備えた汎用検索エンジンです。MygramDBは異なる問題を解決します。MySQLからbinlogで直接同期するインメモリ検索レプリカです。データが既にMySQLにあり、ETLパイプラインなしで高速な全文検索が必要な場合はMygramDBの方がシンプルです。独立した検索プラットフォームとして独自のデータ取り込みが必要な場合は、MeilisearchやTypesenseが適しています。
RediSearchとの違いは?
どちらもインメモリの全文検索エンジンですが、アーキテクチャが根本的に異なります。
| MygramDB | RediSearch | |
|---|---|---|
| データ同期 | MySQL/MariaDB binlogで自動同期 | プッシュ型(FT.ADD)— ETLは自前で構築 |
| 依存 | MySQLまたはMariaDB | Redis(Redis Stack) |
| デプロイ | 単一バイナリ | Redisモジュール |
| 機能 | N-gram検索+BM25スコア、ハイライト、ファジー検索、ファセット集計、シノニム展開 | ファジー検索、ハイライト、集計、地理 |
| ライセンス | MIT | RSALv2 / SSPL(商用制限あり) |
最大の違いはデータフローです。RediSearchはドキュメントをRedisにプッシュする必要があり、MySQLとRedis間のETLパイプラインが必要です。MygramDBはMySQL/MariaDBのbinlogを直接読み取り、自動で同期を維持します。データがMySQL/MariaDBにあり、同期パイプラインを構築せずに検索したい場合はMygramDBの方がシンプルです。既にRedisを運用しており、地理検索やより豊富な集計モデルが必要な場合は、RediSearchの統合コストに見合う可能性があります。
機能と制約
MygramDBに必要なメモリ量は?
verify_textモードによります。verify_text: off(デフォルト)では100万ドキュメントあたり約813MB(インデックスのみ)。verify_text: all(テキスト検証有効)では100万ドキュメントあたり約2.3GB(ポストフィルタ用の正規化テキストを含む)。1000万ドキュメントなら約8GB(off)または約23GB(all)を想定してください。
メモリ不足時の挙動
MygramDBはインメモリ検索エンジンです。データセットが利用可能RAMを超えると、OSやコンテナ基盤のOOMによってプロセスが終了する可能性があります。本番ではダンプ領域とは別に、インデックス用RAMと余裕分を確保してください。
MygramDBは日本語に対応していますか?
はい。ICUベースのUnicode正規化とN-gramトークナイズを使用。日本語・中国語・韓国語は追加プラグインなしでそのまま動作します。
ファジー検索(タイポ補正)には対応していますか?
はい(v1.6.0以降)。クエリに FUZZY(または FUZZY 2)を追加すると、Levenshtein編集距離1または2以内の語句にマッチします。候補は長さの差で事前フィルタされるため、オーバーヘッドは抑えられています。詳しくはクエリガイド — ファジー検索を参照してください。
検索結果のハイライトには対応していますか?
はい(v1.6.0以降)。HIGHLIGHT 句を追加すると、設定可能なタグ(TAG)、フラグメント長(SNIPPET_LEN)、フラグメント数(MAX_FRAGMENTS)でスニペットが返却されます。スニペットは保存済みの正規化テキストから切り出されるため、verify_text を "ascii" または "all" に設定する必要があります。詳しくはクエリガイド — ハイライトを参照してください。
関連度順のランキングには対応していますか?
はい(v1.6.0以降)。SORT _score DESC を使うとBM25関連度スコア(k1=1.2、b=0.75)で並び替えられます。IDF/TFはクエリ時に計算されるため、verify_text を "ascii" または "all" に設定する必要があります。
水平スケールは可能ですか?
組み込みのスケール機能はありません。MygramDBは設計上シングルノードです。単一ノードのRAMを超えるデータセットの場合:
- ロードバランサーの背後に複数のMygramDBインスタンスをデプロイ
- 各インスタンスが同じMySQL Primaryから全データをレプリケーション
- 真のシャーディングにはID範囲でテーブルを分割し、アプリケーション層でクエリをルーティング
多くのユースケース(64〜128GBサーバーで最大約5000万ドキュメント)では、単一ノードで十分です。
複数テーブルを横断検索できますか?
できません。各クエリは単一テーブルを対象とします:SEARCH articles hello world。MygramDBは複数テーブルの設定に対応していますが、各テーブルは独立したインデックスとドキュメントストアを持ちます。クロステーブル検索はアプリケーション層で個別クエリとして処理してください。
1つのMygramDBインスタンスで複数のMySQLデータベースをインデックスできますか?
はい(v1.7.0以降)。各テーブルは <database>.<table> の有効識別子を持ちます。設定済みテーブルが1つのDBにだけ属する場合、articles のような修飾なしの名前も引き続き使えます。設定が2つ以上のDBにまたがる場合は、SEARCH app_db.articles mysql や POST /tables/app_db.articles/search のように修飾が必要です。
MygramDBはPostgreSQLに対応していますか?
非対応です。MygramDBはMySQL固有のバイナリログレプリケーションプロトコルに依存しています。PostgreSQLは異なる仕組み(WALベースのロジカルレプリケーション)を使用しています。現時点でPostgreSQL対応の予定はありません。
MariaDBで動作しますか?
はい(v1.6.0以降)。MygramDBはMariaDB 10.6以降および11.xに対応し、MariaDBネイティブのGTID形式(domain-server-sequence)でレプリケーションします。SELECT VERSION() からサーバー種別を自動判定するため、同じ mysql セクションの設定でMySQL 8.4/9.xとMariaDBを切り替えられます。E2EテストはMariaDB 10.11および11.4で行っています。
インデックスと検索
なぜ形態素解析ではなくN-gramですか?
N-gramトークナイズは言語に依存しません。形態素解析器(MeCab、kuromoji、jieba)は辞書・言語判定・バージョン管理が必要です。N-gramは英語・日本語・中国語・韓国語・多言語混在コンテンツで一律に動作します。
MygramDBはハイブリッド方式を採用しています。ASCII/英数字にはバイグラム(サイズ2)、CJK文字にはユニグラム(サイズ1)を使用。どちらもテーブル単位でngram_sizeとkanji_ngram_sizeで設定可能です。
Roaring Bitmapはどう使われていますか?
転置リストは密度に応じたハイブリッドストレージ戦略を採用しています:
- 疎な転置リスト(全ドキュメントの18%未満): デルタエンコーディング配列。DocIDを前の値との差分で保存し、4バイト整数を1〜2バイトに圧縮。
- 密な転置リスト(18%以上): CRoaringによるRoaring Bitmap。65,536 ID単位のチャンクごとに最適なコンテナタイプ(配列・ビットマップ・ランレングス)を自動選択。
閾値はroaring_thresholdで設定可能。フォーマット間の振動を防ぐヒステリシス係数(0.5倍)があります。
「SIMD高速化」とは具体的に何ですか?
MygramDBはCRoaringをリンクしており、CRoaringがビットマップ演算(AND、OR、カーディナリティ)で内部的にSIMD命令を使用します。x86-64ではAVX2、ARMではNEONを利用。MygramDB自体にカスタムSIMDコードはなく、高速化はビットマップライブラリ由来です。
60-80%の圧縮はどう実現していますか?
ベースラインは非圧縮のuint32配列(DocIDあたり4バイト)です。2つのメカニズムで削減します:
- デルタエンコーディング: 単調増加するDocIDを小さな差分に変換。例:
[1000, 1002, 1005]→[1000, 2, 3]。少ないバイト数でエンコード可能。 - Roaring Bitmap圧縮: 密な転置リストはRoaringのコンテナ最適化を使用。連続範囲にはランレングスエンコーディング、散在する密な領域にはビットマップコンテナ。
60-80%は、疎と密が混在する実際の転置リストでの典型的な値です。
レプリケーションとデータ同期
MySQLのbinlogパーサーは自前実装ですか?
はい。MygramDBはMySQL C API(mysql_binlog_open())を直接使用する独自のC++ binlogパーサーを含んでいます。ROW形式のイベント(WRITE_ROWS、UPDATE_ROWS、DELETE_ROWS)およびDDLイベント(TRUNCATE、ALTER TABLE)をパースします。mysql-event-streamは後から独立したCDCライブラリとして切り出されたもので、Node.jsとPythonバインディングを備えています。
レプリケーションの速度は?INSERTから検索可能になるまで?
エンドツーエンドで通常20ms以下:
- MySQL binlogイベント生成: <1ms
- ネットワーク転送: <5ms(同一ネットワーク)
- イベントキュー処理+インデックス更新: 1〜10ms
ボトルネックはネットワークレイテンシです。localhost接続なら5ms以下です。
MySQLフェイルオーバー時の挙動は?
MygramDBは接続断を検知し、指数バックオフ(500msから10s)で再接続します。再接続時:
- 現在のGTIDポジションを保持
- 新しい接続を確立(ランタイム設定で別ホストへの切り替え可能)
- 保存されたGTIDからbinlogレプリケーションを再開。データロスなし
再接続中は検索クエリが一時的に待たされます(通常1〜5秒)。切断前に処理待ちになっていた書き込みイベントは失われません。
ALTER TABLEはどう処理されますか?
MygramDBはbinlog経由でDDLイベントを検知します。TRUNCATE TABLEはインデックスを即座にクリアします。ALTER TABLEとDROP TABLEは警告としてログに記録されます。検索対象カラムのスキーマ変更(リネーム、型変更)を行った場合は手動リビルドが必要です。MygramDBを停止し、ダンプを削除し、再起動してMySQLからの初期スナップショットをやり直してください。
インデックスからの削除はどう処理されますか?
即時削除です。binlog経由でDELETEイベントが到着すると、ドキュメントのN-gramが転置リストから除去され、ドキュメントストアからも削除されます。トゥームストーンや遅延削除はありません。削除されたドキュメントを参照するキャッシュエントリは無効化されます。
障害復旧と永続化
クラッシュ時の復旧は?WALはありますか?
WALはありません。MygramDBはスナップショットベースの永続化を採用しています:
- 定期または手動のダンプで、現在のGTIDポジションとともにインデックス全体を保存
- 再起動時に最新のダンプをロードし、保存されたGTIDからbinlogレプリケーションを再開
WALより単純な方式ですが、MygramDBでは信頼できるデータソースをMySQLに置いているため、この設計にしています。直近のダンプがない状態でクラッシュした場合、MySQLからフルリビルド(初期スナップショット+binlog追従)します。
ダンプ設定:
dump.interval_sec: 自動保存間隔(0 = 無効、本番推奨: 7200)dump.retain: 保持するダンプ数(デフォルト: 3)
メモリがハードリミットに達するとどうなりますか?
MygramDBはヘルスチェックエンドポイントでメモリ使用量を監視しますが、ハードリミットに達してもクエリの拒否やレプリケーションの停止は行いません。インデックスが利用可能なRAMを超えた場合、OS側のOOM killerがプロセスを終了します。実運用では、全データセットを載せられるRAMと余裕分を確保してください。目安は100万ドキュメントあたり約2.3GB(verify_text: allの場合)。/health/detailやPrometheusメトリクスでメモリ使用量の推移を監視してください。
プロトコルとセキュリティ
クエリプロトコルは何ですか?
TCP上のカスタムテキストプロトコル(デフォルトポート11016)で、Memcachedに似ています。REST/JSONのHTTP APIは別ポート(デフォルト8080、起動時はデフォルト無効)で提供されます。
TCP例:
SEARCH articles golang SORT created_at DESC LIMIT 10\r\nHTTP例:
curl -X POST http://localhost:8080/tables/articles/search \
-H "Content-Type: application/json" \
-d '{"q": "golang", "sort": {"column": "created_at", "order": "DESC"}, "limit": 10}'複数DB構成では /tables/app_db.articles/search のように修飾します。SQLではありません。検索、カウント、ファセット、ID取得、管理コマンドに絞った最小限のプロトコルです。
TLSや認証はありますか?
検索APIにTLSや認証はありません。アクセス制御はNETWORK_ALLOW_CIDRS(CIDRベースの許可リスト)で行います。MySQLレプリケーション接続はSSL/TLSをサポートしています。
MygramDBはプライベートネットワーク内、リバースプロキシやファイアウォールの背後での運用を前提としています。MemcachedやAUTHなしのRedisと同じモデルです。TLS終端が必要な場合はnginxやロードバランサーの背後に配置してください。
デプロイと監視
Kubernetesで動作しますか?
必要な要素は揃っています。ヘルスチェックエンドポイントが組み込まれています:
GET /health/live— Livenessプローブ(プロセス稼働中なら200)GET /health/ready— Readinessプローブ(初期同期中は503、準備完了で200)GET /health/detail— アップタイム、インデックス統計、メモリを含む詳細ステータス
PrometheusメトリクスはGET /metricsで取得できます。Dockerイメージは非rootユーザー(UID 1000)で実行されます。Kubernetesで運用する場合は、永続ボリューム、メモリ制限、Readiness/Livenessプローブ、MySQLへのネットワーク経路を環境に合わせて設定してください。
どのようなメトリクスが取得できますか?
GET /metricsでPrometheus形式のメトリクスを提供:
- クエリ性能(検索/カウント/取得のレイテンシ、QPS)
- インデックス統計(テーブルごとのターム数、ドキュメント数)
- キャッシュ統計(ヒット率、メモリ、エビクション)
- メモリ使用量(RSS、ヒープ)
- レプリケーション状態(binlogポジション、ラグ、適用イベント数)
- 接続統計
「単一バイナリ」と言いつつMySQLが必要 — それは本当にシンプルですか?
MygramDBは「既存のMySQLに検索レプリカを追加する」作業を小さくする設計です。データベースを置き換えるのではなく、MySQLの横に配置し、GTID/binlog設定、レプリケーションユーザー、対象テーブル、ネットワーク許可範囲を設定します。スキーマ変更や検索用ETLパイプラインは基本的に不要ですが、検索リクエストの向き先はMygramDBのTCP APIまたはHTTP APIへ切り替える必要があります。
ベンチマーク
ベンチマークのハードウェア環境は?
110万件のWikipedia記事(英語100万件+日本語10万件)でテスト。MySQL 8.4はDockerでデフォルト設定、MygramDBはverify_text: all(ポストフィルタ有効)でクエリキャッシュ無効。同一Apple M4 Max(128GBユニファイドメモリ)上で実行。M4 Maxのユニファイドメモリ帯域はDDR4より大幅に高く、インメモリのMygramDBに有利に働く点に注意。一般的なDDR4サーバーではMygramDBのレイテンシはやや高くなる可能性があります。
ベンチマークでMySQL側の設定はチューニングしましたか?
していません。MySQLはデフォルトのinnodb_buffer_pool_sizeとinnodb_ft_cache_sizeで実行。多くのMySQL環境がデフォルトまたは最小限のチューニングで運用されている実態を反映しています。積極的なチューニングを行っても、MySQL FULLTEXTの根本的なボトルネック(ディスクベースの転置リストスキャンとシングルスレッドクエリ実行)は変わりません。
MySQLはコールドキャッシュとウォームキャッシュのどちらでテストしましたか?
両方です。MygramDBはインデックスをメモリ上に保持するため、MySQL FULLTEXTよりディスクキャッシュの状態に左右されにくい傾向があります。コールド/ウォームの分析はMySQL FULLTEXTが遅い理由をご覧ください。
なぜElasticsearchとの実測比較がないのですか?
Elasticsearchの性能はクラスタ構成、シャード設計、マッピング、JVM設定で大きく変わります。単純なシングルノード比較では用途差を説明しにくいため、このサイトでは比較ページで定性的な使い分けを示しています。
プロジェクト
なぜRustではなくC++ですか?
C++を選んだ主な理由は、メモリレイアウトを細かく制御したかったためです。転置リスト操作、ビットマップ演算、デルタエンコーディングでは、データをどのようにメモリ上へ配置するかが性能とメモリ効率に直結します。実装ではRAII、unique_ptrによる所有権管理、例外の代わりのExpected<T, Error>を使い、C++で起きやすい問題を抑えています。Rustにも強い利点がありますが、MygramDBでは低レベルなメモリ制御と既存C/C++ライブラリ連携を優先しています。
プロジェクトの成熟度は?
開発は2025年11月に開始。現在のバージョンは1.7.0(2026年6月15日リリース)です。1.6系ではBM25関連度スコア、ハイライト、ファジー検索、ファセット集計、シノニム展開、V2ダンプ、MariaDB binlogレプリケーションが追加されました。1.7系ではDB修飾テーブル識別子、複数DBインデックス、HTTP /tables/{identity}/... ルート、HTTP FACET、Boolean検索のHTTP/TCP差分解消、複数テーブルの一貫スナップショット、GTID協調ダンプが追加されています。高トラフィックなサービスで本番利用実績があります(詳細はNDAにより非公開)。
MySQL FULLTEXTからMygramDBへの移行方法は?
MySQLはそのまま維持し、MygramDBを横に立てて、検索クエリだけルーティングします。既存行は初回 SYNC で読み込み、その後の変更はbinlogで追従します。クイックスタートまたは比較 — 移行方法をご覧ください。
その他の質問はGitHubをご確認いただくか、Issueを作成してください。