Skip to content

クエリ構文ガイド

MygramDBは、全文検索に必要なブール演算、フィルタ、ソート、ページネーションを小さな検索構文として提供します。

SQLではありません

MygramDBのクエリはSQLではなく、検索用の小さなコマンド言語です。SEARCH articles mysql FILTER status = 1 LIMIT 10 のように、検索語と検索オプションだけを記述します。

目次


基本構文

コマンドフォーマット

mygram
SEARCH <table> <query_expression> [FILTER ...] [SORT ...] [LIMIT ...] [OFFSET ...]
COUNT <table> <query_expression> [FILTER ...]

テーブル名の指定

<table> は DB 修飾形式 `database.table`(例: app_db.articles)を受け付けます。単一データベース構成(設定されている個別のデータベースが1つだけ)の場合は、articles のような修飾なしのテーブル名も動作します。2つ以上のデータベースにまたがる構成の場合にのみ修飾が必要となり、修飾なしの名前は曖昧として拒否されます。

シンプルな検索

mygram
SEARCH <table> <term>

例:

mygram
SEARCH threads golang

区切り文字以外の句読点は語句に含められます。たとえば c++e-mailv1.9.0 はそれぞれ1つの語として解析されます。

レスポンスフォーマット

SEARCHレスポンス:

mygram
OK RESULTS <total_count> <id1> <id2> <id3> ...

例:

mygram
OK RESULTS 3 101 205 387

COUNTレスポンス:

mygram
OK COUNT <number>

例:

mygram
OK COUNT 42

ブール演算子

AND検索

すべての指定された用語を含むドキュメントを検索します。

mygram
SEARCH <table> term1 AND term2 AND term3

例:

mygram
SEARCH threads golang AND tutorial

空白区切りとの違い

単純な golang tutorial も実質的には「両方を含む」検索として扱われます。複雑な条件を書く場合は、読みやすさのために AND を明示すると安全です。

OR検索

指定された用語のいずれかを含むドキュメントを検索します。

mygram
SEARCH <table> term1 OR term2 OR term3

例:

mygram
SEARCH threads golang OR python OR rust

NOT検索

特定の用語を含むドキュメントを除外します。

mygram
SEARCH <table> term1 NOT term2

例:

mygram
SEARCH threads tutorial NOT beginner

NOTの使い方

NOT は結果セットからドキュメントを除外します。先頭に NOT を置くクエリは候補が広くなりやすいため、大規模インデックスではできるだけ肯定条件と組み合わせてください。

AND NOT も同じ除外条件として受け付けます。追加条件をすべて AND の後に出力する式変換器でも使えます。

mygram
SEARCH threads tutorial AND NOT beginner

複雑なブール演算クエリ

優先順位を制御する括弧

括弧を使用して式をグループ化し、演算子の優先順位を制御できます:

mygram
SEARCH <table> (term1 OR term2) AND term3

例:

mygram
SEARCH threads (golang OR python) AND tutorial

これは「tutorial」AND(「golang」OR「python」)を含むドキュメントを検索します。

ネストした式

複数レベルの括弧をネストできます:

mygram
SEARCH <table> ((term1 OR term2) AND term3) OR term4

例:

mygram
SEARCH threads ((golang OR python) AND web) OR rust

これは以下を検索します:

  • 「web」AND(「golang」OR「python」)を含むドキュメント
  • または「rust」を含むドキュメント

複雑なクエリの例

GoまたはPythonのチュートリアルを検索し、初心者向けコンテンツを除外

mygram
SEARCH threads (golang OR python) AND tutorial NOT beginner

MySQLまたはPostgreSQLに関するデータベースコンテンツを検索し、SQLiteを除外

mygram
SEARCH posts database AND (mysql OR postgresql) NOT sqlite

PythonまたはRで機械学習コンテンツを検索し、TensorFlowを除外

mygram
SEARCH articles "machine learning" AND (python OR R) NOT tensorflow

演算子の優先順位

括弧が使用されていない場合、演算子は以下の優先順位を持ちます(高い順):

  1. NOT (最高)
  2. AND (中)
  3. OR (最低)

優先順位の例

クエリ: a OR b AND c解釈: a OR (b AND c)

クエリ: NOT a AND b解釈: (NOT a) AND b

クエリ: a AND b OR c AND d解釈: (a AND b) OR (c AND d)

括弧で意図を固定

厳密には不要な場合でも、複雑な条件では括弧を使うと読み間違いを防げます。


引用符によるフレーズ検索

語句の並びを保ったフレーズ検索には、ダブルクォーテーション " またはシングルクォーテーション ' を使います。

mygram
SEARCH <table> "exact phrase"
SEARCH <table> 'machine learning'

エスケープシーケンス

引用符で囲まれた文字列内では、次のエスケープシーケンスを使えます。

  • \n - 改行
  • \t - タブ
  • \r - キャリッジリターン
  • \\ - バックスラッシュ
  • \" - ダブルクォーテーション
  • \' - シングルクォーテーション

例:

mygram
SEARCH articles "hello \"world\""

引用符とブール演算子の組み合わせ

引用符で囲まれたフレーズはブール演算子と組み合わせることができます:

mygram
SEARCH threads "web framework" AND (golang OR python)
SEARCH posts "machine learning" NOT "deep learning"

フィルタ条件

FILTER句を使用して、カラム値で結果をフィルタリングします。

構文

mygram
SEARCH <table> <query> FILTER <column> <operator> <value> [FILTER <col> <op> <val> ...]

複数のフィルタを指定できます(すべて一致する必要があります - AND論理)。

サポートされる演算子

  • = または EQ - 等しい
  • !=<>、または NE - 等しくない
  • > または GT - より大きい
  • >= または GTE - 以上
  • < または LT - より小さい
  • <= または LTE - 以下

単一フィルタ:

mygram
SEARCH articles tech FILTER status = 1

複数フィルタ:

mygram
SEARCH articles tech FILTER status = 1 FILTER category = ai

比較演算子:

mygram
SEARCH articles tech FILTER views > 1000
SEARCH articles tech FILTER created_at >= 2024-01-01
SEARCH articles tech FILTER priority != 0
SEARCH articles tech FILTER status <> archived

ブール演算クエリと組み合わせ:

mygram
SEARCH threads (golang OR python) AND tutorial FILTER status = published

フィルタカラムの型

MygramDBでは、設定ファイルで filters に登録したカラムだけを FILTER で絞り込めます。

  • 整数: status=1, priority=5
  • 文字列: category=tech, author=john
  • 日付/時刻: created_at=2024-01-15T10:30:00, published_on=2024-01-15

FILTERには設定が必要

config.yamlfilters に登録していないカラムは FILTER で使えません。行をインデックス対象に含めるかどうかを決める required_filters とは別の設定です。

フィルタのパフォーマンス

  • ビットマップインデックス: 低カーディナリティカラム(例:status, category)で非常に高速
  • 辞書圧縮: 文字列カラムで効率的
  • フィルタリング順序: フィルタはテキスト検索の積集合の後に適用されます

ソート (SORT句)

SORT句を使用して検索結果をソートします。

構文

mygram
SEARCH <table> <query> SORT [BY] <column> [ASC|DESC]

SQLのORDER BYではありません

MygramDBでは ORDER BY 構文は使えません。検索結果の並び替えには SORT を使ってください。

BY は省略できます。SORT BY created_at DESCSORT created_at DESC は同じです。

デフォルトの動作

SORTが指定されていない場合、結果はプライマリキーの降順でソートされます(最新が最初)。

mygram
SEARCH threads golang
-- 以下と同等: SEARCH threads golang SORT id DESC

プライマリキーでソート

完全な構文:

mygram
SEARCH threads golang SORT id ASC
SEARCH threads golang SORT id DESC
SEARCH threads golang SORT BY id DESC

省略記法(推奨):

mygram
SEARCH threads golang SORT ASC   -- プライマリキー昇順
SEARCH threads golang SORT DESC  -- プライマリキー降順

フィルタカラムでソート

インデックス化された任意のフィルタカラムでソート:

mygram
SEARCH threads golang SORT created_at DESC LIMIT 10
SEARCH threads golang SORT BY created_at DESC LIMIT 10
SEARCH posts database SORT _score ASC LIMIT 20

ブール演算クエリとの組み合わせ

mygram
SEARCH threads (golang OR python) AND tutorial SORT created_at DESC LIMIT 10
SEARCH posts ((mysql OR postgresql) AND database) NOT sqlite SORT _score ASC

パフォーマンスの考慮事項

ソートアルゴリズム:

  • 小さいLIMITあり: LIMIT + OFFSET が結果件数の半分未満なら partial_sort を使います。計算量は O(N × log(K)) です(K = LIMIT + OFFSET)。
  • それ以外: 完全ソートを使います。計算量は O(N × log(N)) です。
  • メモリ: 対象件数によっては一時的なソートキー領域を確保するため、インプレース処理とは限りません。

大規模な結果セット(例:100万件中80万件がヒット)の場合:

  • LIMIT + OFFSET を結果件数より十分小さくすると、partial_sortの対象になります
  • プライマリキーでのソートも一致した結果を比較します。本番に近いデータで列ごとの性能を測定してください
  • 結果はOFFSET/LIMIT適用前にソートされます(正しいページネーション)

パフォーマンス例:

  • 80万件の結果でLIMIT 100の場合はpartial_sortの対象になります
  • 大きな結果セットでは一時的なソートキー領域が必要になることがあります

カラム検証

  • プライマリキー: 常に有効
  • フィルタカラム: 設定済みである必要があります
  • 存在しないカラム: エラーとして拒否されます

ページネーション (LIMIT/OFFSET)

LIMITOFFSETを使用して返される結果の数を制御します。

LIMIT - 最大結果数

mygram
SEARCH <table> <query> LIMIT <n>

例:

mygram
SEARCH articles tech LIMIT 10

デフォルト: 100(config.yamlのapi.default_limitで設定可能) 範囲: 1-1000。api.default_limit 自体は5〜1000の範囲でしか設定できませんが、クエリで LIMIT を明示する場合は1から1000まで指定できます。

MySQL形式の LIMIT <offset>,<count> も使えます。ただし、OFFSET 句と併用するとエラーになります。

OFFSET - 結果のスキップ

mygram
SEARCH <table> <query> OFFSET <n>

例:

mygram
SEARCH articles tech LIMIT 10 OFFSET 20

これは結果21-30を返します(最初の20件をスキップ)。

ページネーションの例

ページ1(最初の10件):

mygram
SEARCH articles tech LIMIT 10 OFFSET 0

ページ2(結果11-20):

mygram
SEARCH articles tech LIMIT 10 OFFSET 10

ページ3(結果21-30):

mygram
SEARCH articles tech LIMIT 10 OFFSET 20

クエリ長の上限

MygramDB は、検索語・AND/NOT 条件・FILTER 値を合計したクエリ式が設定された長さを超えると ERROR を返します。

  • デフォルト: 128文字
  • 設定: api.max_query_length0 で無効化)
  • エラー例: ERROR 3005 Query expression length (...) exceeds ...

複雑な条件が必要な場合は、config.yaml で上限を調整するか、複数のクエリに分割してください。

複数のオプションを組み合わせた例

mygram
SEARCH threads (golang OR python) AND tutorial
  FILTER status = published
  SORT created_at DESC
  LIMIT 10
  OFFSET 20

このクエリは:

  1. 「tutorial」AND(「golang」OR「python」)を含むドキュメントを検索
  2. 公開されたドキュメントのみにフィルタリング
  3. 作成日でソート(最新が最初)
  4. 結果21-30を返す(ページ3、1ページ10件)

ページネーションの性能

  • LIMIT最適化: LIMIT + OFFSET が結果件数の半分未満の場合だけpartial_sortを使う
  • OFFSETコスト: O(N) ただし N = OFFSET(結果は生成されますが返されません)
  • ページネーション: 一貫性のある順序が必要な場合は、SORTLIMIT を組み合わせる
  • 深いページネーション: 大きなOFFSET値(例:10000+)は遅くなる可能性があります

BM25 関連度スコアリング (SORT _score)

BM25ランキング関数を使用して、関連度順に結果をソートします。

用語補足

BM25 は、検索語の出現回数、語の珍しさ、文書の長さを使って関連度を計算する代表的なランキング方式です。単純なID順ではなく「検索語により関連していそうな文書」を上に出したい場合に使います。

構文

mygram
SEARCH <table> <query> SORT _score [ASC|DESC]

動作原理

BM25は以下に基づいて各ドキュメントの関連度スコアを計算します:

  • TF(語句頻度): ドキュメント内での検索語句の出現回数
  • IDF(逆文書頻度): 全ドキュメント中での語句の希少性
  • ドキュメント長正規化: マッチする語句を含む短いドキュメントがより高スコア

パラメータconfig.yamlbm25 セクションで変更可能):

  • bm25.k1 — 語句頻度の飽和度(デフォルト 1.2
  • bm25.b — ドキュメント長正規化(デフォルト 0.75。0 = なし、1 = 完全)

mygram
SEARCH articles "機械学習" SORT _score DESC LIMIT 10
SEARCH articles golang AND tutorial SORT _score LIMIT 20

前提条件

SORT _score には2つの設定が必要です。どちらもデフォルトは無効なので、初期設定のままではクエリが拒否されます。

設定役割未設定時のエラー
bm25.enable: true関連度スコアリングを有効化SORT _score requires BM25 to be enabled in configuration
memory.verify_text: "ascii" または "all"語句頻度を保存済み正規化テキストから数えるためSORT _score requires normalized text storage.
yaml
bm25:
  enable: true
  k1: 1.2
  b: 0.75

memory:
  verify_text: "all"  # または "ascii"

フィルタとの組み合わせ

mygram
SEARCH articles "データベース" SORT _score DESC FILTER category = tech LIMIT 10

ハイライト (HIGHLIGHT)

検索語句をタグで囲んだテキストスニペットを返します。

verify_text が必要

ハイライトは保存済みの正規化テキストからスニペットを切り出します。verify_text: "off" のままでは本文を保持しないため、ハイライトは利用できません。

構文

mygram
SEARCH <table> <query> HIGHLIGHT [TAG <open> <close>] [SNIPPET_LEN <n>] [MAX_FRAGMENTS <n>]

オプション

オプションデフォルト範囲説明
TAG<em> / </em>マッチした語句を囲むタグ
SNIPPET_LEN1001–10,000スニペットフラグメントあたりの最大コードポイント数
MAX_FRAGMENTS31–100省略記号(...)で結合されるフラグメントの最大数

デフォルトのハイライト:

mygram
SEARCH articles "機械学習" HIGHLIGHT LIMIT 10

カスタムタグ:

mygram
SEARCH articles "golang" HIGHLIGHT TAG <strong> </strong> LIMIT 10

長いスニペットとより多くのフラグメント:

mygram
SEARCH articles "データベース" HIGHLIGHT SNIPPET_LEN 200 MAX_FRAGMENTS 5 LIMIT 10

前提条件

ハイライトには、設定で verify_text"ascii" または "all" に設定する必要があります。

他の句との組み合わせ

mygram
SEARCH articles "技術" HIGHLIGHT TAG <b> </b> SORT _score DESC FILTER status = 1 LIMIT 10

あいまい検索 (FUZZY)

レーベンシュタイン編集距離(挿入、削除、置換)内の語句をマッチします。

用語補足

レーベンシュタイン編集距離は、ある文字列を別の文字列に変えるために必要な挿入・削除・置換の回数です。FUZZY 1 は1文字の打ち間違い程度、FUZZY 2 はもう少し広い候補を許容します。

構文

mygram
SEARCH <table> <query> FUZZY [distance]

パラメータ

  • distance (オプション): 1(デフォルト)または 2
    • 1: 1回の編集操作内のマッチ
    • 2: 2回の編集操作内のマッチ

mygram
SEARCH articles "まちがい" FUZZY LIMIT 10
SEARCH articles "データベス" FUZZY 2 LIMIT 10

パフォーマンス

あいまい検索は、不要な距離計算を避けるため、長さの差で事前に候補を絞り込みます。性能を優先する場合は FUZZY 1(デフォルト)を使ってください。

FUZZY に指定できる距離は 1 または 2 だけです。それ以外の値は明示的なクエリエラーになります。


エラーハンドリング

無効なクエリ

以下のクエリはエラーを返します:

空の括弧:

mygram
SEARCH threads ()
ERROR 3000 Invalid query: empty expression in parentheses

閉じられていない括弧:

mygram
SEARCH threads (golang AND python
ERROR 3000 Invalid query: unclosed parentheses

余分な閉じ括弧:

mygram
SEARCH threads golang AND python)
ERROR 3000 Invalid query: unexpected closing parenthesis

オペランドのない演算子:

mygram
SEARCH threads AND
ERROR 3000 Invalid query: operator without operands

末尾の演算子:

mygram
SEARCH threads golang AND
ERROR 3000 Invalid query: trailing operator

閉じられていない引用符:

mygram
SEARCH threads "golang tutorial
ERROR 3000 Invalid query: unclosed quote

無効なフィルタ

存在しないテーブル:

mygram
SEARCH nonexistent tech
ERROR 4007 Table not found: nonexistent

無効なフィルタカラム:

mygram
SEARCH articles tech FILTER invalid_column=1
ERROR 3006 Filter column not found: invalid_column

無効なソート

存在しないカラム:

mygram
SEARCH articles tech SORT nonexistent DESC
ERROR 3007 Sort column 'nonexistent' not found. Column does not exist as filter column or primary key. Check column name spelling.

存在しないカラムはエラーとして拒否されます。


パフォーマンスのヒント

SEARCHは決まったパイプラインで実行されます。クエリはASTに解析され、N-gram参照で候補ドキュメントが得られ、AND・NOT・FILTERが順に候補集合を絞り込み、最後にSORTとLIMIT/OFFSETが結果ページを確定します。以下の各ヒントはこのパイプラインのどこか一段階に対応しており、DEBUGコマンドも同じ名前の段階ごとに所要時間を報告します。

1. 制約の強い用語を先に配置

mygram
-- 良い: 具体的な用語を先に
SEARCH articles "machine learning" AND tutorial

-- 最適ではない: 一般的な用語を先に
SEARCH articles tutorial AND "machine learning"

2. 複雑な条件では括弧を使う

mygram
-- 明示的で読みやすい
SEARCH threads (golang OR python) AND (web OR api)

-- 理解しにくい
SEARCH threads golang OR python AND web OR api

3. 先頭のNOT演算子を避ける

mygram
-- 良い: 肯定的な用語を先に
SEARCH articles tech NOT old

-- 最適ではない: 先頭のNOT
SEARCH articles NOT old

先頭のNOTは除外前の候補が非常に広くなります。可能なら、先に肯定条件で候補を絞ってから NOT を使ってください。

4. フィルタとテキスト検索を組み合わせる

mygram
-- 良い: フィルタで早期に結果を絞り込む
SEARCH articles tech FILTER category = ai FILTER status = 1

-- 動作するが効率は劣る
SEARCH articles tech AND ai AND published

インデックス化されたカラムのフィルタは、同じ条件を通常のテキスト検索語として扱うより高速です。

5. 大規模結果セットにはLIMITを付ける

mygram
-- 良い: LIMITが結果件数に対して十分小さい場合はpartial_sortを使える
SEARCH articles tech SORT created_at DESC LIMIT 10

-- 遅い: すべての結果の完全ソート
SEARCH articles tech SORT created_at DESC

6. 深いページネーションを避ける

mygram
-- 効率的
SEARCH articles tech LIMIT 10 OFFSET 0

-- 効率が劣る(大きなOFFSET)
SEARCH articles tech LIMIT 10 OFFSET 10000

深い結果にはカーソルベースのページネーションなどの代替戦略を検討してください。


COUNTコマンド

すべてのブール演算クエリ構文はCOUNTでも使用できます:

mygram
COUNT <table> <query_expression> [FILTER ...]

例:

mygram
COUNT threads (golang OR python) AND tutorial
COUNT articles tech FILTER status = 1 FILTER category = ai
COUNT posts database AND (mysql OR postgresql) NOT sqlite

注意: COUNTはSORT、LIMIT、OFFSETをサポートしません(カウントには不要)。


実装の詳細

文法(BNF)

クエリは適切な演算子優先順位を持つ抽象構文木(AST)に解析されます:

bnf
query     → or_expr
or_expr   → and_expr (OR and_expr)*
and_expr  → not_expr (AND not_expr)*
not_expr  → NOT not_expr | primary
primary   → TERM | '(' or_expr ')'

パフォーマンス特性

  • AND演算: ソート済みポスティングリストを使用した効率的な積集合
  • OR演算: 集合演算を使用した効率的な和集合
  • NOT演算: すべてのドキュメントに対する補集合(潜在的に高コスト)
  • 括弧: パフォーマンスのオーバーヘッドなし。解析にのみ影響します

N-gramトークン化

MygramDBはインデックス作成と検索にN-gramトークン化を使用します:

  • デフォルトN-gramサイズ: 2(バイグラム) - テーブルごとに設定可能
  • CJKテキスト: 漢字/かなに対して別のN-gramサイズ(設定可能)
  • Unicode正規化: NFKC正規化、幅変換、オプションの小文字化

設定したN-gramサイズより短い検索語には、正規化済みテキストの保存が必要です。memory.verify_text: "ascii" または "all" を設定してください。設定しない場合、サーバーは不完全な結果を返さずにそのクエリを拒否します。


関連情報