お知らせ - 12系 — Groonga v16.1.0ドキュメント

本文へスキップ
`Ctrl`+`K`

# お知らせ - 12系

## 12.1.2リリース - 2023-01-29

### 改良

- [httpd] バンドルしているnginxのバージョンを1.23.3に更新しました。

## 12.1.1リリース - 2023-01-06

### 改良

- [select][POWER_SET] ドリルダウンでベクターのべき集合を集計できるようになりました。

  ドリルダウンに 新しいオプション `key_vector_expansion` を追加しました。 `key_vector_expansion` は、ドリルダウン対象のキーがベクターのときに、キーの展開方法を指定します。 現状は、`key_vector_expansion` には `NONE` または `POWER_SET` が指定できます。

  `key_vector_expansion` に `POWER_SET` を指定することで、べき集合での集計ができるようになります。 この集計方法は、例えばタグの出現回数と、タグの組み合わせの出現回数を一度に集計したい場合に便利です。

  以下は、 `Groonga` 、 `Mroonga` 、 `PGroonga` という３つのタグに対して、これらのタグの出現回数と、 これらの組み合わせの出現回数を集計するケースを考えます。

  実行例:

      table_create PowersetDrilldownMemos TABLE_HASH_KEY ShortText
      # [[0, 1337566253.89858, 0.000355720520019531], true]
      column_create PowersetDrilldownMemos tags COLUMN_VECTOR ShortText
      # [[0, 1337566253.89858, 0.000355720520019531], true]
      load --table PowersetDrilldownMemos
      [
      {"_key": "Groonga is fast!", "tags": ["Groonga"]},
      {"_key": "Mroonga uses Groonga!", "tags": ["Groonga", "Mroonga"]},
      {"_key": "PGroonga uses Groonga!", "tags": ["Groonga", "PGroonga"]},
      {"_key": "Mroonga and PGroonga are Groonga family", "tags": ["Groonga", "Mroonga", "PGroonga"]}
      ]
      # [[0, 1337566253.89858, 0.000355720520019531], 4]
      select PowersetDrilldownMemos \
        --drilldowns[tags].keys tags \
        --drilldowns[tags].key_vector_expansion POWER_SET \
        --drilldowns[tags].columns[power_set].stage initial \
        --drilldowns[tags].columns[power_set].value _key \
        --drilldowns[tags].columns[power_set].flags COLUMN_VECTOR \
        --drilldowns[tags].sort_keys 'power_set' \
        --drilldowns[tags].output_columns 'power_set, _nsubrecs' \
        --limit 0
      # [
      #   [
      #     0,
      #     1337566253.89858,
      #     0.000355720520019531
      #   ],
      #   [
      #     [
      #       [
      #         4
      #       ],
      #       [
      #         [
      #           "_id",
      #           "UInt32"
      #         ],
      #         [
      #           "_key",
      #           "ShortText"
      #         ],
      #         [
      #           "tags",
      #           "ShortText"
      #         ]
      #       ]
      #     ],
      #     {
      #       "tags": [
      #         [
      #           7
      #         ],
      #         [
      #           [
      #             "power_set",
      #             "Text"
      #           ],
      #           [
      #             "_nsubrecs",
      #             "Int32"
      #           ]
      #         ],
      #         [
      #           [
      #             "Groonga"
      #           ],
      #           4
      #         ],
      #         [
      #           [
      #             "Mroonga"
      #           ],
      #           2
      #         ],
      #         [
      #           [
      #             "PGroonga"
      #           ],
      #           2
      #         ],
      #         [
      #           [
      #             "Groonga",
      #             "Mroonga"
      #           ],
      #           2
      #         ],
      #         [
      #           [
      #             "Groonga",
      #             "PGroonga"
      #           ],
      #           2
      #         ],
      #         [
      #           [
      #             "Mroonga",
      #             "PGroonga"
      #           ],
      #           1
      #         ],
      #         [
      #           [
      #             "Groonga",
      #             "Mroonga",
      #             "PGroonga"
      #           ],
      #           1
      #         ]
      #       ]
      #     }
      #   ]
      # ]

  この集計結果から、以下のことがわかります。

  タグ | 登場回数
  `Groonga` | 4
  `Mroonga` | 2
  `PGroonga` | 2
  `Groonga` かつ `Mroonga` | 2
  `Groonga` かつ `PGroonga` | 2
  `Mroonga` かつ `PGroonga` | 1
  `Groonga` かつ `Mroonga` かつ `PGroonga` | 1

  複雑な機能なので、 POWER_SET も合わせて参照してください。

- [select] ベクターカラムの特定の要素のみを対象に検索できるようになりました。

  `match_columns` にベクターカラムの特定の要素をインデックス番号で指定することで、ベクターカラムの特定の要素のみを対象に検索できるようになりました。

  以下はこの機能の例です。

      table_create Memos TABLE_NO_KEY
      column_create Memos contents COLUMN_VECTOR ShortText

      table_create Lexicon TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram
      column_create Lexicon memo_index COLUMN_INDEX|WITH_POSITION|WITH_SECTION Memos contents
      load --table Memos
      [
      ["contents"],
      [["I like Groonga", "Use Groonga with Ruby"]],
      [["I like Ruby", "Use Groonga"]]
      ]
      select Memos \
        --match_columns "contents[1]" \
        --query Ruby \
        --output_columns "contents, _score"
      # [
      #   [
      #     0,
      #     0.0,
      #     0.0
      #   ],
      #   [
      #     [
      #       [
      #         1
      #       ],
      #       [
      #         [
      #           "contents",
      #           "ShortText"
      #         ],
      #         [
      #           "_score",
      #           "Int32"
      #         ]
      #       ],
      #       [
      #         [
      #           "I like Groonga",
      #           "Use Groonga with Ruby"
      #         ],
      #         1
      #       ]
      #     ]
      #   ]
      # ]

  `--match_columns "contents[1]"` とすることで、 `contents` ベクターの第2要素のみを `--query` の対象にしています。この例では、 `["I like Groonga", "Use Groonga with Ruby"]` は第2要素 `Use Groonga with Ruby` に `Ruby` を含むのでヒットしていますが、 `["I like Ruby", "Use Groonga"]` は第2要素 `Use Groonga` に `Ruby` を含まないのでヒットしていません。

- [load] `YYYY-MM-DD` 形式をサポートしました。

  `YYYY-MM-DD` は一般的な時間形式です。この形式をサポートしたことで、 `load` がより使いやすくなりました。

  ロードされた値の時間部分は、現地時間の `00:00:00` になります。

      plugin_register functions/time
      # [[0,0.0,0.0],true]
      table_create Logs TABLE_NO_KEY
      # [[0,0.0,0.0],true]
      column_create Logs created_at COLUMN_SCALAR Time
      # [[0,0.0,0.0],true]
      column_create Logs created_at_text COLUMN_SCALAR ShortText
      # [[0,0.0,0.0],true]
      load --table Logs
      [
      {"created_at": "2000-01-01", "created_at_text": "2000-01-01"}
      ]
      # [[0,0.0,0.0],1]
      select Logs --output_columns "time_format_iso8601(created_at), created_at_text"
      # [
      #   [
      #     0,
      #     0.0,
      #     0.0
      #   ],
      #   [
      #     [
      #       [
      #         1
      #       ],
      #       [
      #         [
      #           "time_format_iso8601",
      #           null
      #         ],
      #         [
      #           "created_at_text",
      #           "ShortText"
      #         ]
      #       ],
      #       [
      #         "2000-01-01T00:00:00.000000+09:00",
      #         "2000-01-01"
      #       ]
      #     ]
      #   ]
      # ]

### 修正

- [select] `command_version` が `3` のとき、 `drilldown` の結果のラベルが不正になる問題を修正しました。 [groonga-dev,05005][篠田さんの報告]

  以下はこの機能の例です。

      table_create Documents TABLE_NO_KEY
      column_create Documents tag1 COLUMN_SCALAR ShortText
      column_create Documents tag2 COLUMN_SCALAR ShortText
      load --table Documents
      [
      {"tag1": "1", "tag2": "2"}
      ]
      select Documents --drilldown tag1,tag2 --command_version 3
      # {
      #   "header": {
      #     "return_code": 0,
      #     "start_time": 1672123380.653039,
      #     "elapsed_time": 0.0005846023559570312
      #   },
      #   "body": {
      #     "n_hits": 1,
      #     "columns": [
      #       {
      #         "name": "_id",
      #         "type": "UInt32"
      #       },
      #       {
      #         "name": "tag1",
      #         "type": "ShortText"
      #       },
      #       {
      #         "name": "tag2",
      #         "type": "ShortText"
      #       }
      #     ],
      #     "records": [
      #       [
      #         1,
      #         "1",
      #         "2"
      #       ]
      #     ],
      #     "drilldowns": {
      #       "ctor": {
      #         "n_hits": 1,
      #         "columns": [
      #           {
      #             "name": "_key",
      #             "type": "ShortText"
      #           },
      #           {
      #             "name": "_nsubrecs",
      #             "type": "Int32"
      #           }
      #         ],
      #         "records": [
      #           [
      #             "1",
      #             1
      #           ]
      #         ]
      #       },
      #       "tag2": {
      #         "n_hits": 1,
      #         "columns": [
      #           {
      #             "name": "_key",
      #             "type": "ShortText"
      #           },
      #           {
      #             "name": "_nsubrecs",
      #             "type": "Int32"
      #           }
      #         ],
      #         "records": [
      #           [
      #             "2",
      #             1
      #           ]
      #         ]
      #       }
      #     }
      #   }
      # }

  `select` の実行結果の `drilldowns` 直後の `ctor` は、本来 `tag1` であるべきです。 この例では `tag1` ではなく `ctor` という値になっていますが、どのような値になるかは不定です。

- [NormalizerTable] 特定の定義が `NormalizerTable` に存在する場合、Groongaがクラッシュすることがある問題を修正しました。 [GitHub:pgroonga/pgroonga#279][i10aさんの報告]

  以下の例を考えます。

      table_create Normalizations TABLE_PAT_KEY ShortText --normalizer NormalizerNFKC130
      column_create Normalizations normalized COLUMN_SCALAR ShortText
      load --table Normalizations
      [
      {"_key": "Ⅰ", "normalized": "1"},
      {"_key": "Ⅱ", "normalized": "2"},
      {"_key": "Ⅲ", "normalized": "3"}
      ]
      normalize 'NormalizerTable("normalized", "Normalizations.normalized")'   "ⅡⅡ"

  この問題は、以下の1.、2.、3.の条件を満たした時に発生します。

  1. 対象となるテーブルのキーがノーマライズされる

     この例では、 `Normalizations` に `--normalizer NormalizerNFKC130` が指定されているので、この条件を満たしています。`Ⅰ` 、 `Ⅱ` 、 `Ⅲ` はそれぞれ `NormalizerNFKC130` によって `i` 、 `ii` 、 `iii` にノーマライズされます。

  2. ノーマライズされた文字列に他のノーマライズされた文字列が含まれている

     上記のノーマライズ後の値を考えると、 `iii` が `ii` と `i` を含んでいるため、条件を満たしています。`ii` は `i` それぞれノーマライズ前の `Ⅱ` と `Ⅰ` に対応します。

  3. 2.の文字列を複数使用する

     `normaize` の対象である `ⅡⅡ` は `NormalizerNFKC130` によって `iiii` にノーマライズされます。 この値に対して、 `Normalizations` の `NormalizerNFKC130` によるノーマライズ後の値が一致条件として使用されてノーマライズされます。

     したがって、 `iiii` を `Normalizations` でノーマライズしようとするときには、以下の順番でノーマライズされるため、この条件を満たしています。

     - 最初の `iii` （ `Ⅲ` に対応）

       NormalizerTable は最長共通接頭辞探索を行うため、 最初は `ii` や `i` ではなく `iii` が使用されます。

     - 残りの `i` （ `Ⅰ` に対応）

### 感謝

- i10aさん

- 篠田さん

## 12.1.0リリース - 2022-11-29

### 改良

- [load] `load` のスローログの出力に対応しました。

  この機能は、Groongaのパフォーマンスチューニングに使用します。例えば、 `load` が遅いときに、この機能を使うことで平均よりも時間がかかっているレコードを検出できます。

  環境変数 `GRN_SLOW_LOG_THRESHOLD` を指定することで、スローログの出力が有効になります。

  `GRN_SLOW_LOG_THRESHOLD` については以下のとおりです。

  - `GRN_SLOW_LOG_THRESHOLD` にはしきい値となる時間を秒単位で指定します。小数を指定することで、1秒よりも短い時間も指定できます。

  - `GRN_SLOW_LOG_THRESHOLD` で指定された時間よりも時間がかかっている処理がある場合、デバッグレベルのログが出力されます。

  ログレベルの設定は `log-level` オプションまたは log_level コマンドで変更可能です。

  `GRN_SLOW_LOG_THRESHOLD` にどのような値を指定すべきかは環境や調べたい内容に依存します。例えば、 `load` の件数と所要時間から、1レコードあたりの所要時間を求め、その値を指定することが考えられます。こうすることで、平均よりも `load` に時間がかかっているレコードを調べることができます。

  `load` の所要時間は クエリーログ から確認することができます。

      2022-11-16 16:41:27.139000|000000CE63AFF640|>load --table Memo
      2022-11-16 16:43:40.841000|000000CE63AFF640|:000133702000000 load(100000): [0][0][100000]
      2022-11-16 16:43:40.842000|000000CE63AFF640|:000133703000000 send(46)
      2022-11-16 16:43:40.842000|000000CE63AFF640|<000133703000000 rc=0

  この例では、所要時間は以下のようになっています。

  - レコード数: 100000件

  - 所要時間: 2分13秒 = 133秒 （ `load` の開始時間 16:43:27 と `load` の終了時間（ `rc=0` ）16:43:40 に基づいています。 ）

  - 1行あたりの所要時間: 0.00133 秒

  したがって、どのレコードが時間がかかっているのか調べるためには、 `GRN_SLOW_LOG_THRESHOLD` に `0.00133` を指定します。

  スローログを有効化すると以下の悪影響があることに注意してください。

  - パフォーマンスの悪化

  - ログサイズの肥大化

  そのため、必要な場合にのみこのスローログを有効にすることを推奨します。

- [API] 新しいAPI `grn_is_reference_count_enable()` を追加しました。

  参照カウントモードが有効になっているかどうかの真偽値を返却します。

- [API] 新しいAPI `grn_set_reference_count_enable(bool enable)` を追加しました。

  参照カウントモードの有効/無効を切り替えます。

  安全のため、複数のテーブルを開いている場合は参照カウントモードを切り替えません。

- [API] 新しいAPI `grn_is_back_trace_enable()` を追加しました。

  バックトレースの出力が有効になっているかどうかの真偽値を返却します。

- [API] 新しいAPI `grn_set_back_trace_enable(bool enable)` を追加しました。

  バックトレース(back trace)の出力の有効/無効を切り替えます。

  バックトレースの出力時にクラッシュする環境があるため、その環境では無効化します。

- [status] 新しい項目 `back_trace` と `/reference_count` を追加しました。

  `back_trace` はバックトレースの出力が有効になっているかどうかを真偽値で返却します。

  `/reference_count` は参照カウントモードが有効になっているかどうかを真偽値で返却します。

      status
      [
        [
          0,
          1654237168.304533,
          0.0001480579376220703
        ],
        {
          (omitted)
          "back_trace": true,
          "reference_count": false,
        }
      ]

### 修正

- [select][ベクターカラム] 重み付きベクターカラムで `WEIGHT_FLOAT32` を指定したとき、結果が整数で表示されていた問題を修正しました。

  参照型の重み付きベクターカラムにはこの問題はなく、参照型ではない重み付きベクターカラムにだけこの問題がありました。

  内部的な処理は浮動小数点数で行われていましたが、最終的な結果の表示が整数になっていました。

  以下は、この問題の例です。

      table_create Memos TABLE_HASH_KEY ShortText
      # [[0,0.0,0.0],true]
      column_create Memos tags COLUMN_VECTOR|WITH_WEIGHT|WEIGHT_FLOAT32 ShortText
      # [[0,0.0,0.0],true]
      load --table Memos
      [
      {
        "_key": "Groonga is fast",
        "tags": {
          "groonga": 2.8,
          "full text search": 1.2
        }
      }
      ]
      # [[0,0.0,0.0],1]
      select Memos
      # [
      #   [
      #     0,
      #     0.0,
      #     0.0
      #   ],
      #   [
      #     [
      #       [
      #         1
      #       ],
      #       [
      #         [
      #           "_id",
      #           "UInt32"
      #         ],
      #         [
      #           "_key",
      #           "ShortText"
      #         ],
      #         [
      #           "tags",
      #           "ShortText"
      #         ]
      #       ],
      #       [
      #         1,
      #         "Groonga is fast",
      #         {
      #           "groonga": 2,
      #           "full text search": 1
      #         }
      #       ]
      #     ]
      #   ]
      # ]

  `tags` カラムが `ShortText` 型の重み付きベクターカラム、つまり参照型でない重み付きベクターカラムです。

  この例の `select` の結果の以下の部分は、それぞれ2.8、1.2であるべきですが、2、1と誤った結果が返却されていました。

      {
        "groonga": 2,
        "full text search": 1
      }

  この修正により、以下のように正しい結果が返却されるようになりました。

      select Memos
      # [
      #   [
      #     0,
      #     0.0,
      #     0.0
      #   ],
      #   [
      #     [
      #       [
      #         1
      #       ],
      #       [
      #         [
      #           "_id",
      #           "UInt32"
      #         ],
      #         [
      #           "_key",
      #           "ShortText"
      #         ],
      #         [
      #           "tags",
      #           "ShortText"
      #         ]
      #       ],
      #       [
      #         1,
      #         "Groonga is fast",
      #         {
      #           "groonga": 2.8,
      #           "full text search": 1.2
      #         }
      #       ]
      #     ]
      #   ]
      # ]

## 12.0.9リリース - 2022-10-28

### 改良

- [AlmaLinux] AlmaLinux 9 向けのパッケージをサポートしました。

  12.0.8リリース - 2022-10-03 でサポートしていましたが、アナウンスしていませんでした。

- [escalate] `escalate()` 関数のドキュメントを追加しました。

- [ノーマライザー] `NormalizerHTML` を追加しました。（実験的）

  `NormalizerHTML` はHTML用のノーマライザーです。

  現在 `NormalizerHTML` は `<span>` や `</span>` といったタグの削除と、`&amp;` や `&#38;` といった文字参照の展開を行います。

  以下は `NormalizerHTML` の例です。

      normalize NormalizerHTML "<span> Groonga &amp; Mroonga &#38; Rroonga </span>"
      [[0,1666923364.883798,0.0005481243133544922],{"normalized":" Groonga & Mroonga & Rroonga ","types":[],"checks":[]}]

  この例では、 `<span>` と `</span>` は削除され、 `&amp;` と `&#38;` は `&` に展開されています。

  タグを削除するかどうかは `remove_tag` オプションで指定できます。(`remove_tag` オプションのデフォルト値は `true` です。)

      normalize 'NormalizerHTML("remove_tag", false)' "<span> Groonga &amp; Mroonga &#38; Rroonga </span>"
      [[0,1666924069.278549,0.0001978874206542969],{"normalized":"<span> Groonga & Mroonga & Rroonga </span>","types":[],"checks":[]}]

  この例では、 `<span>` と `</span>` は削除されていません。

  文字参照を展開するかどうかは `expand_character_reference` オプションで指定できます。(`expand_character_reference` オプションのデフォルト値は `true` です。)

      normalize 'NormalizerHTML("expand_character_reference", false)' "<span> Groonga &amp; Mroonga &#38; Rroonga </span>"
      [[0,1666924357.099782,0.0002346038818359375],{"normalized":" Groonga &amp; Mroonga &#38; Rroonga ","types":[],"checks":[]}]

  この例では、 `&amp;` と `&#38;` は展開されていません。

- [httpd] バンドルしているnginxのバージョンを1.23.2に更新しました。

  CVE-2022-41741とCVE-2022-41742のセキュリティの修正が含まれています。これらのセキュリティーの修正の詳細については、https://nginx.org/en/CHANGES を参照してください。

- メモリーが不足した際に、同じログが大量に出力されないように変更しました。

  メモリーが不足した際に、 `mmap failed!!!!` というメッセージが大量にログが記載されることがありました。このメッセージを可能な限り重複してログ出力されないように改良しました。

### 修正

- [select] n_workers を指定したとき、Groongaがクラッシュしたり、誤った結果を返すことがある問題を修正しました。

  この問題は、 n_workers に `1` より大きい値を指定し、かつ同時に `drilldowns[{LABEL}].filter` を使用している場合に発生していました。

  この問題は内部的な並列処理の際に、誤った値（オブジェクト）を参照していたことが原因で発生していました。そのため、上記の条件が満たされたとき、内部的に並列処理のタイミングによって、Groongaがクラッシュしたり誤った値を返すことがありました。

## 12.0.8リリース - 2022-10-03

### 改良

- `escalate()` 関数（実験的）の仕様を使いやすいように変更しました。

  `escalate()` の外部の結果セットを使用しないように変更しました。

  前回の仕様では、ユーザーはどのくらいの結果が `escalate()` に渡されるのか推測して最初のしきい値を決める必要があり、不便でした。

  以下は前回の `escalate()` の例です。

      number_column > 10 && escalate(THRESHOLD_1, CONDITION_1,
                                     ...,
                                     THRESHOLD_N, CONDITION_N)

  `CONDITION1` は `number_column > 10` の結果が `THRESHOLD_1` 以下の時に実行されます。ユーザーは `THRESHOLD_1` を決めるのに `number_column > 10` がどのくらいの結果を返すのか推測する必要がありました。

  今回のリリースから、ユーザーが `number_column > 10` がどのくらいの結果を返すのか推測する必要がなくなり、使いやすくなりました。

  この変更により、 `escalate()` の構文が以下の通り変更されています。

  前回の構文

      escalate(THRESHOLD_1, CONDITION_1,THRESHOLD_2, CONDITION_2, ..., THRESHOLD_N, CONDITION_N)

  新しい構文

      escalate(CONDITION_1, THRESHOLD_2, CONDITION_2, ..., THRESHOLD_N, CONDITION_N)

  以下は構文の変更の詳細です。

  - 最初の条件のためのしきい値は不要となりました。

  - 引数の指定を必須としました。最初の条件が必須となります。

  - 最初の引数を常に実行します。

  この関数は実験的な関数です。将来的にこれらの動作は変更になる可能性があります。

- [その他: CMakeを使ってビルド] CMakeを使ってビルドする方法を追加しました。

- [その他] GNU Autotoolsを使ってビルドする場合に、Apache Arrowの機能を有効化/無効化する方法について追加しました。

- [select] drilldowns[${LABEL}].table のドキュメントを追加しました。

- [国際化] 翻訳方法を更新しました。

### 修正

- NormalizerTable で冪等でない（繰り返し実行すると結果が変わることがある）定義をした時に、Groongaが誤った結果を返すことがある問題を修正しました。

  これは、検索する値について、値を受け取った後と、トークナイズした後の二回ノーマライズしていたことが原因です。

  Groongaはレコードを追加する時に、インデックス用のテーブルに設定したトークナイザーとノーマライザーを使って、登録するデータをトークナイズしてからノーマライズしています。検索する値についても、インデックス用のテーブルに設定したトークナイザーとノーマライザーを使って、トークナイズしてからノーマライズして、その後インデックスと照合します。両者は同じトークナイザーとノーマライザーを使うので、検索する値がインデックスに登録したデータと同じであれば、インデックスに格納されている状態と同じ状態になります。

  しかし、いままでGroongaは検索する値だけを余分にノーマライズしていました。

  NormalizerAuto といった組み込みのノーマライザーは冪等である（繰り返し実行しても結果が変わらない）ため、この問題は発生しません。一方で、 NormalizerTable はユーザー自身がノーマライザーの定義をすることができます。そのため、冪等でない（繰り返し実行すると結果が変わることがある）定義をすることができました。

  NormalizerTable に冪等でない定義が存在する場合、検索する値のみが余分にノーマライズされることで、インデックスに登録したデータと検索する値が一致しない場合がありました。

  そのような場合、ヒットするはずのデータがヒットしなかったり、ヒットしないはずのデータがヒットしたりしていました。

  以下はこの問題の例です。

      table_create ColumnNormalizations TABLE_NO_KEY
      column_create ColumnNormalizations target_column COLUMN_SCALAR ShortText
      column_create ColumnNormalizations normalized COLUMN_SCALAR ShortText

      load --table ColumnNormalizations
      [
      {"target_column": "a", "normalized": "b"},
      {"target_column": "b", "normalized": "c"}
      ]

      table_create Targets TABLE_PAT_KEY ShortText
      column_create Targets column_normalizations_target_column COLUMN_INDEX \
        ColumnNormalizations target_column

      table_create Memos TABLE_NO_KEY
      column_create Memos content COLUMN_SCALAR ShortText

      load --table Memos
      [
      {"content":"a"},
      {"content":"c"},
      ]

      table_create \
        Terms \
        TABLE_PAT_KEY \
        ShortText \
        --default_tokenizer 'TokenNgram' \
        --normalizers 'NormalizerTable("normalized", \
                                      "ColumnNormalizations.normalized", \
                                      "target", \
                                      "target_column")'

      column_create Terms memos_content COLUMN_INDEX|WITH_POSITION Memos content

      select Memos --query content:@a
      [[0,1664781132.892326,0.03527212142944336],[[[1],[["_id","UInt32"],["content","ShortText"]],[2,"c"]]]]

  `select Memos --query content:@a` の結果の期待値は `a` ですが、Groongaは `c` を返していました。これは、入力された `a` が `ColumnNormalizations` の定義にしたがって `b` にノーマライズされ、その後、 ノーマライズされた `b` を更に `c` にノーマライズしていたためです。結果的に、入力された `a` は `c` に変換され、 `Memos` テーブルの `{"content":"c"}` にマッチしていました。

## 12.0.7リリース - 2022-08-29

### 改良

- 新しい関数 `escalate()` を追加しました。(実験的)

  `escalate()` 関数は既存のマッチエスカレーション( 検索 )と似ています。この関数は、全ての条件で使えます。（既存のマッチエスカレーションは、一つの転置インデックスによる全文検索で使えます。）

  `escalate()` 関数は検索結果の数を制限したい時に便利です。検索結果の数の制限は、 `--limit` でもできますが、 `--limit` は全ての条件を評価した後に評価されます。`escalate()` 関数は結果セットが `THRESHOLD` より多くのレコードを持っていたら、その時点で評価を終了します。つまり、 `escalate()` 関数は条件の評価の数を減らせる可能性があります。

  `escalate()` の構文は以下の通りです。

      escalate(THRESHOLD_1, CONDITION_1,
               THRESHOLD_2, CONDITION_2,
               ...,
               THRESHOLD_N, CONDITION_N)

  `THRESHOLD_N` は、0や29のような正の数です。 `CONDITION_N` は `number_column > 29` のような スクリプト構文 を使った文字列です。

  現在の結果セットのレコード数が `THRESHOLD_1` 以下の場合、 `CONDITION_1` が実行されます。同様に、 `CONDITION_1` 評価後の結果セットのレコード数が `THRESHOLD_2` 以下の場合、 `CONDITION_2` が実行されます。 `CONDITION_2` 評価後の結果セットのレコード数が `THRESHOLD_3` より大きい場合、 `escalate()` は終了します。

  全ての `CONDITION` が実行された場合、 `escalate(THRESHOLD_1, CONDITION_1, ..., THRESHOLD_N, CONDITION_N)` は `CONDITION_1 || ... || CONDITION_N` と同じです。

  `escalate()` 関数は、 `&&` and `&!` のような論理演算子と一緒に使えます。:

      number_column > 10 && escalate(THRESHOLD_1, CONDITION_1,
                                     ...,
                                     THRESHOLD_N, CONDITION_N)
      number_column > 10 &! escalate(THRESHOLD_1, CONDITION_1,
                                     ...,
                                     THRESHOLD_N, CONDITION_N)

  これらは、 `number_column > 10 && (CONDITION_1 || ... || CONDITION_N)` と `number_column > 10 &! (CONDITION_1 || ... || CONDITION_N)` と同じです。

  しかし、これらの挙動は使いにくいため変更される可能性があります。

- [httpd] バンドルしているnginxのバージョンを1.23.1に更新しました。

- [select] `--n_workers` オプションのドキュメントを追加しました。

### 修正

- OR検索実行中に `request_cancel` を実行した場合、Groongaの応答が遅くなることがある問題を修正しました。

  OR検索の結果が多い場合や多くのOR条件をもつクエリー場合に、 "request_cancel" コマンドが原因でGroongaのレスポンスが遅くなることがあります。

## 12.0.6リリース - 2022-08-04

### 改良

- groonga-delta用の新しいMuninプラグインを追加しました。

  このプラグインによって、以下の項目を監視できます。

  > - `groonga-delta-import` がローカルのストレージ上の `.grn` ファイルをインポートできているかどうか。

  > - `groonga-delta-import` がMySQLの差分データをインポートできているかどうか。

  > - `groonga-delta-apply` がインポートしたデータを適用できているかどうか。

  > - 適用したデータの総サイズ。

- [column_copy] 重み付きベクターをサポートしました。

  以下のように、重み付きベクターの値を `column_copy` でコピーできます。

      table_create Tags TABLE_HASH_KEY ShortText
      [[0,0.0,0.0],true]
      table_create CopyFloat32Value TABLE_HASH_KEY ShortText
      [[0,0.0,0.0],true]
      column_create CopyFloat32Value source_tags COLUMN_VECTOR|WITH_WEIGHT|WEIGHT_FLOAT32 Tags
      [[0,0.0,0.0],true]
      column_create CopyFloat32Value destination_tags COLUMN_VECTOR|WITH_WEIGHT|WEIGHT_FLOAT32 Tags
      [[0,0.0,0.0],true]
      load --table CopyFloat32Value
      [
      {
        "_key": "Groonga is fast!!!",
        "source_tags": {
          "Groonga": 2.8,
          "full text search": 1.5
        }
      }
      ]
      [[0,0.0,0.0],1]
      column_copy CopyFloat32Value source_tags CopyFloat32Value destination_tags
      [[0,0.0,0.0],true]
      select CopyFloat32Value
      [
        [
          0,
          0.0,
          0.0
        ],
        [
          [
            [
              1
            ],
            [
              [
                "_id",
                "UInt32"
              ],
              [
                "_key",
                "ShortText"
              ],
              [
                "destination_tags",
                "Tags"
              ],
              [
                "source_tags",
                "Tags"
              ]
            ],
            [
              1,
              "Groonga is fast!!!",
              {
                "Groonga": 2.8,
                "full text search": 1.5
              },
              {
                "Groonga": 2.8,
                "full text search": 1.5
              }
            ]
          ]
        ]
      ]

- [Ubuntu] Ubuntu 21.10 (Impish Indri) のサポートをやめました。

  Ubuntu 21.10 は、2022年7月でEOLとなったためです。

- [Debian GNU/Linux] Debian 10 (buster) のサポートをやめました。

  Debian 10 は、2022年8月でEOLとなるためです。

### 修正

- `n_workers` オプションを使ってドリルダウンを並行して実行したときにGroongaがクラッシュすることがある問題を修正しました。

- [select] `--filter` に非常に長い式を指定するとシンタックスエラーになる問題を修正しました。

  今まで `--filter` 用のスタックサイズを100にしていたため発生していました。

## 12.0.5リリース - 2022-06-29

### 改良

- [select] 検索エスカレーションによる前方一致検索のパフォーマンスを少し改善しました。

- [select] `drilldowns[LABEL]._key` に重み付き参照ベクターカラムを指定できるようになりました。 [GitHub#1366][naoaさんがパッチ提供]

  今までは、ドリルダウンのキーに重み付き参照ベクターカラムを指定すると、Groongaが誤った結果を返していました。

  例えば、以下のタグ検索は、今まで誤った結果を返していました。

      table_create Tags TABLE_PAT_KEY ShortText

      table_create Memos TABLE_HASH_KEY ShortText
      column_create Memos tags COLUMN_VECTOR|WITH_WEIGHT Tags
      column_create Memos date COLUMN_SCALAR Time

      load --table Memos
      [
      {"_key": "Groonga is fast!", "tags": {"full-text-search": 100}, "date": "2014-11-16 00:00:00"},
      {"_key": "Mroonga is fast!", "tags": {"mysql": 100, "full-text-search": 80}, "date": "2014-11-16 00:00:00"},
      {"_key": "Groonga sticker!", "tags": {"full-text-search": 100, "sticker": 10}, "date": "2014-11-16 00:00:00"},
      {"_key": "Rroonga is fast!", "tags": {"full-text-search": 100, "ruby": 20}, "date": "2014-11-17 00:00:00"},
      {"_key": "Groonga is good!", "tags": {"full-text-search": 100}, "date": "2014-11-17 00:00:00"}
      ]

      select Memos \
        --drilldowns[tags].keys tags \
        --drilldowns[tags].output_columns _key,_nsubrecs
      [
        [
          0,
          1656480220.591901,
          0.0005342960357666016
        ],
        [
          [
            [
              5
            ],
            [
              [
                "_id",
                "UInt32"
              ],
              [
                "_key",
                "ShortText"
              ],
              [
                "date",
                "Time"
              ],
              [
                "tags",
                "Tags"
              ]
            ],
            [
              1,
              "Groonga is fast!",
              1416063600.0,
              {"full-text-search":100}
            ],
            [
              2,
              "Mroonga is fast!",
              1416063600.0,
              {"mysql":100,"full-text-search":80}
            ],
            [
              3,
              "Groonga sticker!",
              1416063600.0,
              {"full-text-search":100,"sticker":10}
            ],
            [
              4,
              "Rroonga is fast!",
              1416150000.0,
              {"full-text-search":100,"ruby":20}
            ],
            [
              5,
              "Groonga is good!",
              1416150000.0,
              {"full-text-search":100}
            ]
          ],
          {
            "tags": [
              [
                8
              ],
              [
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "_nsubrecs",
                  "Int32"
                ]
              ],
              [
                "full-text-search",
                5
              ],
              [
                "f",
                5
              ],
              [
                "mysql",
                1
              ],
              [
                "f",
                1
              ],
              [
                "sticker",
                1
              ],
              [
                "f",
                1
              ],
              [
                "ruby",
                1
              ],
              [
                "f",
                1
              ]
            ]
          }
        ]

  今回のリリースから上記のクエリーは、以下のように正しい結果を返します。

      select Memos   --drilldowns[tags].keys tags   --drilldowns[tags].output_columns _key,_nsubrecs
      [
        [
          0,
          0.0,
          0.0
        ],
        [
          [
            [
              5
            ],
            [
              [
                "_id",
                "UInt32"
              ],
              [
                "_key",
                "ShortText"
              ],
              [
                "date",
                "Time"
              ],
              [
                "tags",
                "Tags"
              ]
            ],
            [
              1,
              "Groonga is fast!",
              1416063600.0,
              {
                "full-text-search": 100
              }
            ],
            [
              2,
              "Mroonga is fast!",
              1416063600.0,
              {
                "mysql": 100,
                "full-text-search": 80
              }
            ],
            [
              3,
              "Groonga sticker!",
              1416063600.0,
              {
                "full-text-search": 100,
                "sticker": 10
              }
            ],
            [
              4,
              "Rroonga is fast!",
              1416150000.0,
              {
                "full-text-search": 100,
                "ruby": 20
              }
            ],
            [
              5,
              "Groonga is good!",
              1416150000.0,
              {
                "full-text-search": 100
              }
            ]
          ],
          {
            "tags": [
              [
                4
              ],
              [
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "_nsubrecs",
                  "Int32"
                ]
              ],
              [
                "full-text-search",
                5
              ],
              [
                "mysql",
                1
              ],
              [
                "sticker",
                1
              ],
              [
                "ruby",
                1
              ]
            ]
          }
        ]
      ]

- [select] `query` や `filter` や `post_filter` を使っていても、ドリルダウンのキーに重み付き参照ベクターカラムを指定できるようになりました。 [GitHub#1367][naoaさんがパッチ提供]

  今までは、 `query` や `filter` や `post_filter` を使っているときに、ドリルダウンのキーに重み付き参照ベクターカラムを指定するとGroongaは誤った結果、またはエラーを返していました。

  例えば、今まで以下のクエリーはエラーを返していました。

      table_create Tags TABLE_PAT_KEY ShortText

      table_create Memos TABLE_HASH_KEY ShortText
      column_create Memos tags COLUMN_VECTOR|WITH_WEIGHT Tags
      column_create Memos date COLUMN_SCALAR Time

      load --table Memos
      [
      {"_key": "Groonga is fast!", "tags": {"full-text-search": 100}, "date": "2014-11-16 00:00:00"},
      {"_key": "Mroonga is fast!", "tags": {"mysql": 100, "full-text-search": 80}, "date": "2014-11-16 00:00:00"},
      {"_key": "Groonga sticker!", "tags": {"full-text-search": 100, "sticker": 10}, "date": "2014-11-16 00:00:00"},
      {"_key": "Rroonga is fast!", "tags": {"full-text-search": 100, "ruby": 20}, "date": "2014-11-17 00:00:00"},
      {"_key": "Groonga is good!", "tags": {"full-text-search": 100}, "date": "2014-11-17 00:00:00"}
      ]

      select Memos \
        --filter true \
        --post_filter true \
        --drilldowns[tags].keys tags \
        --drilldowns[tags].output_columns _key,_nsubrecs
      [
        [
          -22,
          1656473820.734894,
          0.03771400451660156,
          "[hash][add][           ] key size unmatch",
          [
            [
              "grn_hash_add",
              "hash.c",
              3405
            ]
          ]
        ],
        [
          [
          ]
        ]
      ]

  今回のリリースから上記のクエリーは、以下のように正しい結果を返します。

      select Memos \
        --filter true \
        --post_filter true \
        --drilldowns[tags].keys tags \
        --drilldowns[tags].output_columns _key,_nsubrecs
      [
        [
          0,
          0.0,
          0.0
        ],
        [
          [
            [
              5
            ],
            [
              [
                "_id",
                "UInt32"
              ],
              [
                "_key",
                "ShortText"
              ],
              [
                "date",
                "Time"
              ],
              [
                "tags",
                "Tags"
              ]
            ],
            [
              1,
              "Groonga is fast!",
              1416063600.0,
              {
                "full-text-search": 100
              }
            ],
            [
              2,
              "Mroonga is fast!",
              1416063600.0,
              {
                "mysql": 100,
                "full-text-search": 80
              }
            ],
            [
              3,
              "Groonga sticker!",
              1416063600.0,
              {
                "full-text-search": 100,
                "sticker": 10
              }
            ],
            [
              4,
              "Rroonga is fast!",
              1416150000.0,
              {
                "full-text-search": 100,
                "ruby": 20
              }
            ],
            [
              5,
              "Groonga is good!",
              1416150000.0,
              {
                "full-text-search": 100
              }
            ]
          ],
          {
            "tags": [
              [
                4
              ],
              [
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "_nsubrecs",
                  "Int32"
                ]
              ],
              [
                "full-text-search",
                5
              ],
              [
                "mysql",
                1
              ],
              [
                "sticker",
                1
              ],
              [
                "ruby",
                1
              ]
            ]
          }
        ]
      ]

### 既知の問題

- 現在Groongaには、ベクターカラムに対してデータを大量に追加、削除、更新した際にデータが破損することがある問題があります。

- `*<` と `*>` は、filter条件の右辺に `query()` を使う時のみ有効です。もし、以下のように指定した場合、 `*<` と `*>` は `&&` として機能します。

  > - `'content @ "Groonga" *< content @ "Mroonga"'`

- `GRN_II_CURSOR_SET_MIN_ENABLE` が原因でマッチするはずのレコードを返さないことがあります。

### 感謝

- naoaさん

## 12.0.4リリース - 2022-06-06

### 改良

- [Ubuntu] Ubuntu 22.04 (Jammy Jellyfish)をサポートしました。

- groonga-benchmark の提供をやめました。

  誰も使用しておらず、メンテナンスもできないためです。

- [status] 新しい項目 `memory_map_size` を追加しました。

  `status` コマンドを使うことで、Groongaのメモリーマップサイズの合計を取得できます。

      status
      [
        [
          0,
          1654237168.304533,
          0.0001480579376220703
        ],
        {
          (omitted)
          "memory_map_size": 70098944
        }
      ]

  例えば、Windowsでは、Mroogaが物理メモリーとスワップ領域を使い果たした場合、それ以上メモリーをマップすることができません。そのため、この値を監視することで、メモリーが十分でない環境でもメモリーマップサイズを適切にコントロールできます。

### 修正

- 検索実行中に `request_cancel` を実行した時Groongaの応答が遅くなることがある問題を修正しました。

  特に、検索対象のレコード数が多い時に、Groongaの応答がとても遅くなることがあります。

- 文字列リストをint32のベクターにキャストできない問題を修正しました。

  例えば、以下のキャストは失敗していました。

  - ["10", "100"] -> [10, 100]

  この問題は、 `load` の引数として、 `input_type` に `apache-arrow` を指定したときのみ発生します。 この問題は、Groonga 12.0.2以降で発生します。

- GroongaのMuninプラグインがAlmaLinux 8 とCentOS 7上で動作しない問題を修正しました。

## 12.0.3リリース - 2022-04-29

### 改良

- [logical_count] `logical_count` 実行中のメモリー使用量を改善しました。

  いままで、Groongaは `logical_count` 実行中に確保したオブジェクト(オブジェクトとは、テーブルやカラム、インデックスなどです。)と一時テーブルを `logical_count` の実行完了まで保持し続けていました。

  この機能によって、Groongaは、1つのシャードを処理した後すぐに参照を減らします。そのため、Groongaは、 `logical_count` の実行中にメモリーを解放できるようになり、Groongaのメモリー使用量を削減できることがあります。

  この機能は参照カウントモードのときのみ有効です。`GRN_ENABLE_REFERENCE_COUNT=yes` と設定することで、参照カウントモードを有効にできます。

  加えて、Groongaは、この機能によって `logical_count` 実行中に一時テーブルを動的に解放します。そのため、Groongaのメモリー使用量を削減できます。この改善は、参照カウントモードが有効でなくても効果があります。

- [dump] `MISSING_IGNORE/MISSING_NIL` をサポートしました。

  `MISSING_IGNORE/MISSING_NIL` を持つカラムがある場合、これらのカラムのダンプに失敗していました。このリリースから、 `dump` コマンドはこれらのカラムをサポートしました。

- [snippet],[snippet_html] 入力としてベクターをサポートしました。[groonga-dev,04956][Reported by shinonon]

  例えば、以下のようにJSONデータ内のベクターに対して検索キーワードの周辺テキストを抽出できます。

      table_create Entries TABLE_NO_KEY
      column_create Entries title COLUMN_SCALAR ShortText
      column_create Entries contents COLUMN_VECTOR ShortText

      table_create Tokens TABLE_PAT_KEY ShortText   --default_tokenizer TokenNgram   --normalizer NormalizerNFKC130
      column_create Tokens entries_title COLUMN_INDEX|WITH_POSITION Entries title
      column_create Tokens entries_contents COLUMN_INDEX|WITH_SECTION|WITH_POSITION   Entries contents

      load --table Entries
      [
      {
        "title": "Groonga and MySQL",
        "contents": [
          "Groonga is a full text search engine",
          "MySQL is a RDBMS",
          "Mroonga is a MySQL storage engine based on Groonga"
        ]
      }
      ]

      select Entries\
        --output_columns 'snippet_html(contents), contents'\
        --match_columns 'title'\
        --query Groonga
      [
        [
          0,
          0.0,
          0.0
        ],
        [
          [
            [
              1
            ],
            [
              [
                "snippet_html",
                null
              ],
              [
                "contents",
                "ShortText"
              ]
            ],
            [
              [
                "<span class=\"keyword\">Groonga</span> is a full text search engine",
                "Mroonga is a MySQL storage engine based on <span class=\"keyword\">Groonga</span>"
              ],
              [
                "Groonga is a full text search engine",
                "MySQL is a RDBMS",
                "Mroonga is a MySQL storage engine based on Groonga"
              ]
            ]
          ]
        ]
      ]

  今までも、 `--output_columns 'snippet_html(contents[1])'` のように `snippet*` を指定することで以下のようにベクターに対して検索キーワードの周辺テキストを抽出できますが、この方法ではどの要素を出力すればよいかわかりません。どの要素が検索にヒットしたかわからないためです。

      select Entries\
        --output_columns 'snippet_html(contents[0]), contents'\
        --match_columns 'title'\
        --query Groonga
      [
        [
          0,
          0.0,
          0.0
        ],
        [
          [
            [
              1
            ],
            [
              [
                "snippet_html",
                null
              ],
              [
                "contents",
                "ShortText"
              ]
            ],
            [
              [
                "<span class=\"keyword\">Groonga</span> is a full text search engine"
              ],
              [
                "Groonga is a full text search engine",
                "MySQL is a RDBMS",
                "Mroonga is a MySQL storage engine based on Groonga"
              ]
            ]
          ]
        ]
      ]

- [`vector_join`] 新しい関数 `vector_join()` を追加しました。 [groonga-dev,04956][shinononさんの報告]

  この関数は各要素を結合します。この関数の第二引数で区切り文字を指定できます。

  例えば、以下のようにベクターに対して `snippet()` や `snippet_html()` を実行できます。

      plugin_register functions/vector

      table_create Entries TABLE_NO_KEY
      column_create Entries title COLUMN_SCALAR ShortText
      column_create Entries contents COLUMN_VECTOR ShortText

      table_create Tokens TABLE_PAT_KEY ShortText   --default_tokenizer TokenNgram   --normalizer NormalizerNFKC130
      column_create Tokens entries_title COLUMN_INDEX|WITH_POSITION Entries title
      column_create Tokens entries_contents COLUMN_INDEX|WITH_SECTION|WITH_POSITION   Entries contents

      load --table Entries
      [
      {
        "title": "Groonga and MySQL",
        "contents": [
          "Groonga is a full text search engine",
          "MySQL is a RDBMS",
          "Mroonga is a MySQL storage engine based on Groonga"
        ]
      }
      ]

      select Entries\
        --output_columns 'snippet_html(vector_join(contents, "\n")), contents'\
        --match_columns 'title'\
        --query Groonga --output_pretty yes
      [
        [
          0,
          1650849001.524027,
          0.0003361701965332031
        ],
        [
          [
            [
              1
            ],
            [
              [
                "snippet_html",
                null
              ],
              [
                "contents",
                "ShortText"
              ]
            ],
            [
              [
                "<span class=\"keyword\">Groonga</span> is a full text search engine\nMySQL is a RDBMS\nMroonga is a MySQL storage engine based on <span class=\"keyword\">Groonga</span>"
              ],
              [
                "Groonga is a full text search engine","MySQL is a RDBMS","Mroonga is a MySQL storage engine based on Groonga"
              ]
            ]
          ]
        ]
      ]

- [インデックス構築] 動的インデックス構築のようにとても大きなトークンを無視するようにしました。 [GitHub:pgroonga/pgroonga#209][Zhanzhao (Deo) Liangさんの報告]

  Groongaはエラーを発生しなくなり、静的インデックス構築を実行する時に大きなトークンを無視し警告を出力します。

### 修正

- パトリシアトライのテーブルにキーを追加できなくなることがある問題を修正しました。

  この問題は、以下の条件で発生します。

  - パトリシアトライのテーブルにすでにキーがある場合。

  - 4096バイトのキーを追加する場合。

### 既知の問題

- 現在Groongaには、ベクターカラムに対してデータを大量に追加、削除、更新した際にデータが破損することがある問題があります。

- `*<` と `*>` は、filter条件の右辺に `query()` を使う時のみ有効です。もし、以下のように指定した場合、 `*<` と `*>` は `&&` として機能します。

  > - `'content @ "Groonga" *< content @ "Mroonga"'`

- `GRN_II_CURSOR_SET_MIN_ENABLE` が原因でマッチするはずのレコードを返さないことがあります。

### 感謝

- shinononさん

- Zhanzhao (Deo) Liangさん

## 12.0.2リリース - 2022-03-29

### 改良

- [logical_range_filter] シャードを処理した直後に参照を減らすようにしました。

  今までGroongaは、 `logical_range_filter` 終了時にすべてのシャードの参照を減らしていました。この機能によって、Groongaは、シャードを処理した後すぐに参照を減らします。この機能によって、 `logical_range_filter` 実行中のメモリー使用量を削減できることがあります。

  この機能は参照カウントモードのときのみ有効です。`GRN_ENABLE_REFERENCE_COUNT=yes` と設定することで、参照カウントモードを有効にできます。

  通常、Groongaは一度でも開いたオブジェクト(テーブル、カラム、インデックスなど)をメモリ上に保持し続けますが、たくさんのオブジェクトを開いた場合、Groongaはたくさんのメモリーを使用します。参照カウントモードでは、どこからも参照されてないオブジェクトをメモリーから開放します。これにより、Groongaのメモリー使用量が減ることがあります。

- クラッシュリカバリー機能の安定性が向上しました。

  この機能は実験的で、デフォルトで無効です。したがって、以下の改良は。一般的なユーザーには影響ありません。

  - Groongaがクラッシュしたときにインデックスが破損する問題を修正しました。

  - ロックが残留する問題を修正しました。

  - クラッシュリカバリー中にGroongaがクラッシュする問題を修正しました。

- 無名マッピングが利用可能な時のmmapのパフォーマンスを向上しました。[GitHub:MariaDB/server#1999][David CARLIERさんの提案]

  この改善によって、Groongaのパフォーマンスが少し向上します。

- [インデックス構築] 以下のタイプのカラムで静的インデックス構築をサポートしました。

  - 非参照重み付きベクターカラム

  - 参照重み付きベクターカラム

  - 参照スカラーカラム

  これらのカラムは、いままで、静的インデックス構築をサポートしていませんでした。そのため、これらのカラムにデータをロードしたあとに、インデックスを構築しても、インデックスの構築時間が長くなっていました。この改良によって、このケースでインデックス構築時間が短くなります。

- [column_create] 新しいフラグ `MISSING_*` と `INVALID_*` を追加しました。

  `column_create` に以下の新しいフラグを追加しました。

  > - `MISSING_ADD`

  > - `MISSING_IGNORE`

  > - `MISSING_NIL`

  > - `INVALID_ERROR`

  > - `INVALID_WARN`

  > - `INVALID_IGNORE`

  通常、データカラムが参照データカラムで存在しないキーを指定された場合、自動的に存在しないキーを作成し、新しいレコードを作ります。

  このGroongaが参照先のカラムにキーを自動的に追加する挙動は、タグ検索のような検索で便利です。Groongaがロード時に自動的にデータを追加してくれるためです。

  しかしながら、この挙動は、キー以外の値が必要な場合に不便です。キーしか存在しないレコードがあるためです。

  このリリースで追加したフラグを使ってこの挙動を変更できます。

  > - `MISSING_ADD`: デフォルト値です。現在と同じ挙動になります。

  >   データカラムが参照データカラムで、存在しないキーを指定された場合、自動的にキーを作成し、新しいレコードを追加します。

  > - `MISSING_IGNORE`:

  >   データカラムが参照データカラムで、存在しないキーを指定された場合、存在しないキーを無視します。参照データカラムがスカラーカラムの場合、値は `GRN_ID_NIL` になります。参照データカラムがベクターカラムの場合、以下のようにその要素のみを無視します。

  >       ["existent1", "nonexistent", "existent2"] ->
  >       ["existent1" "existent2"]

  > - `MISSING_NIL`:

  >   データカラムが参照データカラムで、存在しないキーを指定された場合、スカラーカラムとベクターカラムは存在しないキーを``GRN_ID_NIL`` として扱います。

  >       ["existent1", "nonexistent", "existent2"] ->
  >       ["existent1", "" (GRN_ID_NIL), "existent2"]

  > - `INVALID_ERROR`: デフォルト値です。 ベクターカラムのエラー応答を除いて、現在と同じ挙動になります。

  >   無効な値を設定した場合(e.g.: `XXX` for `UInt8` scalar column)、設定操作をエラーとして扱います。データカラムがスカラーカラムの場合、 `load` は応答とログにエラーを報告します。データカラムがベクターカラムの場合、 `load` はログにエラーを報告しますが、応答にエラーを報告しません。これは非互換の変更です。

  > - `INVALID_WARN`:

  >   無効な値を設定した場合(e.g.: `XXX` for `UInt8` scalar column)、警告メッセージをログに記録し、設定操作を無視します。対象のデータカラムが参照ベクターカラムの場合、`MISSING_IGNORE` と `MISSING_NIL` を使って挙動を決定します。

  > - `INVALID_IGNORE`:

  >   無効な値を設定した場合(e.g.: `XXX` for `UInt8` scalar column)、設定操作を無視します。対象のデータカラムが参照ベクターカラムの場合、`MISSING_IGNORE` と `MISSING_NIL` を使って挙動を決定します。

- [dump][column_list] `MISSING_*` と `INVALID_*` フラグをサポートしました。

  これらのコマンドは、後方互換性を維持するため、 `MISSING_ADD` と `INVALID_ERROR` フラグを表示しません。これらのフラグはデフォルトの挙動を表すためです。

- [schema] `MISSING_*` と `INVALID_*` フラグをサポートしました。

  後方互換性を維持するため、 `MISSING_AND` と `INVALID_ERROR` フラグを `flag` に表示しませんがそれぞれのカラムに、新しく `missing` と `invalid` キーが追加されます。

- Amazon Linux 2向けのパッケージを提供するようにしました。

- [Windows] Visual Studio 2017 でのビルドをやめました。

  GitHub Actionsで windows-2016 のイメージが使えなくなったためです。

### 既知の問題

- 現在Groongaには、ベクターカラムに対してデータを大量に追加、削除、更新した際にデータが破損することがある問題があります。

- `*<` と `*>` は、filter条件の右辺に `query()` を使う時のみ有効です。もし、以下のように指定した場合、 `*<` と `*>` は `&&` として機能します。

  > - `'content @ "Groonga" *< content @ "Mroonga"'`

- `GRN_II_CURSOR_SET_MIN_ENABLE` が原因でマッチするはずのレコードを返さないことがあります。

### 感謝

- David CARLIERさん

## 12.0.1リリース - 2022-02-28

### 改良

- [query_expand] 同義語グループをサポートしました。

  同義語検索をする場合、今までは、以下のようにキーワードとその同義語をそれぞれ定義していました。

      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"]}
      ]

  上記のケースでは、`mroonga` を検索した場合、 Groongaは、意図通り、 `mroonga OR tritonn OR "groonga mysql" を検索しますが、``tritonn` を検索した場合は、 Groongaは、 `tritonn` のみを検索します。`tritonn` を検索した場合でも、`tritonn OR mroonga OR "groonga mysql"` と検索した場合、以下のように定義を追加する必要がありました。

      load --table Thesaurus
      [
      {"_key": "tritonn", "synonym": ["tritonn", "mroonga", "groonga mysql"]},
      ]

  多くのケースでは、 `mroonga` を `mroonga OR tritonn OR "groonga mysql"` と展開した場合、 `tritonn` や `"groonga mysql"` も `mroonga OR tritonn OR "groonga mysql"` と展開して欲しくなりますが、今までは、そのようなケースでは定義を追加する必要がありました。したがって、対象のキーワードに同義語がたくさんあると、同じような定義をたくさん定義する必要があるため、同義語の定義が煩雑でした。

  加えて、同義語を削除する際も、多くのレコードを削除する必要があるので面倒でした。

  今回のリリースから同義語の代表値を決めることで一つのグループを作れるようになりました。例えば、以下のすべてのキーワードは、 "mroonga" グループです。

      load --table Synonyms
      [
        {"_key": "mroonga": "representative": "mroonga"}
      ]

      load --table Synonyms
      [
        {"_key": "tritonn": "representative": "mroonga"},
        {"_key": "groonga mysql": "representative": "mroonga"}
      ]

  このケースでは、 `mroonga` は `mroonga OR tritonn OR "groonga mysql"` と展開されます。また、 `tritonn` や `"groonga mysql"` も `mroonga OR tritonn OR "groonga mysql"` と展開されます。

  同義語を削除する際も、対象のレコードを削除するだけです。例えば、同義語から `"groonga mysql"` を削除する場合は、 `{"_key": "groonga mysql": "representative": "mroonga"}` を削除するだけです。

- [query_expand] 同義語グループにベクターを使えるようにしました。

  以下のように、同義語グループにベクターを使えます。

      table_create SynonymGroups TABLE_NO_KEY
      [[0,0.0,0.0],true]
      column_create SynonymGroups synonyms COLUMN_VECTOR ShortText
      [[0,0.0,0.0],true]
      table_create Synonyms TABLE_PAT_KEY ShortText
      [[0,0.0,0.0],true]
      column_create Synonyms group COLUMN_INDEX SynonymGroups synonyms
      [[0,0.0,0.0],true]
      load --table SynonymGroups
      [
      ["synonyms"],
      [["rroonga", "Ruby groonga"]],
      [["groonga", "rroonga", "mroonga"]]
      ]
      [[0,0.0,0.0],2]
      query_expand Synonyms.group "rroonga"
      [
        [
          0,
          0.0,
          0.0
        ],
        "((rroonga) OR (Ruby groonga) OR (groonga) OR (rroonga) OR (mroonga))"
      ]

- 環境変数によって、バックトレースを無効にできるようにしました。

  `GRN_BACK_TRACE_ENABLE` を使うことで、バックトレースの出力を無効にできます。`GRN_BACK_TRACE_ENABLE=no` と設定すると、Groongaはバックトレースを出力しません。

  Groongaはバックトレースをスタック領域に保持します。したがって、OSによっては、Groongaがスタック領域を使い切ってしまいクラッシュする可能性があります。`GRN_BACK_TRACE_ENABLE=no` を使うことで、このようなケースを避けることができます。

- [select] `--slices` のパフォーマンスを改善しました。

- [Windows] VisualStudio 2022 をサポートしました。

- [select] 近傍検索でそれぞれの要素ごとの距離を指定できるようになりました。

  例えば、近傍フレーズ検索なら、フレーズごとに最大距離を指定できます。この機能は今後ドキュメント化されます。そのため、機能の詳細は後日、共有します。

- [Groonga HTTPサーバー] RPMパッケージのGroongaであっても、 `groonga-server-http` を使えるようにしました。

### 修正

- [Windows] Groongaがバックトレースを出力時にクラッシュする問題を修正しました。

### 既知の問題

- 現在Groongaには、ベクターカラムに対してデータを大量に追加、削除、更新した際にデータが破損することがある問題があります。

- `*<` と `*>` は、filter条件の右辺に `query()` を使う時のみ有効です。もし、以下のように指定した場合、 `*<` と `*>` は `&&` として機能します。

  > - `'content @ "Groonga" *< content @ "Mroonga"'`

- `GRN_II_CURSOR_SET_MIN_ENABLE` が原因でマッチするはずのレコードを返さないことがあります。

## 12.0.0リリース - 2022-02-09

メジャーバージョンアップです! メジャーバージョンアップですが、互換性は壊れていないので、データベースを再構築することなく12.0.0へアップグレードできます。

まずはじめに Groonga 11.0.0 から 11.1.3 までの変更点を紹介します。次に、12.0.0の主な変更点を紹介します。

### Groonga 11.0.0 から 11.1.3 までの主な変更点

#### 新規機能と改良

- [snippet] 32個以上のキーワードを使えるようにしました。

  いままで、 `snippet` は32個以上のキーワードを指定できませんでしたが、この改良によって、32個以上のキーワードを指定できます。

  通常の使用では、 `snippet` に32以上のキーワードは指定しませんが、 `query_expand` などを使うことによって自動的にキーワードが増加したときに対象のキーワードが32以上になることがあります。

  今までは、このようなケースでは、Groongaはエラーになっていましたが、この改良によって、エラーが発生しなくなります。

  詳細は、 release 11.1.3 を参照してください。

- [NormalizerNFKC130] 新しいオプション `remove_symbol` を追加しました。

  このオプションは、正規化対象の文字列から記号(例えば #, !, ", &, % 等)を削除します。例えば、歌のタイトルやアーティスト名、お店の名前等の表記ゆれの防止に使えます。

  詳細は、 release 11.1.3 を参照してください。

- [load] ISO 8601 形式をサポートしました。

  ISO 8601形式は一般的なフォーマットです。より一般的な形式をサポートしたことによって `load` の使い勝手が良くなりました。

  詳細は、 release 11.1.0 を参照してください。

- [snippet] 正規表現を使ってスニペットの区切り文字を見つける新しいオプション `delimiter_regexp` を追加しました。

  この機能は検索結果を文で表示したい時に便利です。

  snippet は、検索キーワードの周辺のテキストを抽出します。 snippet で抽出したテキストをスニペットと呼びます。

  通常、 snippet は、検索キーワードの周辺の200byteのテキストを返しますが、 snippet は、センテンスの区切りを考慮しません。スニペットは、複数のセンテンスで構成されることがあります。

  `delimiter_regexp` オプションは、検索キーワードと同じセンテンスのテキストのみを抽出したいときに便利です。例えば、 `\.\s*` を使って対象のセンテンス内のテキストのみを抽出できます。文字列は、 `\` でエスケープする必要があることに注意してください。

  詳細は、 release 11.0.9 を参照してください。

- [cache_limit] `cache_limit 0` を実行したときにクエリーキャッシュを削除するようにしました。

  Groongaは内部的なテーブルにクエリーキャッシュを保存しています。このテーブルは、ハッシュテーブルなので、トータルのキーサイズは最大で4GiBです。そのため、もし多くの巨大なクエリーを実行した場合、トータルのキーサイズの最大値4GiBを超え、Groongaがクエリーをキャッシュできない可能性があります。このようなケースで、 `cache_limit 0` を実行することで、クエリーキャッシュ用のテーブルをクリアーし、Groongaがクエリーキャッシュを保存できるようにします。

  今まではこの問題を解消するには、Groongaを再起動する必要がありましたが、この改良によって、 `cache_limit 0` を実行するだけで問題を解消できます。

  詳細は、 release 11.0.6 を参照してください。

- [between] `between()` で、条件式の評価順序の最適化をサポートしました。

  `GRN_EXPR_OPTIMIZE=yes` を設定することで、 `between()` で条件式の評価順序の最適化を使えます。この最適化は、 `between()` で十分にレコードを絞り込めるか、 `between()` でほとんどレコードを絞り込めない時に効果があります。

- [ログ] 標準出力、標準エラー出力への出力をサポートしました。

  この機能はDocker上でGroongaを実行する際に有用です。Dockerは標準で標準出力と標準エラー出力を記録する機能を持っています。したがって、Groongaのログを取得するために、Dockerの環境にログインする必要がなくなります。

  詳細は、 release 11.0.4 を参照してください。

- [query] クエリー毎に `TokenFilterStem` と `TokenFilterStopWord` を無効にできるようになりました。

  特定のクエリーでのみ `TokenFilterStem` と `TokenFilterStopWord` を無効にして検索できるようになりました。

  この機能は、検索キーワードと正確に同じ語を検索したい時に便利です。通常、ステミングやストップワードの除去を有効にしたほうが良い結果を得られますが、検索キーワードと正確に同じ語を検索したい場合は、これらの機能は不要です。

  今までは、検索キーワードと正確に同じ語を検索したい場合は、専用のインデックスを作る必要がありましたが、この改良によって、専用のインデックスを作らずに検索キーワードと正確に同じ語を検索できます。

  詳細は、 release 11.0.3 を参照してください。

- [string_slice] 新しい関数 `string_slice` を追加しました。

  `string_slice()` は、検索結果の文字列から文字の位置や正規表現を使って、部分文字列を抽出します。この機能は、検索結果を編集したい時に便利です。

  例えば、この機能は、検索結果からタグを除去するのに使えます。

- [query_parallel_or] クエリーを並行して実行できる新しい関数を追加しました。

  `query_parallel_or` は query と似ていますが、 `query_parallel_or` は複数の OR 条件を並列に処理します。この機能を使うことで、大量のOR条件の実行速度を向上できます。

  ただ、 `query_parallel_or` だけで複数のCPUを使います。したがって、 `query_parallel_or` と同時に実行しているクエリーは速度が低下する可能性があります。

- [トークンフィルター] オプションをつけた複数のトークンフィルターを使えるようにしました。

  以下の例のように、オプション付きのトークンフィルターを複数使うことができます。

      --token_filters 'TokenFilterStopWord("column", "ignore"), TokenFilterNFKC130("unify_kana", true)'

- [select] `--post_filter` と `--slices[].post_filter` をサポートしました。

  `--post_filter` と `--slices[].post_filter` を使うことで、 `--filter` 実行後に再度フィルタリングすることができます。`--post_filter` と `--slices[].post_filter` の違いは応答フォーマットです。

  `--post_filter` の応答フォーマットは、 `--filter` と同じです。`--slices[].post_filter` の応答フォーマットは `--slices[].post_filter` の実行前後の結果を出力します。

  `--slices[].post_filter` の応答フォーマットは、通常の `select` の応答と異なることに注意してください。

#### 修正

- Groongaが依存している arrow-libs がバージョンアップしたことによって、Groongaのバージョンアップが失敗する問題を修正しました。

  ただし、 arrow-libs がメジャーバージョンアップした場合は、この問題は再発します。その場合は、Groongaパッケージを再構築して対応する予定です。

  This bug only occurs AlmaLinux 8 and CentOS 7.

- [Windows] メモリー不足によって、新しくファイルのオープンに失敗した時にリソースリークする問題を修正しました。

- オプションをサポートしているトークナイザーやノーマライザー、トークンフィルターが使われている際、多くの検索クエリーを送信するとGroongaが応答を返さなくなることがある問題を修正しました。

- インデックス内のデータを大量に追加、削除、更新した際にインデックスが破損することがある問題を修正しました。

  この問題は、インデックス内のデータを大量に削除しただけでも発生します。ただ、インデックスにデータを追加しただけでは発生しません。

  詳細は、 release 11.0.0 を参照してください。

#### 新しくサポートしたOS

- [AlmaLinux] AlmaLinux 8 向けのパッケージをサポートしました。

- [AlmaLinux] ARM64版 AlmaLinux 8 向けのパッケージをサポートしました。

- [Debian GNU/Linux] Debian 11 (Bullseye) をサポートしました。

- [Debian GNU/Linux] ARM64版 Debian 11 (Bullseye) と ARM64版 Debian 10 (buster) をサポートしました。

- [Ubuntu] Ubuntu 21.10 (Impish Indri)をサポートしました。

#### サポートをやめたOS

- [CentOS] CentOS 8のサポートをやめました。

- [Ubuntu] Ubuntu 21.04 (Hirsute Hippo)のサポートをやめました。

- [Ubuntu] Ubuntu 20.10 (Groovy Gorilla)のサポートをやめました。

- [Ubuntu] Ubuntu 16.04 LTS (Xenial Xerus)のサポートをやめました。

- [Windows] Linux上のMinGWを使ってクロスコンパイルしていた以下のWindows向けパッケージの提供をやめました。

  - groonga-x.x.x-x86.exe

  - groonga-x.x.x-x86.zip

  - groonga-x.x.x-x64.exe

  - groonga-x.x.x-x86.zip

#### 感謝

- naoaさん

- Anthony M. Cookさん

- MASUDA Kazuhiroさん

- potiさん

- Takashi Hashidaさん

- higchiさん

- wi24rdさん

- Josep Sanzさん

- Keitaro YOSHIMURAさん

- shibanao4870さん

12.0.0 の主な変更点は以下の通りです。

### 改良

- [sub_filter] 新しいオプション `pre_filter_threshold` を追加しました。

  このオプションで、 `GRN_SUB_FILTER_PRE_FILTER_THRESHOLD` の値を変更できます。Groongaが `sub_filter` 実行時に レコード数が `GRN_SUB_FILTER_PRE_FILTER_THRESHOLD` 以下だった場合、Groongaは既に絞り込んだレコードに対して `sub_filter` を実行します。

  -1にすると、常にこの最適化を有効にできます。

- [index_column_have_source_record] 新しい関数 `index_column_have_source_record()` を追加しました。

  インデックスに存在するトークンがGroongaに登録されているいずれかのレコードに含まれているかどうかを確認できます。

  Groongaは、レコードの更新によってどのレコードからも使われていないトークンがあっても、それを削除しません。したがって、例えば、オートコンプリート機能を使っていると、検索候補としてどのレコードにも含まれていないトークンを返す可能性がありますが、この関数をつかうことで、不要なトークンを返さないようにできます。

  この関数は、トークンがどのレコードにも含まれていないことを検出できるからです。

- [NormalizerNFKC130] 新しいオプション `strip` を追加しました。

  このオプションは、先頭と末尾から空白を削除します。

      normalize \
      'NormalizerNFKC121("strip", true, \
                         "report_source_offset", true)' \
      "  hello world\t! \t " \
      WITH_CHECKS|WITH_TYPES
       [
         [
           0,
           0.0,
           0.0
         ],
         {
           "normalized": "hello world!",
           "types": [
             "alpha",
             "alpha",
             "alpha",
             "alpha",
             "alpha",
             "others",
             "alpha",
             "alpha",
             "alpha",
             "alpha",
             "alpha|blank",
             "symbol|blank"
           ],
           "checks": [
             3,
             1,
             1,
             1,
             1,
             1,
             1,
             1,
             1,
             1,
             1,
             2
           ],
           "offsets": [
             0,
             3,
             4,
             5,
             6,
             7,
             8,
             9,
             10,
             11,
             12,
             14
           ]
         }
       ]

- [select] 新しい引数 `drilldown_max_n_target_records` と `drilldown[${LABEL}].max_n_target_records` を追加しました。

  ドリルダウン対象のテーブル（フィルター結果）の中のうち最大で何レコードをドリルダウンに使うかを指定します。もし、フィルター結果のレコード数が指定した値より大きかったらフィルターした結果内のいくつかのレコードはドリルダウンには使われません。これらの引数のデフォルト値は、 `-1` です。これらの引数に `-1` がセットされた場合、Groongaは全てのレコードをドリルダウンに使います。

  この機能はフィルター結果が非常に大きくなるかもしれない場合に有用です。大きなフィルター結果に対するドリルダウンは遅くなることがあるためです。この機能を使うことでドリルダウンに使うレコード数を制限できます。

  以下はドリルダウンに使う最大レコード数を制限する例です。最後の2レコード（ `{"_id": 4, "tag": "Senna"}` と `{"_id": 5, "tag": "Senna"}` ）は使われていません。

      table_create Entries TABLE_HASH_KEY ShortText
      column_create Entries content COLUMN_SCALAR Text
      column_create Entries n_likes COLUMN_SCALAR UInt32
      column_create Entries tag COLUMN_SCALAR ShortText

      table_create Terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
      column_create Terms entries_key_index COLUMN_INDEX|WITH_POSITION Entries _key
      column_create Terms entries_content_index COLUMN_INDEX|WITH_POSITION Entries content
      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"}
      ]

      select Entries \
        --limit -1 \
        --output_columns _id,tag \
        --drilldown tag \
        --drilldown_max_n_target_records 3
      [
        [
          0,
          1337566253.89858,
          0.000355720520019531
        ],
        [
          [
            [
              5
            ],
            [
              [
                "_id",
                "UInt32"
              ],
              [
                "tag",
                "ShortText"
              ]
            ],
            [
              1,
              "Hello"
            ],
            [
              2,
              "Groonga"
            ],
            [
              3,
              "Groonga"
            ],
            [
              4,
              "Senna"
            ],
            [
              5,
              "Senna"
            ]
          ],
          [
            [
              2
            ],
            [
              [
                "_key",
                "ShortText"
              ],
              [
                "_nsubrecs",
                "Int32"
              ]
            ],
            [
              "Hello",
              1
            ],
            [
              "Groonga",
              2
            ]
          ]
        ]
      ]

- [httpd] バンドルしているnginxのバージョンを1.21.6に更新しました。