7.3.57. select#

7.3.57.1. 概要#

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

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

7.3.57.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]
       [match_escalation=auto]
       [load_table=null]
       [load_columns=null]
       [load_values=null]
       [drilldown_max_n_target_records=-1]
       [n_workers=0]
       [fuzzy_max_distance_ratio=0]
       [fuzzy_max_distance=0]
       [fuzzy_max_expansions=10]
       [fuzzy_prefix_length=0]
       [fuzzy_with_transposition=yes]
       [fuzzy_tokenize=no]

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

  • 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}].max_n_target_records=-1

  • 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.57.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.57.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.57.3.2. 検索条件#

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

7.3.57.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.57.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.57.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.57.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.57.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.57.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.57.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.57.3.8. タイプミスの許容#

タイプミスとして何文字許容するかを指定することでタイプミスを許容した検索を実現できます。指定されたクエリーでどのレコードにもマッチしない場合、Groongaは自動でタイプミスを修正したクエリーで再検索します。

デフォルトではタイプミスを許容する文字数は0です。つまり、デフォルトではタイプミスを許容した検索は無効になっています。

fuzzy_max_distance_ratio または fuzzy_max_distance を指定することでタイプミスを許容した検索を実行にできます。多くの場合、 --fuzzy_max_distance_ratio 0.34 が適切なパラメーターになります。

fuzzy_max_distance_ratio は入力された各単語の文字数に応じて何文字のタイプミスを許容するかを指定します。

以下は --fuzzy_max_distance_ratio 0.34 だとタイプミスとして何文字許容するかを示した表です。

単語の文字数

許容するタイプミスの文字数

1

0 (floor(1 * 0.34) = floor(0.34) = 0)

2

0 (floor(2 * 0.34) = floor(0.68) = 0)

3

1 (floor(3 * 0.34) = floor(1.02) = 1)

4

1 (floor(4 * 0.34) = floor(1.36) = 1)

5

1 (floor(5 * 0.34) = floor(1.7) = 1)

6

2 (floor(6 * 0.34) = floor(2.04) = 2)

まとめると、Groongaは短い単語(0文字から2文字の単語)ではタイプミスを許容せず、少し長い単語(3文字から5文字の単語)では1文字のタイプミスを許容し、長い単語(6文字以上の単語)では2文字以上のタイプミスを許容します。

以下は Moronga (2文字のタイプミス)で Groonga を検索する例です。

実行例:

select \
  --table Entries \
  --fuzzy_max_distance_ratio 0.34 \
  --match_columns content \
  --query Moronga \
  --output_columns content,_score
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "_score",
#           "Int32"
#         ]
#       ],
#       [
#         "I started to use Groonga. It's very fast!",
#         1
#       ],
#       [
#         "I also started to use Mroonga. It's also very fast! Really fast!",
#         2
#       ]
#     ]
#   ]
# ]

fuzzy_max_distance を使ってタイプミスを許容する文字数を固定値で指定することもできます。たとえば、 --fuzzy_max_distance 2 と指定するとすべての単語でタイプミスとして2文字許容します。しかし、多くのケースでは --fuzzy_max_distance_ratio の方が適切です。

タイプミスを許容した検索をするためには正しい単語が必要です。Groongaは語彙表の中の単語を正しい単語として使います。このケースでは Terms が語彙表です。語彙表の中の単語はトークナイザーが生成します。データが英語のようなアルファベットベースの言語の場合、 TokenNgram を使えます。なぜなら、 TokenNgram はアルファベットベースの言語ではテクストを(ほぼ)単語にトークナイズするからです。データが日本語のような非アルファベットベースの言語の場合、 TokenNgram は使えません。なぜなら TokenNgram は非アルファベットベースの言語ではテキストをN文字毎にトークナイズするからです。非アルファベットベースの言語では形態素解析器ベースのトークナイザーを使う必要があります。たとえば、日本語には TokenMecab を使えます。(適切な辞書を用意すれば日本語以外でも TokenMecab を使えます。)

以下は日本語テキストでタイプミスを許容した検索をする例です。 JapaneseTerms--default_tokenizer TokenMecab が重要です。この例では JapaneseTerms が語彙表になります。

.. groonga-command
.. include:: ../../example/reference/commands/select/usage_typo_tolerance_japanese.log
.. table_create JapaneseEntries TABLE_NO_KEY
.. column_create JapaneseEntries content COLUMN_SCALAR Text
.. table_create JapaneseTerms TABLE_PAT_KEY ShortText \
..   --default_tokenizer TokenMecab \
..   --normalizer NormalizerNFKC150
.. column_create JapaneseTerms japanese_entries_content \
..   COLUMN_INDEX|WITH_POSITION JapaneseEntries content
.. load --table JapaneseEntries
.. [
.. {"content": "ようこそ!これが最初の投稿です!"},
.. {"content": "Groongaを使い始めました。とても速いですね!"},
.. {"content": "Mroongaも使い始めました。これもとても速いですね!本当に速い!"},
.. {"content": "Sennaのシステムをすべて移行しました!"},
.. {"content": "Tritonnのシステムもすべて移行しました!"}
.. ]
.. select \
..   --table JapaneseEntries \
..   --fuzzy_max_distance_ratio 0.34 \
..   --match_columns content \
..   --query ともて \
..   --output_columns content,_score

詳細は あいまいクエリー関連の引数 を見てください。

7.3.57.4. 引数#

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

7.3.57.4.1. 必須引数#

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

7.3.57.4.1.1. table#

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

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

実行例:

select Nonexistent
# [
#   [
#     -22,
#     1337566253.89858,
#     0.000355720520019531,
#     "[select][table] invalid name: <Nonexistent>",
#     [
#       [
#         "execute",
#         "lib/proc/proc_select.cpp",
#         5002
#       ]
#     ]
#   ]
# ]

7.3.57.4.3. 高度な検索のための引数#

7.3.57.4.3.1. match_escalation_threshold#

バージョン 8.0.1 で追加.

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

デフォルトの閾値は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.57.4.3.2. match_escalation#

検索方法のエスカレーションをどのように使うかを指定します。検索方法のエスカレーションについては match_escalation検索 を参照してください。

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

説明

auto

Groongaは match_escalation_threshold を使って検索方法をエスカレーションするかどうかを決めます。

これがデフォルトです。

yes

Groongaは常に検索方法のエスカレーションします。

no

Groongaは絶対に検索方法をエスカレーションしません。

--match_escalation yes--match_escalation_threshold 9999...999 よりも強力です。 --match_escalation yes を指定した場合は --filter 'true && column @ "query" を実行するときに検索方法をエスカレーションします。 --match_escalation_threshold 9999...999 を指定した場合は --filter 'true && column @ "query" を実行するときに検索方法をエスカレーションしません。

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

実行例:

select Entries --filter 'true && content @ "groo"'
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         0
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "content",
#           "Text"
#         ],
#         [
#           "n_likes",
#           "UInt32"
#         ],
#         [
#           "tag",
#           "ShortText"
#         ]
#       ]
#     ]
#   ]
# ]
select Entries --filter 'true && content @ "groo"' --match_escalation yes
# [
#   [
#     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 カラムの値に groo という単語を含むレコードを検索します。しかし、この検索ではどのレ"コードにもマッチしません。これは、 TokenBigram トークナイザーは groongagr|ro|oo|on|ng|ga ではなく groonga にトークナイズするからです。

2番目の select コマンドも Entries テーブルから content カラムの値に groo という単語を含むレコードを検索します。しかし、この select コマンドは検索方法をエスカレーションします。そのため、この select コマンドはマッチします。

7.3.57.4.3.3. query_expansion#

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

7.3.57.4.3.4. query_flags#

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

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

  • ALLOW_PRAGMA

  • ALLOW_COLUMN

  • ALLOW_UPDATE

  • ALLOW_LEADING_NOT

  • QUERY_NO_SYNTAX_ERROR

  • NONE

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

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

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

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

QUERY_NO_SYNTAX_ERROR を指定すると、クエリーは構文エラーにならなくなります。このフラグは、アプリケーションがユーザーの入力を直接使う時や、構文エラーをユーザーに見せたくない時、ログに記録したくない時に便利です。このフラグは、デフォルトで無効になっています。

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 を含んでいないレコードを検索します。

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

実行例:

table_create --name Magazine --flags TABLE_HASH_KEY --key_type ShortText
# [[0,1337566253.89858,0.000355720520019531],true]
column_create --table Magazine --name title --type ShortText
# [[0,1337566253.89858,0.000355720520019531],true]
load --table Magazine
[
{"_key":"http://test.jp/magazine/webplus","title":"WEB+"},
{"_key":"http://test.jp/magazine/database","title":"DataBase"},
]
# [[0,1337566253.89858,0.000355720520019531],2]

以下は QUERY_NO_SYNTAX_ERROR の使用例です。

実行例:

select Magazine --match_columns title --query 'WEB +'  --query_flags ALLOW_PRAGMA|ALLOW_COLUMN|QUERY_NO_SYNTAX_ERROR
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "title",
#           "ShortText"
#         ]
#       ],
#       [
#         1,
#         "http://test.jp/magazine/webplus",
#         "WEB+"
#       ]
#     ]
#   ]
# ]

このフラグを指定しない場合は、このクエリーは次のように構文エラーになります。

実行例:

select Magazine --match_columns title --query 'WEB +'  --query_flags ALLOW_PRAGMA|ALLOW_COLUMN
# [
#   [
#     -63,
#     1337566253.89858,
#     0.000355720520019531,
#     "Syntax error: <WEB +||>",
#     [
#       [
#         "yy_syntax_error",
#         "lib/grn_ecmascript.lemon",
#         168
#       ]
#     ]
#   ]
# ]

以下は 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.57.4.3.5. 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.57.4.3.6. n_workers#

バージョン 12.0.5 で追加.

注釈

この機能は実験的な機能です。現状、この機能はまだ安定していません。

コマンドバージョン 3 以降を指定する必要があります。

Apache Arrow が有効である必要があります。

パッケージの提供元によりApache Arrowが有効かどうかは異なります。

Apache Arrow が有効かどうかは、 status コマンドの結果で apache_arrowtrue かどうかで確認することができます。

Apache Arrow が無効な場合、 インストール の手順にしたがい、Apache Arrowを有効にしてソースコードからビルドするか、パッケージの提供元にApache Arrowを有効にするよう依頼をしてください。

このパラメータの値に -1 または 2 以上を指定すると、 drilldowndrilldowns および スライス を並列で実行します。

デフォルトでは各 drilldowndrilldownsslices を直列に実行します。つまり、1つの処理が終わったら次の処理を実行します。そのため、 drilldowndrilldownsslices がたくさんある場合は、クエリーの実行時間が長くなる傾向にあります。

n_workers を使うと依存関係のない複数の drilldowndrilldownsslices を並列に実行できます。そのため、従来はすべての処理の総和分の実行時間がかかっていたところが並列に実行する分短縮できます。この並列実行は、 select コマンドごとに行います。

依存関係がないとは、 dorilldowns.table を使用して他のドリルダウンやスライスの結果を参照していないことです。

依存関係がある場合、つまり、 drilldowns.table を使用している場合、依存するドリルダウンやスライスの処理の終了を待ちます。したがって依存関係がある場合は並列度が下がります。

並列に実行するということは、複数のCPUを同時に使用するということです。CPUのリソースに空きがないのに並列に実行しようとするとかえって遅くなることがあります。対象のCPUが実行している別処理が終わるのを待たないといけないからです。

CPUのリソースに空きがあるかどうか、どのくらいの n_workers を指定すべきかの判断基準はどのようなシステム構成かに依存します。

たとえば、CPUが6個のシステムで Groonga HTTPサーバー を使うケースを考えます。

Groonga HTTPサーバー は各リクエストごとに1スレッド(= 1CPU)を割り当てて処理します。

平均同時接続数が6のとき、CPUを既に6つ使用しているのでCPUのリソースに空きはありません。各リクエストを処理するためにすべてのCPUが使われているからです。

平均同時接続数が2のとき、リクエストを処理するためにはCPUを2つしか使用していないので、4つ空きがあります。n_workers2 を指定すると、 select コマンドはリクエストを処理するためのスレッドを含んで最大で3つのCPUを使用します。そのため、 n_workers2 を指定した select コマンドが2つ同時にリクエストされると、合計で最大で6つのCPUを使用することになりリソースをすべて使って高速に処理できます。 2 より大きな値を指定すると、CPUのリソースよりも高い並列度になってしまうので、かえって実行が遅くなる可能性があります。

n_workers は指定した値に応じて以下の動作をします。

  • 0 または 1 を指定した場合

    • 並列実行しません。

  • 2 以上を指定した場合

    • 指定したスレッド数以下で並列実行します。

  • -1 以下を指定した場合

    • CPUのコア数以下のスレッドで並列実行します。

デフォルト値は 0 です。つまり並列実行しません。

注釈

環境変数 GRN_SELECT_N_WORKERS_DEFAULT を指定することでデフォルト値を変更することができます。

7.3.57.5. 戻り値#

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

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

このコマンドが失敗すると、 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}] スタイルの出力フォーマット も見てください。

7.3.57.6. 参考#