7.3.54. select

7.3.54.1. 概要

select はテーブルから指定された条件にマッチするレコードを検索し、見つかったレコードを出力します。

select は最も重要なgroongaのコマンドです。Groongaの力を最大限に活かすためには select を理解する必要があります。

7.3.54.2. 構文

このコマンドにはたくさんの引数があります。

必須の引数は table だけです。残りは省略できます:

select table
       [match_columns=null]
       [query=null]
       [filter=null]
       [scorer=null]
       [sortby=null]
       [output_columns="_id, _key, *"]
       [offset=0]
       [limit=10]
       [drilldown=null]
       [drilldown_sortby=null]
       [drilldown_output_columns="_key, _nsubrecs"]
       [drilldown_offset=0]
       [drilldown_limit=10]
       [cache=yes]
       [match_escalation_threshold=0]
       [query_expansion=null]
       [query_flags=ALLOW_PRAGMA|ALLOW_COLUMN]
       [query_expander=null]
       [adjuster=null]
       [drilldown_calc_types=NONE]
       [drilldown_calc_target=null]
       [drilldown_filter=null]
       [sort_keys=null]
       [drilldown_sort_keys=null]

以下の名前付き引数で動的カラム機能を使うことができます。

  • columns[${NAME}].stage=null
  • columns[${NAME}].flags=COLUMN_SCALAR
  • columns[${NAME}].type=null
  • columns[${NAME}].value=null
  • columns[${NAME}].window.sort_keys=null
  • columns[${NAME}].window.group_keys=null

${NAME} には1つ以上のアルファベット、数字、 _ を使うことができます。たとえば、 column1 は有効な ${NAME} です。これは通常のカラムと同じルールです。 name も見てください。

同じ ${NAME} も持つ引数は同じグループになります。

たとえば、以下の引数は1つの動的カラムを指定しています。

  • --columns[name].stage initial
  • --columns[name].type UInt32
  • --columns[name].value 29

以下の引数は2つの動的カラムを指定しています。

  • --columns[name1].stage initial
  • --columns[name1].type UInt32
  • --columns[name1].value 29
  • --columns[name2].stage filtered
  • --columns[name2].type Float
  • --columns[name2].value '_score * 0.1'

このコマンドには高度なドリルダウン機能のために以下の名前付き引数があります。

  • drilldowns[${LABEL}].keys=null
  • drilldowns[${LABEL}].sort_keys=null
  • drilldowns[${LABEL}].output_columns="_key, _nsubrecs"
  • drilldowns[${LABEL}].offset=0
  • drilldowns[${LABEL}].limit=10
  • drilldowns[${LABEL}].calc_types=NONE
  • drilldowns[${LABEL}].calc_target=null
  • drilldowns[${LABEL}].filter=null
  • drilldowns[${LABEL}].columns[${NAME}].stage=null
  • drilldowns[${LABEL}].columns[${NAME}].flags=COLUMN_SCALAR
  • drilldowns[${LABEL}].columns[${NAME}].type=null
  • drilldowns[${LABEL}].columns[${NAME}].value=null
  • drilldowns[${LABEL}].columns[${NAME}].window.sort_keys=null
  • drilldowns[${LABEL}].columns[${NAME}].window.group_keys=null

バージョン 6.0.3 で撤廃: drilldown[...] 構文は非推奨になりました。代わりに drilldowns[...] を使用してください。

${LABEL} には1つ以上のアルファベット、数字、 _. を使うことができます。たとえば、 parent.sub1 は有効な ${LABEL} です。

同じ ${LABEL} も持つ引数は同じグループになります。

たとえば、以下の引数は1つのドリルダウンを指定しています。

  • --drilldowns[label].keys column
  • --drilldowns[label].sort_keys -_nsubrecs

以下の引数は2つのドリルダウンを指定しています。

  • --drilldowns[label1].keys column1
  • --drilldowns[label1].sort_keys -_nsubrecs
  • --drilldowns[label2].keys column2
  • --drilldowns[label2].sort_keys _key

7.3.54.3. 使い方

例を使いながら select の使い方を学びましょう。このセクションではよく使われる使い方を紹介します。

使い方を示すために使うスキーマ定義とサンプルデータは以下の通りです。

実行例:

table_create Entries TABLE_HASH_KEY ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Entries content COLUMN_SCALAR Text
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Entries n_likes COLUMN_SCALAR UInt32
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Entries tag COLUMN_SCALAR ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
table_create Terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Terms entries_key_index COLUMN_INDEX|WITH_POSITION Entries _key
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Terms entries_content_index COLUMN_INDEX|WITH_POSITION Entries content
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table Entries
[
{"_key":    "The first post!",
 "content": "Welcome! This is my first post!",
 "n_likes": 5,
 "tag": "Hello"},
{"_key":    "Groonga",
 "content": "I started to use Groonga. It's very fast!",
 "n_likes": 10,
 "tag": "Groonga"},
{"_key":    "Mroonga",
 "content": "I also started to use Mroonga. It's also very fast! Really fast!",
 "n_likes": 15,
 "tag": "Groonga"},
{"_key":    "Good-bye Senna",
 "content": "I migrated all Senna system!",
 "n_likes": 3,
 "tag": "Senna"},
{"_key":    "Good-bye Tritonn",
 "content": "I also migrated all Tritonn system!",
 "n_likes": 3,
 "tag": "Senna"}
]
# [[0, 1337566253.89858, 0.000355720520019531], 5]

ブログエントリ用の Entries テーブルがあります。各エントリはタイトルと内容と「いいね!」数、タグを持っています。タイトルは Entries のキーとします。内容は Entries.content カラムの値とします。「いいね!」数は Entries.n_likes カラムの値とします。タグは Entries.tag カラムの値とします。

Entries._key カラムと Entries.content カラムには TokenBigram トークナイザーを使ったインデックスを作成します。そのため、 Entries._keyEntries.content は両方とも全文検索できます。

これで例を示すためのスキーマとデータの準備ができました。

7.3.54.3.1. 簡単な使い方

上記のスキーマとデータを使った一番簡単な使い方は以下の通りです。これは Entries テーブルのすべてのレコードを出力します。

実行例:

select Entries
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         5
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         1,
#         "The first post!",
#         "Welcome! This is my first post!",
#         5,
#         "Hello"
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ],
#       [
#         4,
#         "Good-bye Senna",
#         "I migrated all Senna system!",
#         3,
#         "Senna"
#       ],
#       [
#         5,
#         "Good-bye Tritonn",
#         "I also migrated all Tritonn system!",
#         3,
#         "Senna"
#       ]
#     ]
#   ]
# ]

どうしてこのコマンドがすべてのレコードを出力するのでしょうか?理由は2つです。1つ目の理由はこのコマンドが検索条件を何も指定していないからです。検索条件を指定しないとすべてのレコードがマッチします。2つ目の理由は全レコード数が5だからです。 select コマンドはデフォルトでは最大10レコードを出力します。この例では5レコードしかありません。これは10よりも少ないのですべてのレコードを出力します。

7.3.54.3.2. 検索条件

検索条件は query または filter で指定します。 queryfilter を両方指定することもできます。この場合は queryfilter の両方の条件にマッチしたレコードが出力されます。

7.3.54.3.2.1. 検索条件: query

query はWebページの検索ボックス用に用意されています。例えば、google.co.jpにあるような検索ボックスです。 query の検索条件はスペース区切りでキーワードを指定します。例えば、 検索 エンジン検索エンジン という2つのキーワードを含むレコードを検索します。

通常は query 引数は全文検索条件を指定するために使います。全文検索条件以外も指定できますが、その用途には filter 引数の方が向いています。

query 引数で全文検索条件を指定する場合は、 match_columns 引数と一緒に使います。 match_columns はどのカラムまたはインデックスを使って query を検索するかを指定します。

以下は簡単な query の使用例です。

実行例:

select Entries --match_columns content --query fast
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

この select コマンドは Entries テーブルの中から content カラムの値に fast を含んでいるレコードを検索します。

query はクエリー構文という構文を使いますが、詳細はここでは説明しません。詳細は クエリー構文 を参照してください。

7.3.54.3.2.2. 検索条件: filter

filter は複雑な検索条件を指定するために用意されています。ECMAScriptのような構文で filter に検索条件を指定します。

以下は簡単な filter の使用例です。

実行例:

select Entries --filter 'content @ "fast" && _key == "Groonga"'
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

この select コマンドは Entries テーブルの中の content カラムの値に fast という単語を含んでいて、かつ、 _keyGroonga のレコードを検索します。このコマンドの中には @&&== という3つの演算子があります。 @ は全文検索用の演算子です。 &&== はECMAScriptと同じ意味です。 && が論理積用の演算子で == が等価演算子です。

filter にはもっと演算子や構文があります。例えば、 (...) を使った検索条件のグループ化などです。しかし、ここでは詳細は説明しません。詳細は スクリプト構文 を参照してください。

7.3.54.3.3. ページング

offsetlimit を指定することで出力されるレコードの範囲を指定できます。以下は2番目のレコードだけを出力する例です。

実行例:

select Entries --offset 1 --limit 1
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         5
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

offset は0始まりです。 --offset 1 は2番目以降のレコードを出力するという意味になります。

limit は出力レコード数の最大値を指定します。 --limit 1 は多くても1レコードを出力するという意味になります。もし、1つもレコードがマッチしていなければ select コマンドはどのレコードも出力しません。

7.3.54.3.4. 全レコード数

--limit 0 を使うとレコードの内容は取得せずに全レコード数だけを取得できます。

実行例:

select Entries --limit 0
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         5
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ]
#     ]
#   ]
# ]

--limit 0 はマッチしたレコード数だけを取得したいときにも便利です。

7.3.54.3.5. ドリルダウン

1回の select で検索結果だけでなく、検索結果をグループ化した結果も一緒に取得できます。SQLでは2回以上 SELECT を使わなければいけない場合でも、Groongaの場合は1回の select で実現できます。

Groongaではこの機能を ドリルダウン と呼んでいます。他の検索エンジンでは ファセット検索 とも呼ばれています。

例えば、以下の状況を考えてみましょう。

fast という単語を含むエントリーを探します。

実行例:

select Entries --filter 'content @ "fast"'
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

--filter 'content @ "fast" && tag == "???" というように、追加の検索条件として tag を使いたいとします。しかし、 content @ "fast" の結果を見るまでは適切なタグはわかりません。

もし、有効なタグそれぞれについてマッチするレコード数がわかれば、その中から適切なタグを選ぶことができます。このような用途のためにドリルダウンを使えます。

実行例:

select Entries --filter 'content @ "fast"' --drilldown tag
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ],
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "_nsubrecs",
#           "Int32"
#         ]
#       ],
#       [
#         "Groonga",
#         2
#       ]
#     ]
#   ]
# ]

--drilldown tag は「有効なタグ」と「そのタグを持っているレコード数」のペアをリストにして返します。このリストからタグを選ぶと「検索したけどヒット数0」という状況を避けることができます。また、リストの中からレコード数が少ないタグを選べば「検索結果が多すぎる」という状況も避けることができます。

ドリルダウン結果を使うと次のようなUIを作ることができます。

  • 検索結果を絞り込むリンク。(ユーザーはキーボードから検索クエリーを入力する必要がなくなります。単にリンクをクリックすればよいからです。)

多くのECサイトではこのUIを使っています。Amazonのサイドメニューを見てください。

Groongaはグループ化したレコードの数を数えるだけでなく、グループ化したレコードのカラムの値の中から最大値・最小値を見つけたり、合計値を計算したりすることができます。詳細は ドリルダウン関連の引数 を参照してください。

7.3.54.3.6. 動的カラム

1回の select 実行中に0個以上のカラムを動的に作ることができます。この機能を使うと計算した値に対してドリルダウンしたりウィンドウ関数と使ったりできます。

以下は計算した値に対してドリルダウンするために動的カラムを使う例です。この例では n_likes_class という名前のカラムを新しく作っています。 n_likes_class カラムには Entry.n_likes の値を分類した値を入れます。この例では Entry.n_likes カラムの値を 10 刻みで分類し、一番小さい数値をその分類の代表値とします。もし、 Entry.n_likes の値が 35 のように 0 から 9 の間の値なら、 n_likes_class の値(分類した値)は 0 になります。もし、 Entry.n_likes の値が 1015 のように 10 から 19 の間の値なら、 n_likes_class の値(分類した値)は 10 になります。

このような分類をするために number_classify 関数を使えます。 number_classify 関数を使うためには plugin_register コマンドで functions/number プラグインを登録する必要があります。

この例では n_likes_class の値でドリルダウンしています。このドリルダウン結果があるとデータの傾向がわかりやすくなるでしょう。

実行例:

plugin_register functions/number
# [[0, 1337566253.89858, 0.000355720520019531], true]
select \
  --table Entries \
  --columns[n_likes_class].stage initial \
  --columns[n_likes_class].type UInt32 \
  --columns[n_likes_class].value 'number_classify(n_likes, 10)' \
  --drilldown n_likes_class \
  --drilldown_sort_keys _nsubrecs \
  --output_columns n_likes,n_likes_class
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         5
#       ],
#       [
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "n_likes_class",
#           "UInt32"
#         ]
#       ],
#       [
#         5,
#         0
#       ],
#       [
#         10,
#         10
#       ],
#       [
#         15,
#         10
#       ],
#       [
#         3,
#         0
#       ],
#       [
#         3,
#         0
#       ]
#     ],
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_key",
#           "UInt32"
#         ],
#         [
#           "_nsubrecs",
#           "Int32"
#         ]
#       ],
#       [
#         10,
#         2
#       ],
#       [
#         0,
#         3
#       ]
#     ]
#   ]
# ]

詳細は 動的カラム関連の引数 を見てください。

7.3.54.3.7. ウィンドウ関数

グループ化したレコードの値を使って各レコードの値を計算することができます。たとえば、グループ毎に合計を計算して、合計値をすべてのレコードに格納できます。ドリルダウンもグループ毎に合計を計算できますが、すべてのレコードに合計を格納するのではなく、各グループ合計を格納する点が違います。

以下はウィンドウ関数を使った結果の例です。すべてのレコードが合計値を持っています。

グループ番号

合計対象の値

合計結果

1 5 5
2 10 25
2 15 25
3 3 8
3 5 8

以下はドリルダウンを使った結果の例です。各グループが合計値を持っています。

グループ番号

合計対象の値

合計結果

1 5 5
2 10, 15 25
3 3, 5 8

ウィンドウ関数はデータ解析に有用です。

以下は Entries.tag 毎に Entries.n_likes の合計を計算する例です。

実行例:

plugin_register functions/number
# [[0, 1337566253.89858, 0.000355720520019531], true]
select \
  --table Entries \
  --columns[n_likes_sum_per_tag].stage initial \
  --columns[n_likes_sum_per_tag].type UInt32 \
  --columns[n_likes_sum_per_tag].value 'window_sum(n_likes)' \
  --columns[n_likes_sum_per_tag].window.group_keys tag \
  --output_columns tag,n_likes,n_likes_sum_per_tag
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         5
#       ],
#       [
#         [
#           "tag",
#           "ShortText"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "n_likes_sum_per_tag",
#           "UInt32"
#         ]
#       ],
#       [
#         "Hello",
#         5,
#         5
#       ],
#       [
#         "Groonga",
#         10,
#         25
#       ],
#       [
#         "Groonga",
#         15,
#         25
#       ],
#       [
#         "Senna",
#         3,
#         6
#       ],
#       [
#         "Senna",
#         3,
#         6
#       ]
#     ]
#   ]
# ]

詳細は ウィンドウ関数関連の引数 を見てください。

7.3.54.4. 引数

このセクションではすべての引数について説明します。引数はカテゴリわけしています。

7.3.54.4.1. 必須引数

table だけが必須の引数です。

7.3.54.4.1.1. table

検索対象のテーブルを指定します。 table は必ず指定しなければいけません。

存在しないテーブルを指定するとエラーが返ります。

実行例:

select Nonexistent
# [
#   [
#     -22,
#     1337566253.89858,
#     0.000355720520019531,
#     "[select][table] invalid name: <Nonexistent>",
#     [
#       [
#         "grn_select",
#         "proc_select.c",
#         3006
#       ]
#     ]
#   ]
# ]

7.3.54.4.3. 高度な検索のための引数

7.3.54.4.3.1. match_escalation_threshold

検索方法をエスカレーションするかどうかを決定するための閾値を指定します。この閾値はマッチしたレコード数との比較に使われます。マッチしたレコード数がこの閾値以下の場合は検索方法をエスカレーションします。検索方法のエスカレーションについては 検索 を参照してください。

デフォルトの閾値は0です。これは1つもレコードがマッチしなかったときだけ検索方法をエスカレーションするということです。

デフォルトの閾値は以下の方法でカスタマイズできます。

  • configureの --with-match-escalation-threshold オプション

  • groongaコマンドの --match-escalation-threshold オプション

  • 設定ファイルの match-escalation-threshold 設定項目

以下は簡単な match_escalation_threshold の使用例です。最初の selectmatch_escalation_threshold 引数がありません。2番目の selectmatch_escalation_threshold 引数があります。

実行例:

select Entries --match_columns content --query groo
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ]
#     ]
#   ]
# ]
select Entries --match_columns content --query groo --match_escalation_threshold -1
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         0
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ]
#     ]
#   ]
# ]

最初の select コマンドは Entries テーブルから content カラムの値に groo という単語を含むレコードを検索します。しかし、この検索ではどのレコードにもマッチしません。これは、 TokenBigram トークナイザーは groongagr|ro|oo|on|ng|ga ではなく groonga にトークナイズするからです。( TokenBigramSplitSymbolAlphagroongagr|ro|oo|on|ng|ga にトークナイズします。詳細は トークナイザー を見てください。)つまり、 groonga はインデックスに登録されていますが、 groo はインデックスに登録されていないということです。インデックスに登録されていないので完全一致検索では groo はどのレコードにもマッチしません。このケースでは検索方法のエスカレーションが行われています。なぜならばマッチしたレコード数(0)が match_escalation_threshold (0)の値と等しいからです。非分かち書き検索では groo で1つのレコードがマッチします。

2番目の select コマンドも Entries テーブルから content カラムの値に groo という単語を含むレコードを検索します。そして、この select コマンドもマッチしません。この場合、マッチしたレコード数(0)が match_escalation_threshold (-1)より大きいので、検索方法をエスカレーションしません。そして、1つもレコードがマッチしません。

7.3.54.4.3.2. query_expansion

バージョン 3.0.2 で撤廃: 代わりに query_expander を使ってください。

7.3.54.4.3.3. query_flags

query パラメーターの構文をカスタマイズします。デフォルトでは query パラメーターでカラムの値を更新することはできません。しかし、 query_flagsALLOW_COLUMN|ALLOW_UPDATE を指定することで query でカラムの値を更新することができます。

指定可能な値は以下の通りです。

  • ALLOW_PRAGMA
  • ALLOW_COLUMN
  • ALLOW_UPDATE
  • ALLOW_LEADING_NOT
  • NONE

ALLOW_PRAGMA を指定すると query の先頭でプラグマを指定することができます。この機能はまだ実装されていません。

ALLOW_COLUMN を指定すると match_columns で指定していないカラムでも検索できるように成ります。カラムを指定するには COLUMN:... というような構文を使います。

ALLOW_UPDATE を指定すると COLUMN:=NEW_VALUE という構文を使って query でカラムの値を更新できます。カラム更新用の構文ではカラムを指定する必要があるため、 ALLOW_COLUMN も一緒に指定する必要があります。

ALLOW_LEADING_NOT を指定すると -WORD という構文を使って最初の条件として否定条件を指定できます。このクエリーは WORD にマッチしないレコードを検索します。最初の条件に否定条件を使ったクエリーは多くの場合重いクエリーになります。これは多くのレコードにマッチするからです。そのため、このフラグはデフォルトでは無効になっています。もし、このフラグを使う場合は重いクエリーとなるということを十分気をつけてください。

NONE は単に無視されます。フラグを指定しないときに NONE を使えます。

これらのフラグは ALLOW_COLUMN|ALLOW_UPDATE のように | で区切って同時に指定することができます。

デフォルト値は ALLOW_PRAGMA|ALLOW_COLUMN です。

以下は ALLOW_COLUMN の使用例です。

実行例:

select Entries --query content:@mroonga --query_flags ALLOW_COLUMN
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

この select コマンドは Entries テーブルの中から content カラムの値に mroonga を含んでいるレコードを検索します。

以下は ALLOW_UPDATE の使用例です。

実行例:

table_create Users TABLE_HASH_KEY ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Users age COLUMN_SCALAR UInt32
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table Users
[
{"_key": "alice", "age": 18},
{"_key": "bob",   "age": 20}
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]
select Users --query age:=19 --query_flags ALLOW_COLUMN|ALLOW_UPDATE
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "age",
#           "UInt32"
#         ]
#       ],
#       [
#         1,
#         "alice",
#         19
#       ],
#       [
#         2,
#         "bob",
#         19
#       ]
#     ]
#   ]
# ]
select Users
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "age",
#           "UInt32"
#         ]
#       ],
#       [
#         1,
#         "alice",
#         19
#       ],
#       [
#         2,
#         "bob",
#         19
#       ]
#     ]
#   ]
# ]

最初の select コマンドは全てのレコードの age カラムの値を 19 にします。二番目の select コマンドは age カラムの値を出力します。

以下は ALLOW_LEADING_NOT の使用例です。

実行例:

select Entries --match_columns content --query -mroonga --query_flags ALLOW_LEADING_NOT
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         4
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         1,
#         "The first post!",
#         "Welcome! This is my first post!",
#         5,
#         "Hello"
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ],
#       [
#         4,
#         "Good-bye Senna",
#         "I migrated all Senna system!",
#         3,
#         "Senna"
#       ],
#       [
#         5,
#         "Good-bye Tritonn",
#         "I also migrated all Tritonn system!",
#         3,
#         "Senna"
#       ]
#     ]
#   ]
# ]

この select コマンドは Entries テーブルの中から content カラムの値に mroonga を含んでいないレコードを検索します。

以下は NONE の使用例です。

実行例:

select Entries --match_columns content --query 'mroonga OR _key:Groonga' --query_flags NONE
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

この select コマンドは Entries テーブルの中から content カラムの値に mroonga または _key:Groonga のどちらかの単語を含んでいるレコードを検索します。 _key:Groonga_key カラムの値が Groonga という条件にはならないことに注意してください。これは ALLOW_COLUMN フラグが指定されていないからです。

クエリー構文 も見てください。

7.3.54.4.3.4. query_expander

クエリー展開用の引数です。クエリー展開はクエリー中の特定の単語を別の単語に置換します。通常は類義語検索に使います。

query 引数の値を置換するために使うカラムを指定します。この引数の値の書式は「 ${TABLE}.${COLUMN} 」です。例えば、 「 Terms.synonym 」は Terms テーブルの synonym カラムを指定しています。

クエリー展開用のテーブルを「置換テーブル」と呼びます。置換テーブルのキーは ShortText にしてください。そのため、配列テーブル( TABLE_NO_KEY )は置換テーブルに使うことはできません。なぜなら、配列テーブルにはキーがないからです。

クエリー展開用のカラムを「置換カラム」と呼びます。置換カラムの値の型は ShortText にしてください。カラムの種類はベクター( COLUMN_VECTOR )にしてください。

クエリー展開はクエリーの中にある置換テーブルのキーを置換カラムの値で置換します。 query の中にある単語が置換テーブルのキーだったら、キーに対応する置換カラムの値でその単語を置換します。置換は再帰的に実行しません。これは、置換されたクエリー内に置換対象の単語があっても置換されないということです。

以下は query_expander の簡単な使用例を示すためのサンプル置換テーブルです。

実行例:

table_create Thesaurus TABLE_PAT_KEY ShortText --normalizer NormalizerAuto
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Thesaurus synonym COLUMN_VECTOR ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table Thesaurus
[
{"_key": "mroonga", "synonym": ["mroonga", "tritonn", "groonga mysql"]},
{"_key": "groonga", "synonym": ["groonga", "senna"]}
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]

Thesaurus 置換テーブルは2つの類義語があります。 "mroonga""groonga" です。ユーザが "mroonga" で検索すると、Groongaは "((mroonga) OR (tritonn) OR (groonga mysql))" で検索します。ユーザーが "groonga" で検索すると、Groongaは "((groonga) OR (senna))" で検索します。

通常、置換テーブルにはノーマライザーを指定したほうがよいです。たとえば、ノーマライザーを指定すると、置換対象の単語に対して大文字小文字区別せずにマッチするようになります。利用可能なノーマライザーは ノーマライザー を参照してください。

これらの類義語の値の中に "mroonga""groonga" といったキーの値も含まれていることに注意してください。このように類義語にキーの値も含めることを推奨します。もしキーの値を含めないと、置換した値には元の置換対象の値が含まれません。通常、元の値が含まれていた方がよい検索結果になります。もし、検索してほしくない単語がある場合は、元の単語を含めないでください。例えば、空のベクター値を指定することで「ストップワード」機能を実現することもできます。

以下は簡単な query_expander の使用例です。

実行例:

select Entries --match_columns content --query "mroonga"
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ]
#   ]
# ]
select Entries --match_columns content --query "mroonga" --query_expander Thesaurus.synonym
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ],
#       [
#         5,
#         "Good-bye Tritonn",
#         "I also migrated all Tritonn system!",
#         3,
#         "Senna"
#       ]
#     ]
#   ]
# ]
select Entries --match_columns content --query "((mroonga) OR (tritonn) OR (groonga mysql))"
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ],
#       [
#         5,
#         "Good-bye Tritonn",
#         "I also migrated all Tritonn system!",
#         3,
#         "Senna"
#       ]
#     ]
#   ]
# ]

最初の select コマンドはクエリー展開を使いません。そのため、 "tritonn" という単語を含んでいるレコードは見つかりません。2番目の select コマンドはクエリー展開を使っています。そのため、 "tritonn" という単語を含んでいるレコードが見つかります。3番目の select コマンドはクエリー展開を使っていませんが、2番目の select コマンドと同じ結果になります。これは、3番目の select コマンドは展開後のクエリーを使っているからです。

それぞれの置換する値は (...)OR といった クエリー構文 を使えます。これらの構文を使うことにより複雑な置換をすることができます。

以下はクエリー構文を使った複雑な置換の使用例です。

実行例:

load --table Thesaurus
[
{"_key": "popular", "synonym": ["popular", "n_likes:>=10"]}
]
# [[0, 1337566253.89858, 0.000355720520019531], 1]
select Entries --match_columns content --query "popular" --query_expander Thesaurus.synonym
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "Groonga",
#         "I started to use Groonga. It's very fast!",
#         10,
#         "Groonga"
#       ],
#       [
#         3,
#         "Mroonga",
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         15,
#         "Groonga"
#       ]
#     ]
#   ]
# ]

この load コマンドは新しく "popular" という類義語を登録しています。これは ((popular) OR (n_likes:>=10)) に置換されます。置換されたクエリーは、「popular」というのは「popular」という単語を含んでいるか10以上の「いいね!」数を持つエントリという意味になります。

この select コマンドは Entries テーブルの中から n_likes カラムの値が 10 以上のレコードを出力します。

7.3.54.5. 戻り値

select は以下のフォーマットのレスポンスを返します:

[
  HEADER,
  [
    SEARCH_RESULT,
    DRILLDOWN_RESULT_1,
    DRILLDOWN_RESULT_2,
    ...,
    DRILLDOWN_RESULT_N
  ]
]

select が失敗すると、 HEADER にエラーの詳細が含まれます。

HEADER については 出力形式 を参照してください。

0個以上の DRILLDOWN_RESULT があります。もし、 drilldowndrilldowns[${LABEL}].keys も指定していない場合、次のように DRILLDOWN_RESULT は出力されません:

[
  HEADER,
  [
    SEARCH_RESULT
  ]
]

--drilldown "_key, column1, column2" というように drilldown に2つ以上のキーがある場合、複数の DRILLDOWN_RESULT が存在します:

[
  HEADER,
  [
    SEARCH_RESULT,
    DRILLDOWN_RESULT_FOR_KEY,
    DRILLDOWN_RESULT_FOR_COLUMN1,
    DRILLDOWN_RESULT_FOR_COLUMN2
  ]
]

もし drilldowns[${LABEL}].keys を使っているなら、 DRILLDOWN_RESULT が1つだけ存在します:

[
  HEADER,
  [
    SEARCH_RESULT,
    DRILLDOWN_RESULT_FOR_LABELED_DRILLDOWN
  ]
]

DRILLDOWN_RESULT のフォーマットは drilldowndrilldowns[${LABEL}].keys で違います。これについては後述します。

SEARCH_RESULT は以下のフォーマットです:

[
  [N_HITS],
  COLUMNS,
  RECORDS
]

このフォーマットの具体例は 簡単な使い方 を見てください。

N_HITSlimit を適用する前のマッチしたレコード数です。

COLUMNSoutput_columns で指定した出力カラムの情報を表しています。これは次のフォーマットになっています:

[
  [COLUMN_NAME_1, COLUMN_TYPE_1],
  [COLUMN_NAME_2, COLUMN_TYPE_2],
  ...,
  [COLUMN_NAME_N, COLUMN_TYPE_N]
]

COLUMNS は1つ以上の出力カラムの情報を含んでいます。各出力カラムの情報は次の情報を含んでいます。

  • カラム名(文字列)

  • カラムの型(文字列または null

カラム名は output_columns で指定された値から抽出しています。

カラムの方はGroongaでの型名または null です。カラムがベクターかスカラーかの情報は持っていません。実際のカラムの値が配列かどうかで判断する必要があります。

型の詳細は データ型 を見てください。

null になるときはカラムの値の型を決められないときです。たとえば、 --output_columns "snippet_html(content)" というように output_columns の中で関数呼び出しを使ったときは null になります。

以下は COLUMNS の使用例です:

[
  ["_id",     "UInt32"],
  ["_key",    "ShortText"],
  ["n_likes", "UInt32"],
]

RECORDS はマッチした各レコードのカラムの値を含んでいます。 RECORDS に含まれるレコードは offsetlimit で選択されたレコードです。 RECORDS は次のフォーマットです:

[
  [
    RECORD_1_COLUMN_1,
    RECORD_1_COLUMN_2,
    ...,
    RECORD_1_COLUMN_N
  ],
  [
    RECORD_2_COLUMN_1,
    RECORD_2_COLUMN_2,
    ...,
    RECORD_2_COLUMN_N
  ],
  ...
  [
    RECORD_N_COLUMN_1,
    RECORD_N_COLUMN_2,
    ...,
    RECORD_N_COLUMN_N
  ]
]

以下は RECORDS の例です:

[
  [
    1,
    "The first post!",
    5
  ],
  [
    2,
    "Groonga",
    10
  ],
  [
    3,
    "Mroonga",
    15
  ]
]

DRILLDOWN_RESULT のフォーマットは drilldowndrilldowns[${LABEL}].keys で違います。

drilldownSEARCH_RESULT と同じフォーマットです:

[
  [N_HITS],
  COLUMNS,
  RECORDS
]

drilldown で1つ以上のキーを指定すると、 drilldown は1つ以上の DRILLDOWN_RESULT を出力します。

drilldowns[${LABEL}].keys は次のフォーマットを使います。複数の drilldowns[${LABEL}].keys は1つのオブジェクト(キーと値のペアの集合)になります:

{
  "LABEL_1": [
    [N_HITS],
    COLUMNS,
    RECORDS
  ],
  "LABEL_2": [
    [N_HITS],
    COLUMNS,
    RECORDS
  ],
  ...,
  "LABEL_N": [
    [N_HITS],
    COLUMNS,
    RECORDS
  ]
}

drilldowns[${LABEL}].keys は次の部分に対応します:

"LABEL": [
  [N_HITS],
  COLUMNS,
  RECORDS
]

以下の値の部分は SEARCH_RESULT と同じフォーマットです:

[
  [N_HITS],
  COLUMNS,
  RECORDS
]

drilldownss[${LABEL}] スタイルのドリルダウンの出力形式については drilldowns[${LABEL}] スタイルの出力フォーマット も見てください。