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

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

# お知らせ - 10系

## 10.1.1リリース - 2021-01-25

### 改良

- [select] Apache Arrow形式でUInt64の値の出力をサポートしました。

- [select] Apache Arrow形式で以下のようにヒット数の出力をサポートしました。

      -- metadata --
      GROONGA:n-hits: 10

- [query] "order by estimated size" の最適化をサポートしました。

  - 通常、ヒット数の少ない条件から最初に実行すると、高速に検索できます。

    - "A (ヒット数が多い) && B (ヒット数が少ない)" より "B (ヒット数が少ない) && A (ヒット数が多い)" 方が高速です。

  - これは、よく知られた最適化ですが、自分で条件を並び替える必要があります。

  - Groongaは、 "order by estimated size" の最適化を使うことで、自動的にこの並び替えを実行します。

  - この最適化は、 `GRN_ORDER_BY_ESTIMATED_SIZE_ENABLE=yes` で有効になります。

- [between] 以下の改良で、パフォーマンスを改善しました。

  - `between()` でシーケンシャルサーチを使うかどうかの判断の精度を改善しました。

  - `between()` の結果を結果セットに一度にセットするよう改善しました。

- [select] 前方一致検索のパフォーマンスを改善しました。

  - 例えば、以下のような "*" を使った前方一致検索のパフォーマンスが向上します。

        table_create Memos TABLE_PAT_KEY ShortText
        table_create Contents TABLE_PAT_KEY ShortText   --normalizer NormalizerAuto
        column_create Contents entries_key_index COLUMN_INDEX Memos _key

        load --table Memos
        [
        {"_key": "(groonga) Start to try!"},
        {"_key": "(mroonga) Installed"},
        {"_key": "(groonga) Upgraded!"}
        ]

        select \
          --table Memos \
          --match_columns _key \
          --query '\\(groonga\\)*'

- [トークナイザー][TokenMecab] トークンカラムを並列で構築する際のパフォーマンスを改善しました。 [GitHub#1158][naoaさんがパッチ提供]

### 修正

- [sub_filter] `slices[].filter` 内で `sub_filter` が動作しない問題を修正しました。

  - 例えば、以下のクエリーでは、この問題によって、 `sub_filter` の結果は0件になります。

        table_create Users TABLE_HASH_KEY ShortText
        column_create Users age COLUMN_SCALAR UInt8

        table_create Memos TABLE_NO_KEY
        column_create Memos user COLUMN_SCALAR Users
        column_create Memos content COLUMN_SCALAR Text

        load --table Users
        [
        {"_key": "alice", "age": 9},
        {"_key": "bob",   "age": 29}
        ]

        load --table Memos
        [
        {"user": "alice", "content": "hello"},
        {"user": "bob",   "content": "world"},
        {"user": "alice", "content": "bye"},
        {"user": "bob",   "content": "yay"}
        ]

        select \
          --table Memos \
          --slices[adult].filter '_id > 1 && sub_filter(user, "age >= 18")'

- ハッシュテーブルに対して、繰り返し大量のデータを追加、削除すると、Groongaがクラッシュしたり、データの追加ができなくなる可能性がある問題を修正しました。

### 感謝

- naoaさん

## 10.1.0リリース - 2020-12-29

### 改良

- [highlight_html] 全角スペースをハイライト対処から除外しました。[PGroonga#GitHub#155][Hung Nguyen Vさんが報告]

  - 今までは、以下のように先頭の全角スペースも含めてハイライト対象としていました。

        table_create Entries TABLE_NO_KEY
        column_create Entries body COLUMN_SCALAR ShortText

        table_create Terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
        column_create Terms document_index COLUMN_INDEX|WITH_POSITION Entries body

        load --table Entries
        [
        {"body": "Groonga　高速！"}
        ]

        select Entries --output_columns \
          --match_columns body --query '高速' \
          --output_columns 'highlight_html(body)'
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                1
              ],
              [
                [
                  "highlight_html",
                  null
                ]
              ],
              [
                "Groonga<span class=\"keyword\">　高速</span>！"
              ]
            ]
          ]
        ]

  - しかし、この全角スペースはハイライト対象としては不要です。そのため、このリリースから `highlight_html()` は先頭の全角スペースを削除します。

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

  - 以下のように、Groongaのどの機能が有効なのかを表示できます。

        status --output_pretty yes
        [
          [
            0,
            0.0,
            0.0
          ],
          {
            "alloc_count": 361,
            "starttime": 1608087311,
            "start_time": 1608087311,
            "uptime": 35,
            "version": "10.1.0",
            "n_queries": 0,
            "cache_hit_rate": 0.0,
            "command_version": 1,
            "default_command_version": 1,
            "max_command_version": 3,
            "n_jobs": 0,
            "features": {
              "nfkc": true,
              "mecab": true,
              "message_pack": true,
              "mruby": true,
              "onigmo": true,
              "zlib": true,
              "lz4": false,
              "zstandard": false,
              "kqueue": false,
              "epoll": true,
              "poll": false,
              "rapidjson": false,
              "apache_arrow": false,
              "xxhash": false
            }
          }
        ]

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

  - 以下のようにGroongaが使うApache Arrowのバージョンを表示できます。

      [
        [
          0,
          1608088628.440753,
          0.0006628036499023438
        ],
        {
          "alloc_count": 360,
          "starttime": 1608088617,
          "start_time": 1608088617,
          "uptime": 11,
          "version": "10.0.9-39-g5a4c6f3",
          "n_queries": 0,
          "cache_hit_rate": 0.0,
          "command_version": 1,
          "default_command_version": 1,
          "max_command_version": 3,
          "n_jobs": 0,
          "features": {
            "nfkc": true,
            "mecab": true,
            "message_pack": true,
            "mruby": true,
            "onigmo": true,
            "zlib": true,
            "lz4": true,
            "zstandard": false,
            "kqueue": false,
            "epoll": true,
            "poll": false,
            "rapidjson": false,
            "apache_arrow": true,
            "xxhash": false
          },
          "apache_arrow": {
            "version_major": 2,
            "version_minor": 0,
            "version_patch": 0,
            "version": "2.0.0"
          }
        }
      ]

  - この項目は、Apache Arrowが有効な場合にのみ表示されます。

- [ウィンドウ関数] 対象のテーブルがシャードをまたいでいる場合でも、全てのテーブルを一度に処理するようにしました。(実験的)

  - 今まで、対象のテーブルがシャードをまたいでいた場合、ウインドウ関数はシャード毎に処理をしていました。

    - そのため、複数のグループキーを使う場合、2番目以降のグループキーの値は1種類でなければなりませんでした。

    - この改良によって、以下のように複数の種類の値を2番目以降のグループキーで使用できるようになります。

          plugin_register sharding
          plugin_register functions/time

          table_create Logs_20170315 TABLE_NO_KEY
          column_create Logs_20170315 timestamp COLUMN_SCALAR Time
          column_create Logs_20170315 price COLUMN_SCALAR UInt32
          column_create Logs_20170315 item COLUMN_SCALAR ShortText

          table_create Logs_20170316 TABLE_NO_KEY
          column_create Logs_20170316 timestamp COLUMN_SCALAR Time
          column_create Logs_20170316 price COLUMN_SCALAR UInt32
          column_create Logs_20170316 item COLUMN_SCALAR ShortText

          table_create Logs_20170317 TABLE_NO_KEY
          column_create Logs_20170317 timestamp COLUMN_SCALAR Time
          column_create Logs_20170317 price COLUMN_SCALAR UInt32
          column_create Logs_20170317 item COLUMN_SCALAR ShortText

          load --table Logs_20170315
          [
          {"timestamp": "2017/03/15 10:00:00", "price": 1000, "item": "A"},
          {"timestamp": "2017/03/15 11:00:00", "price":  900, "item": "A"},
          {"timestamp": "2017/03/15 12:00:00", "price":  300, "item": "B"},
          {"timestamp": "2017/03/15 13:00:00", "price":  200, "item": "B"}
          ]

          load --table Logs_20170316
          [
          {"timestamp": "2017/03/16 10:00:00", "price":  530, "item": "A"},
          {"timestamp": "2017/03/16 11:00:00", "price":  520, "item": "B"},
          {"timestamp": "2017/03/16 12:00:00", "price":  110, "item": "A"},
          {"timestamp": "2017/03/16 13:00:00", "price":  410, "item": "A"},
          {"timestamp": "2017/03/16 14:00:00", "price":  710, "item": "B"}
          ]

          load --table Logs_20170317
          [
          {"timestamp": "2017/03/17 10:00:00", "price":  800, "item": "A"},
          {"timestamp": "2017/03/17 11:00:00", "price":  400, "item": "B"},
          {"timestamp": "2017/03/17 12:00:00", "price":  500, "item": "B"},
          {"timestamp": "2017/03/17 13:00:00", "price":  300, "item": "A"}
          ]

          table_create Times TABLE_PAT_KEY Time
          column_create Times logs_20170315 COLUMN_INDEX Logs_20170315 timestamp
          column_create Times logs_20170316 COLUMN_INDEX Logs_20170316 timestamp
          column_create Times logs_20170317 COLUMN_INDEX Logs_20170317 timestamp

          logical_range_filter Logs \
            --shard_key timestamp \
            --filter 'price >= 300' \
            --limit -1 \
            --columns[offsetted_timestamp].stage filtered \
            --columns[offsetted_timestamp].type Time \
            --columns[offsetted_timestamp].flags COLUMN_SCALAR \
            --columns[offsetted_timestamp].value 'timestamp - 39600000000' \
            --columns[offsetted_day].stage filtered \
            --columns[offsetted_day].type Time \
            --columns[offsetted_day].flags COLUMN_SCALAR \
            --columns[offsetted_day].value 'time_classify_day(offsetted_timestamp)' \
            --columns[n_records_per_day_and_item].stage filtered \
            --columns[n_records_per_day_and_item].type UInt32 \
            --columns[n_records_per_day_and_item].flags COLUMN_SCALAR \
            --columns[n_records_per_day_and_item].value 'window_count()' \
            --columns[n_records_per_day_and_item].window.group_keys 'offsetted_day,item' \
            --output_columns "_id,time_format_iso8601(offsetted_day),item,n_records_per_day_and_item"
          [
            [
              0,
              0.0,
              0.0
            ],
            [
              [
                [
                  "_id",
                  "UInt32"
                ],
                [
                  "time_format_iso8601",
                  null
                ],
                [
                  "item",
                  "ShortText"
                ],
                [
                  "n_records_per_day_and_item",
                  "UInt32"
                ]
              ],
              [
                1,
                "2017-03-14T00:00:00.000000+09:00",
                "A",
                1
              ],
              [
                2,
                "2017-03-15T00:00:00.000000+09:00",
                "A",
                2
              ],
              [
                3,
                "2017-03-15T00:00:00.000000+09:00",
                "B",
                1
              ],
              [
                1,
                "2017-03-15T00:00:00.000000+09:00",
                "A",
                2
              ],
              [
                2,
                "2017-03-16T00:00:00.000000+09:00",
                "B",
                2
              ],
              [
                4,
                "2017-03-16T00:00:00.000000+09:00",
                "A",
                2
              ],
              [
                5,
                "2017-03-16T00:00:00.000000+09:00",
                "B",
                2
              ],
              [
                1,
                "2017-03-16T00:00:00.000000+09:00",
                "A",
                2
              ],
              [
                2,
                "2017-03-17T00:00:00.000000+09:00",
                "B",
                2
              ],
              [
                3,
                "2017-03-17T00:00:00.000000+09:00",
                "B",
                2
              ],
              [
                4,
                "2017-03-17T00:00:00.000000+09:00",
                "A",
                1
              ]
            ]
          ]

  - この機能には、まだリリースされていない、Apache Arrow 3.0.0が必要です。

- 参照カラムに対する検索でシーケンシャルサーチをサポートしました。

  - この機能は、インデックス検索でたくさんのレコードがマッチした場合、かつ結果セットが十分小さい場合にのみ使われます。

    - 上記のケースでは、インデックス検索よりもシーケンシャルサーチの方が速いためです。

  - この機能はデフォルトでは無効です。

  - この機能は、環境変数 `GRN_II_SELECT_TOO_MANY_INDEX_MATCH_RATIO_REFERENCE` を設定することで有効になります。

  - 環境変数 `GRN_II_SELECT_TOO_MANY_INDEX_MATCH_RATIO_REFERENCE` はインデックス検索からシーケンシャルサーチに切り替えるためのしきい値です。

    - 例えば、以下のように `GRN_II_SELECT_TOO_MANY_INDEX_MATCH_RATIO_REFERENCE=0.7` とセットした場合、結果セットのレコード数が、総レコード数の70%以下の場合にシーケンシャルサーチで検索します。

          $ export GRN_II_SELECT_TOO_MANY_INDEX_MATCH_RATIO_REFERENCE=0.7

          table_create Tags TABLE_HASH_KEY ShortText
          table_create Memos TABLE_HASH_KEY ShortText
          column_create Memos tag COLUMN_SCALAR Tags

          load --table Memos
          [
          {"_key": "Rroonga is fast!", "tag": "Rroonga"},
          {"_key": "Groonga is fast!", "tag": "Groonga"},
          {"_key": "Mroonga is fast!", "tag": "Mroonga"},
          {"_key": "Groonga sticker!", "tag": "Groonga"},
          {"_key": "Groonga is good!", "tag": "Groonga"}
          ]

          column_create Tags memos_tag COLUMN_INDEX Memos tag

          select Memos --query '_id:>=3 tag:@Groonga' --output_columns _id,_score,_key,tag
          [
            [
              0,
              0.0,
              0.0
            ],
            [
              [
                [
                  2
                ],
                [
                  [
                    "_id",
                    "UInt32"
                  ],
                  [
                    "_score",
                    "Int32"
                  ],
                  [
                    "_key",
                    "ShortText"
                  ],
                  [
                    "tag",
                    "Tags"
                  ]
                ],
                [
                  4,
                  2,
                  "Groonga sticker!",
                  "Groonga"
                ],
                [
                  5,
                  2,
                  "Groonga is good!",
                  "Groonga"
                ]
              ]
            ]
          ]

- [tokenizers] `TokenDocumentVectorTFIDF` と `TokenDocumentVectorBM25` でトークンカラムをサポートしました。

  - インデックスカラムと同じソースを持つトークンカラムがある場合、これらのトークナイザーは、トークンカラムのトークンIDを使います。

    - トークンカラムは、既にトークナイズ済みのデータを持っています。

    - そのため、トークンカラムを使うことによって、これらのトークナイザーのパフォーマンスが改善されます。

  - 例えば、以下のように、 `content_tokens` というトークンカラムを作ることで、この機能を使えます。

        table_create Memos TABLE_NO_KEY
        column_create Memos content COLUMN_SCALAR Text

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

        table_create Tokens TABLE_PAT_KEY ShortText \
          --normalizer NormalizerNFKC121 \
          --default_tokenizer TokenNgram
        column_create Tokens memos_content COLUMN_INDEX|WITH_POSITION Memos content

        column_create Memos content_tokens COLUMN_VECTOR Tokens content

        table_create DocumentVectorBM25 TABLE_HASH_KEY Tokens \
          --default_tokenizer \
            'TokenDocumentVectorBM25("index_column", "memos_content", \
                                     "df_column", "df")'
        column_create DocumentVectorBM25 df COLUMN_SCALAR UInt32

        column_create Memos content_feature COLUMN_VECTOR|WITH_WEIGHT|WEIGHT_FLOAT32 \
          DocumentVectorBM25 content

        select Memos
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                5
              ],
              [
                [
                  "_id",
                  "UInt32"
                ],
                [
                  "content",
                  "Text"
                ],
                [
                  "content_feature",
                  "DocumentVectorBM25"
                ],
                [
                  "content_tokens",
                  "Tokens"
                ]
              ],
              [
                1,
                "a b c a",
                {
                  "a": 0.5095787,
                  "b": 0.6084117,
                  "c": 0.6084117
                },
                [
                  "a",
                  "b",
                  "c",
                  "a"
                ]
              ],
              [
                2,
                "c b c",
                {
                  "c": 0.8342565,
                  "b": 0.5513765
                },
                [
                  "c",
                  "b",
                  "c"
                ]
              ],
              [
                3,
                "b b a",
                {
                  "b": 0.9430448,
                  "a": 0.3326656
                },
                [
                  "b",
                  "b",
                  "a"
                ]
              ],
              [
                4,
                "a c c",
                {
                  "a": 0.3326656,
                  "c": 0.9430448
                },
                [
                  "a",
                  "c",
                  "c"
                ]
              ],
              [
                5,
                "a",
                {
                  "a": 1.0
                },
                [
                  "a"
                ]
              ]
            ]
          ]
        ]

  - `TokenDocumentVectorTFIDF` と `TokenDocumentVectorBM25` は、各トークンに対して重みをつけます。

    - `TokenDocumentVectorTFIDF` は、TF-IDFを使ってトークンの重みを計算します。

    - TF-IDFについては、 https://radimrehurek.com/gensim/models/tfidfmodel.html を参照してください。

    - `TokenDocumentVectorBM25` は、Okapi BM25を使ってトークンの重みを計算します。

    - Okapi BM25については、 https://en.wikipedia.org/wiki/Okapi_BM25 を参照してください。

- 以下のケースのパフォーマンスを改善しました。

  - `(column @ "value") && (column @ "value")`

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

- [Debian GNU/Linux] stretchのサポートをやめました。

  - EOLになったためです。

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

  - EOLになったためです。

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

### 修正

- 以下のように、複数のドリルダウンのキーと複数のアクセサーを使用した時にGroongaがクラッシュする問題を修正しました。[GitHub#1153][naoaさんがパッチ提供]

      table_create Tags TABLE_PAT_KEY ShortText

      table_create Memos TABLE_HASH_KEY ShortText
      column_create Memos tags COLUMN_VECTOR Tags
      column_create Memos year COLUMN_SCALAR Int32

      load --table Memos
      [
      {"_key": "Groonga is fast!", "tags": ["full-text-search"], "year": 2019},
      {"_key": "Mroonga is fast!", "tags": ["mysql", "full-text-search"], "year": 2019},
      {"_key": "Groonga sticker!", "tags": ["full-text-search", "sticker"], "year": 2020},
      {"_key": "Rroonga is fast!", "tags": ["full-text-search", "ruby"], "year": 2020},
      {"_key": "Groonga is good!", "tags": ["full-text-search"], "year": 2020}
      ]

      select Memos \
        --filter '_id > 0' \
        --drilldowns[tags].keys 'tags,year >= 2020' \
        --drilldowns[tags].output_columns _key[0],_key[1],_nsubrecs

      select Memos \
        --filter '_id > 0' \
        --drilldowns[tags].keys 'tags,year >= 2020' \
        --drilldowns[tags].output_columns _key[1],_nsubrecs

- 以下のように、同じフレーズが複数回出現すると、近傍フレーズ検索がマッチしない問題を修正しました。

      table_create Entries TABLE_NO_KEY
      column_create Entries content COLUMN_SCALAR Text

      table_create Terms TABLE_PAT_KEY ShortText \
        --default_tokenizer TokenNgram \
        --normalizer NormalizerNFKC121
      column_create Terms entries_content COLUMN_INDEX|WITH_POSITION Entries content

      load --table Entries
      [
      {"content": "a x a x b x x"},
      {"content": "a x x b x"}
      ]

      select Entries \
        --match_columns content \
        --query '*NP2"a b"' \
        --output_columns '_score, content'

### 感謝

- Hung Nguyen Vさん

- naoaさん

- timgates42さん [GitHub#1155にてパッチ提供]

## 10.0.9リリース - 2020-12-01

### 改良

- `limit` に `-1` を指定した時のパフォーマンスを改善しました。

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

  - Groongaは、リクエストが `--auto_release_count` で指定された値に到達した時に自動的に参照カウントを減らします。

  - 例えば、以下のように、取得した `User` の参照は、2番目の `status` が処理された後に自動的に解放されます。

        reference_acquire --target_name Users --auto_release_count 2
        status # Users is still referred.
        status # Users' reference is released after this command is processed.

  - このオプションで、取得した参照の解放漏れを防げます。

- Groongaが空の `vector` や `uvector` を評価した時の動作を変更しました。

  - 空の `vector` と `uvector` はcommand version 3では、 `false` と評価されます。

    - この挙動はcommand version 3でのみ有効です。

    - 今までとは挙動が異なることに注意してください。

- [ノーマライザー] Unicode 13.0 の NFKC（Normalization Form Compatibility Composition）をベースにしたノーマライザー `NormalizerNFKC130` を追加しました。

- [トークンフィルター] Unicode 13.0 の NFKC（Normalization Form Compatibility Composition）をベースにしたトークンフィルター `TokenFilterNFKC130` を追加しました。

- [select] `"_score = column - X"` のパフォーマンスを改善しました。

- [reference_acquire] `--recursive dependent` オプションを指定した時に必要のないインデックスカラムへの参照を取得しないように改善しました。

  - 今回のリリースから、 `--recursive dependent` の対象は、対象のテーブルのキーあるいはデータカラムに設定してあるインデックスカラムです。

- [select] 順序限定の近傍フレーズ検索をサポートしました。

  - 今までの近傍フレーズ検索は、指定したフレーズ間の距離が近いレコードのみを探していました。

  - この機能は、以下の条件を満たすレコードを探します。

    - 指定したフレーズ間の距離が近い場合。

    - 指定したフレーズが指定した順序で並んでいる場合。

  - この機能は、 `*ONP` を演算子として使います。(`*NP` 演算子ではないことに注意してください。)

  - `$` はクエリー構文では、 `$` そのものとして扱います。クエリー構文では、 `$` は特殊文字ではないことに注意してください。

  - スクリプト構文の場合、この機能は以下のように使用します。

        table_create Entries TABLE_NO_KEY
        column_create Entries content COLUMN_SCALAR Text

        table_create Terms TABLE_PAT_KEY ShortText \
          --default_tokenizer 'TokenNgram("unify_alphabet", false, \
                                          "unify_digit", false)' \
          --normalizer NormalizerNFKC121
        column_create Terms entries_content COLUMN_INDEX|WITH_POSITION Entries content

        load --table Entries
        [
        {"content": "abcXYZdef"},
        {"content": "abebcdXYZdef"},
        {"content": "abcdef"},
        {"content": "defXYZabc"},
        {"content": "XYZabc"},
        {"content": "abc123456789def"},
        {"content": "abc12345678def"},
        {"content": "abc1de2def"}
        ]

        select Entries --filter 'content *ONP "abc def"' --output_columns '_score, content'
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                4
              ],
              [
                [
                  "_score",
                  "Int32"
                ],
                [
                  "content",
                  "Text"
                ]
              ],
              [
                1,
                "abcXYZdef"
              ],
              [
                1,
                "abcdef"
              ],
              [
                1,
                "abc12345678def"
              ],
              [
                1,
                "abc1de2def"
              ]
            ]
          ]
        ]

  - クエリー構文の場合、この機能は以下のように使用します。

        select Entries --query 'content:*ONP "abc def"' --output_columns '_score, content'
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                4
              ],
              [
                [
                  "_score",
                  "Int32"
                ],
                [
                  "content",
                  "Text"
                ]
              ],
              [
                1,
                "abcXYZdef"
              ],
              [
                1,
                "abcdef"
              ],
              [
                1,
                "abc12345678def"
              ],
              [
                1,
                "abc1de2def"
              ]
            ]
          ]
        ]

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

### 修正

- [Groonga HTTPサーバー] Groonga HTTP server が全てのワーカースレッドの完全な終了を待たずに終了していた問題を修正しました。

  - 今まで、Groonga HTTP server は、ワーカースレッドの処理が終了した後から、自身の終了処理を開始していました。しかし、このタイミングでは、ワーカースレッドは完全に終了していないことがあります。そのため、タイミングによってはGroonga HTTP serverがクラッシュすることがあります。Groonga HTTP server がワーカースレッドがまだ使用している領域を解放することがあるためです。

## 10.0.8リリース - 2020-10-29

### 改良

- [select] 大きいサイズのドリルダウンのキーを使えるようになりました。

  - Groongaのテーブルのキーサイズの最大は4KiBですが、複数のドリルダウンのキーを指定している場合、ドリルダウンのキーのサイズが4KiBを超える場合があります。

    - 例えば、以下のケースで、 `tag` キーと `n_like` キーのトータルサイズが4KiB以上だった場合、ドリルダウンは失敗します。

        select Entries \
          --limit -1 \
          --output_columns tag,n_likes \
          --drilldowns[tag.n_likes].keys tag,n_likes \
          --drilldowns[tag.n_likes].output_columns _value.tag,_value.n_likes,_nsubrecs

    - ドリルダウンは指定されている全てのキーを連結しているためです。そのため、ドリルダウンのキーそれぞれが大きい場合は、ドリルダウンのキーを連結したサイズが4KiB以上になります。

  - この機能には、 xxHash が必要です。

    - ただ、Groongaをパッケージからインストールしている場合は、特に何もしなくてもこの機能を使えます。Groongaのパッケージには、すでに xxHash が含まれているためです。

- [select] 異なるテーブルを参照しているカラムを同じ動的カラムで扱えるようにしました。

  - 従来、異なるテーブルを参照しているカラムは、同一の動的カラムでは扱えませんでした。カラムの型が異なるためです。

  - 今回のバージョンから、以下のように異なるテーブルを参照しているカラムであってもビルトインの型にキャストすることで同じ動的カラムで扱うことができます。

        table_create Store_A TABLE_HASH_KEY ShortText
        table_create Store_B TABLE_HASH_KEY ShortText

        table_create Customers TABLE_HASH_KEY Int32
        column_create Customers customers_A COLUMN_VECTOR Store_A
        column_create Customers customers_B COLUMN_VECTOR Store_B

        load --table Customers
        [
          {"_key": 1604020694, "customers_A": ["A", "B", "C"]},
          {"_key": 1602724694, "customers_B": ["Z", "V", "Y", "T"]},
        ]

        select Customers \
          --filter '_key == 1604020694' \
          --columns[customers].stage output \
          --columns[customers].flags COLUMN_VECTOR \
          --columns[customers].type ShortText \
          --columns[customers].value 'customers_A' \
          --output_columns '_key, customers'

  - 今までは、 `Store_A` または `Store_B` を `customers` カラムの`type`に設定する必要がありました。

  - 上記の例では、 `customers_A` カラムの型は、 `ShortText` にキャストします。

  - `customers_A` のキーも `customers_B` のキーも `ShortText` 型であるため、これで `customers` カラムの値に `customers_B` の値も設定できます。

- [select] 検索結果のレコード数が非常に多い場合のパフォーマンスを改善しました。

  - この最適化は、以下のケースで効果があります。

    - `--filter 'column <= "value"'` or `--filter 'column >= "value"'`

    - `--filter 'column == "value"'`

    - `--filter 'between(...)'` または `--filter 'between(_key, ...)'`

    - `--filter 'sub_filter(reference_column, ...)'`

    - `--filter '_key > "value"'` のような `_key` に対する比較

    - `--filter 'geo_in_circle(...)'`

- バンドルしているLZ4を1.8.2から1.9.2に更新しました。

- xxHash 0.8 をサポートしました。

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

### 修正

- ブラウザーベースの管理ツール関連の問題を修正しました。　[GitHub#1139][sutaminさんの報告]

  - Groongaのロゴが表示されない問題。

  - 日本語のインデックスページにスループットグラフが表示されない問題。

- [between] `between(_key, ...)` が常にシーケンシャルサーチで評価される問題を修正しました。

### 感謝

- sutaminさん

## 10.0.7リリース - 2020-09-29

### 改良

- [highlight], [highlight_full] ノーマライザーにオプションを指定できるようになりました。

- [リターンコード] 新しいリターンコード `GRN_CONNECTION_RESET` を追加しました。

  - このリターンコードは、リモートホストから強制的に接続を切断されたときに返されます。

- Ubuntu 19.10(Eoan Ermine)のサポートをやめました。

  - このバージョンはEOLになっているためです。

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

- [grndb] キーの重複を検出できるようになりました。

  - 今回のリリースから、`grndb check` でキーの重複も検出できるようになりました。

  - このチェックは、 `TABLE_NO_KEY` のテーブル以外で有効です。

  - `grndb check` で重複が検出されたテーブルにインデックスカラムしかない場合は、 `grndb recover` で復旧できます。

- [table_create], [column_create] 新しいオプション `--path` を追加しました。

  - このオプションによって指定したテーブルまたは、カラムを任意のパスに格納できます。

  - このオプションは、高速なストレージ(SSDなど)によく使うテーブルやカラムを格納し、低速なストレージ(HDDなど)にあまり使わないテーブルやカラムを格納したいときに有用です。

  - このオプションは、相対パス、絶対パスの両方が指定できます。

    - 相対パスを指定した場合は、 `groonga` プロセスのパスを起点に指定したパスが解決されます。

  - `--path` を指定した場合、 `dump` コマンドの結果に `--path` の情報が含まれます。

    - したがって、 `--path` を指定した場合、 異なる環境のホストではリストアできなくなります。

      - これは、ディレクトリ構成や `groonga` プロセスの場所が環境ごとに異なるためです。

    - `--path` の情報を `dump` に含みたくない場合は、 `dump` コマンド実行時に `--dump_paths no` を指定する必要があります。

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

  - `--dump_paths` オプションは、 `--path` をダンプするかどうかを制御します。

  - デフォルト値は `yes` です。

  - もし、テーブルやカラム作成時に `--path` を指定していて、 `--path` の情報を `dump` に含みたくない場合は、 `dump` コマンド実行時に `--dump_paths` に `no` を指定してください。

- 新しい関数 `string_toknize()` を追加しました。

  - この関数は、第二引数に指定されたカラムの値を、第一引数に指定されたトークナイザーでトークナイズします。

- [tokenizers] 新しいトークナイザー `TokenDocumentVectorTFIDF` を追加しました。(実験的)

  - このトークナイザーは、TF-IDFで文書ベクトルを自動で生成します。

- [tokenizers] 新しいトークナイザー `TokenDocumentVectorBM25` を追加しました。(実験的)

  - このトークナイザーは、BM25で文書ベクトルを自動で生成します。

- [select] 同一センテンス内での、フレーズ近傍検索をサポートしました。

### 修正

- [load] 257個のカラムに対して `load` を実行すると `load` の応答が返らなくなる問題を修正しました。

  - この問題は、10.0.4以降で発生する可能性があります。

  - この問題は、 `[a, b, c, ...]` の形式でデータをロードした時にのみ発生します。

    - `[{...}]` を使ってデータをロードした場合は発生しません。

- [MessagePack] float32の値を正しくアンパックできない問題を修正しました。

- マルチカラムインデックス関連の問題を修正しました。

  - `_score` の値が壊れることがあります。

  - ヒットしないはずのレコードがヒットすることがあります。

  - この問題の発生条件については、以下のURLを参照してください。

    - https://groonga.org/ja/blog/2020/09/29/groonga-10.0.7.html#multi-column-index

## 10.0.6リリース - 2020-08-29

### 改良

- [logical_range_filter] 大きなデータの検索プランを改善しました。

  - 通常、 `logical_range_filter` は `logical_select` より高速ですが、以下のケースでは、 `logical_select` より遅くなっていました。

    - `logical_range_filter` には要求されたレコード数をなかなか見つけられない場合にシーケンシャル検索からインデックス検索に切り替える機能があります。( `logical_range_filter` は通常、検索対象のレコード数が多い場合は、シーケンシャル検索を使います。)

    - 上記の切り替えが発生した場合は、 `logical_select` と検索処理がほぼ同じになります。そのため、大きなデータを対象とした検索では、上記のケースで、 `logical_range_filter` は、 `logical_select` の数倍遅くなります。なぜなら、 `logical_range_filter` は検索後にソートを実行するためです。

  - 今回のリリースから、大きなデータを検索する場合に、今までよりシーケンシャル検索が採用されやすくしました。

  - これによって、 `logical_select` と同等の処理になるケースが減少し `logical_range_filter` のパフォーマンスが改善します。

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

- Debian GNU/Linux へのインストール方法を変更しました。

  - `groonga-archive-keyring` の代わりに `groonga-apt-source` を使うように変更しました。 `lintian` コマンドが `/etc/apt/sources.lists.d/` 配下にファイルを置くパッケージは `apt-source` を使うよう推奨しているためです。

    - `lintian` コマンドはパッケージングに共通のエラーをチェックするためのコマンドです。

    - インストール方法についての詳細は、以下のURLも参照してください。

      - https://groonga.org/ja/docs/install/debian.html

- [logical_select] `highlight_html` と `highlight_full` をサポートしました。

- 値を持たない配列を削除した時、そのレコードのIDを再利用するようにしました。[GitHub#mroonga/mroonga#327][gaeeyoさんの報告]

  - 値を持たない配列を削除した場合、削除されたIDは再利用されません。

  - Groongaは大きなIDがあることによって、多くのストレージを使用します。大きなIDはそれだけで、多くのストレージを使うためです。

    - 大きなIDは、例えば、Mroongaの `mroonga_operations` のように多くの追加と削除によって発生します。

- [select] インデックスを設定していない全文検索のパフォーマンスを改善しました。

- [関数] 全ての引数が他のテーブルへの参照か、リテラルである関数のパフォーマンスを改善しました。

- [インデックス構築] トークンカラムを使った静的インデックス構築のパフォーマンスを改善しました。 [GitHub#1126][naoaさんがパッチ提供]

- `"_score = func(...)"` のパフォーマンスを改善しました。

  - `_score` の値が `"_score = func(...)"` のように関数によってのみ算出される場合のパフォーマンスを改善しました。

### 修正

- 応答送信のエラーが発生した後の応答にゴミが含まれることがある問題を修正しました。

  - これは、クライアントが全ての応答を読み込まずにコネクションがクローズされた場合に発生することがあります。

### 感謝

- gaeeyoさん

- naoaさん

## 10.0.5リリース - 2020-07-30

### 改良

- [select] `-load_table` で指定したテーブルに参照を格納できるようにしました。

  - `--load-table` は予め用意したテーブルに検索結果を格納する機能です。

    - 複数回検索が実行される場合、このテーブルに結果を格納することで、検索結果をキャッシュできます。

    - このテーブルを使うことで、初回以降の検索時間を短縮できます。

  - 今回のリリース以降で、以下のようにこのテーブルに別のテーブルへの参照を格納できます。

    - カラムの値を格納せず、参照のみを格納するため、このテーブルのサイズを小さくすることができます。

    - このテーブルに対して検索する場合、参照先のテーブルのインデックスを使って検索できます。

        table_create Logs TABLE_HASH_KEY ShortText
        column_create Logs timestamp COLUMN_SCALAR Time

        table_create Times TABLE_PAT_KEY Time
        column_create Times logs_timestamp COLUMN_INDEX Logs timestamp

        table_create LoadedLogs TABLE_HASH_KEY Logs

        load --table Logs
        [
        {
          "_key": "2015-02-03:1",
          "timestamp": "2015-02-03 10:49:00"
        },
        {
          "_key": "2015-02-03:2",
          "timestamp": "2015-02-03 12:49:00"
        },
        {
          "_key": "2015-02-04:1",
          "timestamp": "2015-02-04 00:00:00"
        }
        ]

        select \
          Logs \
          --load_table LoadedLogs \
          --load_columns "_key" \
          --load_values "_key" \
          --limit 0

        select \
          --table LoadedLogs \
          --filter 'timestamp >= "2015-02-03 12:49:00"'
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                2
              ],
              [
                [
                  "_id",
                  "UInt32"
                ],
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "timestamp",
                  "Time"
                ]
              ],
              [
                2,
                "2015-02-03:2",
                1422935340.0
              ],
              [
                3,
                "2015-02-04:1",
                1422975600.0
              ]
            ]
          ]
        ]

- [select] 以下のケースのソートのパフォーマンスを改善しました。

  - 多くのソートキーがID解決をする場合。

    - 例えば、以下の式はIDを解決する必要があります。

      - `--filter true --sort_keys column`

    - 例えば、以下の式はIDを解決する必要がありません。 擬似カラム `_score` は、結果テーブルに存在しており、ソーステーブルには存在しないためIDを解決する必要がありません。

      - `--filter true --sort_keys _score`

  - ソート対象のテーブルがキーを持っている場合。

    - したがって、 `TABLE_NO_KEY` はこの改善をサポートしていません。

- [select] 以下のケースのパフォーマンスを少し改善しました。

  - 沢山のレコードがマッチする検索をしているケース。

  - 沢山のレコードに対してドリルダウンするケース。

- [aggregator] score アクセサーをサポートしました。[GitHub#1120][naoaさんのパッチ提供]

  - 例えば、 以下のように `_score` を `aggregator_*` の対象にできます。

        table_create Items TABLE_HASH_KEY ShortText
        column_create Items price COLUMN_SCALAR UInt32
        column_create Items tag COLUMN_SCALAR ShortText

        load --table Items
        [
        {"_key": "Book",  "price": 1000, "tag": "A"},
        {"_key": "Note",  "price": 1000, "tag": "B"},
        {"_key": "Box",   "price": 500,  "tag": "B"},
        {"_key": "Pen",   "price": 500,  "tag": "A"},
        {"_key": "Food",  "price": 500,  "tag": "C"},
        {"_key": "Drink", "price": 300,  "tag": "B"}
        ]

        select Items \
          --filter true \
          --drilldowns[tag].keys tag \
          --drilldowns[tag].output_columns _key,_nsubrecs,score_mean \
          --drilldowns[tag].columns[score_mean].stage group \
          --drilldowns[tag].columns[score_mean].type Float \
          --drilldowns[tag].columns[score_mean].flags COLUMN_SCALAR \
          --drilldowns[tag].columns[score_mean].value 'aggregator_mean(_score)'
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                6
              ],
              [
                [
                  "_id",
                  "UInt32"
                ],
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "price",
                  "UInt32"
                ],
                [
                  "tag",
                  "ShortText"
                ]
              ],
              [
                1,
                "Book",
                1000,
                "A"
              ],
              [
                2,
                "Note",
                1000,
                "B"
              ],
              [
                3,
                "Box",
                500,
                "B"
              ],
              [
                4,
                "Pen",
                500,
                "A"
              ],
              [
                5,
                "Food",
                500,
                "C"
              ],
              [
                6,
                "Drink",
                300,
                "B"
              ]
            ],
            {
              "tag": [
                [
                  3
                ],
                [
                  [
                    "_key",
                    "ShortText"
                  ],
                  [
                    "_nsubrecs",
                    "Int32"
                  ],
                  [
                    "score_mean",
                    "Float"
                  ]
                ],
                [
                  "A",
                  2,
                  1.0
                ],
                [
                  "B",
                  3,
                  1.0
                ],
                [
                  "C",
                  1,
                  1.0
                ]
              ]
            }
          ]
        ]

- [インデックス構築] VC++版の静的インデックス構築のパフォーマンスを改善しました。

- [select] JSON形式で出力する際に `NaN` や `Infinity` 、 `-Infinity` の代わりに `null` を出力するようにしました。

  - これらの値はJSONではサポートされていないためです。

- [select] 標準偏差の集計をサポートしました。

  - 例えば、以下のようにグループごとの標準偏差を計算できます。

        table_create Items TABLE_HASH_KEY ShortText
        column_create Items price COLUMN_SCALAR UInt32
        column_create Items tag COLUMN_SCALAR ShortText

        load --table Items
        [
        {"_key": "Book",  "price": 1000, "tag": "A"},
        {"_key": "Note",  "price": 1000, "tag": "B"},
        {"_key": "Box",   "price": 500,  "tag": "B"},
        {"_key": "Pen",   "price": 500,  "tag": "A"},
        {"_key": "Food",  "price": 500,  "tag": "C"},
        {"_key": "Drink", "price": 300,  "tag": "B"}
        ]

        select Items \
          --drilldowns[tag].keys tag \
          --drilldowns[tag].output_columns _key,_nsubrecs,price_sd \
          --drilldowns[tag].columns[price_sd].stage group \
          --drilldowns[tag].columns[price_sd].type Float \
          --drilldowns[tag].columns[price_sd].flags COLUMN_SCALAR \
          --drilldowns[tag].columns[price_sd].value 'aggregator_sd(price)' \
          --output_pretty yes
        [
          [
            0,
            1594339851.924836,
            0.002813816070556641
          ],
          [
            [
              [
                6
              ],
              [
                [
                  "_id",
                  "UInt32"
                ],
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "price",
                  "UInt32"
                ],
                [
                  "tag",
                  "ShortText"
                ]
              ],
              [
                1,
                "Book",
                1000,
                "A"
              ],
              [
                2,
                "Note",
                1000,
                "B"
              ],
              [
                3,
                "Box",
                500,
                "B"
              ],
              [
                4,
                "Pen",
                500,
                "A"
              ],
              [
                5,
                "Food",
                500,
                "C"
              ],
              [
                6,
                "Drink",
                300,
                "B"
              ]
            ],
            {
              "tag": [
                [
                  3
                ],
                [
                  [
                    "_key",
                    "ShortText"
                  ],
                  [
                    "_nsubrecs",
                    "Int32"
                  ],
                  [
                    "price_sd",
                    "Float"
                  ]
                ],
                [
                  "A",
                  2,
                  250.0
                ],
                [
                  "B",
                  3,
                  294.3920288775949
                ],
                [
                  "C",
                  1,
                  0.0
                ]
              ]
            }
          ]
        ]

    - `aggregate_sd(target, {"unbiased": true})` と指定することで、不偏標準偏差も計算できます。

- [Windows] Visual Studio 2013のサポートをやめました。

### 修正

- [Groonga HTTPサーバー] 応答がエラーで中断された時に、 `shutdown?immediate` を実行しても、リクエストが中断しない問題を修正しました。

- リクエスト中にエラーが発生した時にクラッシュする問題を修正しました。

  - これは、Apache Arrow形式を使っている時にのみ発生します。

  - 前のリクエストがエラーによって中断された後に再度Groongaへリクエストを送信した時にGroongaがクラッシュします。

- [between] 一時テーブルを使用した時にクラッシュする問題を修正しました。

  - 例えば、 `between` の第一引数に動的カラムを指定すると、Groongaがクラッシュしていました。

- プラグインで作成したプロシージャーが予期せず解放される問題を修正しました。

  - 参照カウントモードでのみ発生します。

  - `plugin_register` を使っていない場合は、発生しません。

  - `plugin_register` を実行したプロセスでは発生しません。

  - `plugin_register` を実行していないプロセスで発生します。

- `token_column` を使った静的インデックス構築中に正規化エラーが発生する問題を修正しました。[GitHub#1122][naoaさんの報告]

### 感謝

- naoaさん

## 10.0.4リリース - 2020-06-29

### 改良

- [テーブル] ハッシュテーブルで4億件のレコードの登録をサポートしました。

- [select] `_score` が再帰的に値を取得しない時のパフォーマンスを改善しました。

  - Groongaは、検索結果が検索対象の時に、 `_score` の値を再帰的に取得します。

  - 例えば、 `slices` は検索結果が検索対象です。したがって、 `slices` を使っているクエリーでは、この改善は効果がありません。

- [ログ] ドリルダウンのキーをクエリーログに出力するようにしました。

- [reference_acquire], [reference_release] 参照カウントモード用に新しいコマンドを追加しました。

  - 短い間隔で複数の `load` を呼び出す必要がある場合、参照カウントモードによる自動クローズによってパフォーマンスが低下します。

  - 複数の `load` の前に `/reference_acquire` を呼び、 複数の `load` の後に `/reference_release` を呼ぶことで、このパフォーマンスの低下を避けることができます。`/reference_acquire` と `/reference_release` の間は自動クローズは無効になります。

    - `/reference_acquire` が、対象のオブジェクトの参照を取得するためです。

  - パフォーマンスに影響のある操作が完了したら、 `/reference_release` を呼ぶ必要があります。

  - `/reference_release` を呼ばない場合、参照カウントモードは機能しません。

- [select] 一度の `drilldown` で複数グループの集計をサポートしました。

  - 以下のように、一回の `drilldown` で異なるグループ毎に和と算術平均を計算できるようになりました。

        table_create Items TABLE_HASH_KEY ShortText
        column_create Items price COLUMN_SCALAR UInt32
        column_create Items quantity COLUMN_SCALAR UInt32
        column_create Items tag COLUMN_SCALAR ShortText

        load --table Items
        [
        {"_key": "Book",  "price": 1000, "quantity": 100, "tag": "A"},
        {"_key": "Note",  "price": 1000, "quantity": 10,  "tag": "B"},
        {"_key": "Box",   "price": 500,  "quantity": 15,  "tag": "B"},
        {"_key": "Pen",   "price": 500,  "quantity": 12,  "tag": "A"},
        {"_key": "Food",  "price": 500,  "quantity": 111, "tag": "C"},
        {"_key": "Drink", "price": 300,  "quantity": 22,  "tag": "B"}
        ]

        select Items \
          --drilldowns[tag].keys tag \
          --drilldowns[tag].output_columns _key,_nsubrecs,price_sum,quantity_sum \
          --drilldowns[tag].columns[price_sum].stage group \
          --drilldowns[tag].columns[price_sum].type UInt32 \
          --drilldowns[tag].columns[price_sum].flags COLUMN_SCALAR \
          --drilldowns[tag].columns[price_sum].value 'aggregator_sum(price)' \
          --drilldowns[tag].columns[quantity_sum].stage group \
          --drilldowns[tag].columns[quantity_sum].type UInt32 \
          --drilldowns[tag].columns[quantity_sum].flags COLUMN_SCALAR \
          --drilldowns[tag].columns[quantity_sum].value 'aggregator_sum(quantity)'
        [
          [
            0,
            0.0,
            0.0
          ],
          [
            [
              [
                6
              ],
              [
                [
                  "_id",
                  "UInt32"
                ],
                [
                  "_key",
                  "ShortText"
                ],
                [
                  "price",
                  "UInt32"
                ],
                [
                  "quantity",
                  "UInt32"
                ],
                [
                  "tag",
                  "ShortText"
                ]
              ],
              [
                1,
                "Book",
                1000,
                100,
                "A"
              ],
              [
                2,
                "Note",
                1000,
                10,
                "B"
              ],
              [
                3,
                "Box",
                500,
                15,
                "B"
              ],
              [
                4,
                "Pen",
                500,
                12,
                "A"
              ],
              [
                5,
                "Food",
                500,
                111,
                "C"
              ],
              [
                6,
                "Drink",
                300,
                22,
                "B"
              ]
            ],
            {
              "tag": [
                [
                  3
                ],
                [
                  [
                    "_key",
                    "ShortText"
                  ],
                  [
                    "_nsubrecs",
                    "Int32"
                  ],
                  [
                    "price_sum",
                    "UInt32"
                  ],
                  [
                    "quantity_sum",
                    "UInt32"
                  ]
                ],
                [
                  "A",
                  2,
                  1500,
                  112
                ],
                [
                  "B",
                  3,
                  1800,
                  47
                ],
                [
                  "C",
                  1,
                  500,
                  111
                ]
              ]
            }
          ]
        ]

- [groonga 実行ファイル] スタンドアローンモードで、 `--pid-path` をサポートしました。

  - 以前のバージョンのスタンドアローンモードでは、 `--pid-path` は無視されていました。

- [io_flush] 参照カウントモードに対応しました。

- [logical_range_filter],[logical_count] 参照カウントモードに対応しました。

- [Groonga HTTPサーバー] 最後のチャンクの後にヘッダーをつけないようにしました。

  - 最後のチャンクの後のヘッダーを無視するHTTPクライアントが存在する可能性があるためです。

- [vector_slice] `Float32` 型のベクターをサポートしました。 [GitHub#1106 naoaさんがパッチ提供]

- トークンカラムを使った、並列静的インデックス構築をサポートしました。

  - 予めトークナイズされたデータから複数スレッドで静的インデックスの構築ができるようになりました。

  - 以下の環境変数で、並列静的インデックス構築のパラメータを調整できます。

    - `GRN_TOKEN_COLUMN_PARALLEL_CHUNK_SIZE` : スレッド毎にどのくらいのレコードを処理するかを指定します。

      - デフォルト値は `1024` レコードです。

    - `GRN_TOKEN_COLUMN_PARALLEL_TABLE_SIZE_THRESHOLD` : どのくらいのソースレコードで並列化するかを指定します。

      - デフォルト値は `102400` レコードです。

- [select] 参照カウントモード時の `load_table` のパフォーマンスを改善しました。

### 修正

- シャードをまたいでいて、かつ `--filter` を指定していない動的カラムを使って検索すると、Gronngaのデータベースが破損する問題を修正しました。

- `schema` コマンドの結果に `Float32` 型が表示されなかった問題を修正しました。

- 参照 `uvector` が要素を持っていないとき、 `_nsubrecs` を余分にカウントする問題を修正しました。

### 感謝

- naoaさん

## 10.0.3リリース - 2020-05-29

### 改良

- 予めトークナイズされたデータから転置インデックスを構築できるようになりました。

  - これにより、インデックスの構築が高速化します。

  - この改善を使うには、トークンカラムを準備する必要があります。

  - トークンカラムは、インデックスカラムのように自動で値が生成されます。

  - トークンカラムの値はソースカラムの値をトークナイズすることで生成されます。

  - トークンカラムは以下のようにソースカラムを設定することで作成できます。

        table_create Terms TABLE_PAT_KEY ShortText \
          --normalizer NormalizerNFKC121 \
          --default_tokenizer TokenNgram

        table_create Notes TABLE_NO_KEY
        column_create Notes title COLUMN_SCALAR Text

        # The last "title" is the source column.
        column_create Notes title_terms COLUMN_VECTOR Terms title

- [select] 関数の引数に `vector` を指定できるようになりました。

  - 例えば、 `query` の `flags` オプションを `vector` を使って以下のように記述できます。

        select \
          --table Memos \
          --filter 'query("content", "-content:@mroonga", \
                          { \
                            "expander": "QueryExpanderTSV", \
                            "flags": ["ALLOW_LEADING_NOT", "ALLOW_COLUMN"] \
                          })'

- [select] 動的カラムに新しいステージ `result_set` を追加しました。

  - このステージは、結果セットのテーブルにカラムを作ります。したがって、 `query` か `filter` が存在しない場合は作られません。

    - `query` や `filter` が存在しない場合は、結果セットのテーブルが作られないためです。

  - このステージでは `_value` は使用できません。 `result_set` ステージの値は `score_column` に格納されます。

- [vector_slice] 重み付きベクターの重みに `Float32` 型が使えるようになりました。 [GitHub#1106 naoaさんがパッチ提供]

- [select] drilldownsの動的カラムのステージに `filtered` と `output` を追加しました。 [GitHub#1101 naoaさんがパッチ提供][GitHub#1100 naoaさんがパッチ提供]

  - `drilldowns[Label].stage filtered` や `drilldowns[Label].stage output` のように drilldowns の動的カラムのステージに `filtered` と `output` を使えます。

- [select] ドリルダウンでの集計に `Float` 型の値をサポートしました。

  - `MAX`、`MIN`、`SUM` を使って `Float` 型の値の最大値、最小値、合計値を集計できます。

- [query] [geo_in_rectangle] [geo_in_circle] `query()` と `geo_in_rectangle()` と `geo_in_circle()` に新しいオプション `score_column` を追加しました。

  - `score_column` を使うことで条件毎にスコアの値を格納できます。

  - 通常、Groongaは、全ての条件のスコアーを加算してスコアーを計算しますが、条件毎にスコアーの値を取得したいこともあります。

  - 例えば以下のように、中心座標にどれだけ近いかをスコアーとして使いたい場合に `score_column` が使えます。

      table_create LandMarks TABLE_NO_KEY
      column_create LandMarks name COLUMN_SCALAR ShortText
      column_create LandMarks category COLUMN_SCALAR ShortText
      column_create LandMarks point COLUMN_SCALAR WGS84GeoPoint

      table_create Points TABLE_PAT_KEY WGS84GeoPoint
      column_create Points land_mark_index COLUMN_INDEX LandMarks point

      load --table LandMarks
      [
        {"name": "Aries"      , "category": "Tower"     , "point": "11x11"},
        {"name": "Taurus"     , "category": "Lighthouse", "point": "9x10" },
        {"name": "Gemini"     , "category": "Lighthouse", "point": "8x8"  },
        {"name": "Cancer"     , "category": "Tower"     , "point": "12x12"},
        {"name": "Leo"        , "category": "Tower"     , "point": "11x13"},
        {"name": "Virgo"      , "category": "Temple"    , "point": "22x10"},
        {"name": "Libra"      , "category": "Tower"     , "point": "14x14"},
        {"name": "Scorpio"    , "category": "Temple"    , "point": "21x9" },
        {"name": "Sagittarius", "category": "Temple"    , "point": "43x12"},
        {"name": "Capricorn"  , "category": "Tower"     , "point": "33x12"},
        {"name": "Aquarius"   , "category": "mountain"  , "point": "55x11"},
        {"name": "Pisces"     , "category": "Tower"     , "point": "9x9"  },
        {"name": "Ophiuchus"  , "category": "mountain"  , "point": "21x21"}
      ]

      select LandMarks \
        --sort_keys 'distance' \
        --columns[distance].stage initial \
        --columns[distance].type Float \
        --columns[distance].flags COLUMN_SCALAR \
        --columns[distance].value 0.0 \
        --output_columns 'name, category, point, distance, _score' \
        --limit -1 \
        --filter 'geo_in_circle(point, "11x11", "11x1", {"score_column": distance}) && category == "Tower"'
      [
        [
          0,
          1590647445.406149,
          0.0002503395080566406
        ],
        [
          [
            [
              5
            ],
            [
              [
                "name",
                "ShortText"
              ],
              [
                "category","ShortText"
              ],
              [
                "point",
                "WGS84GeoPoint"
              ],
              [
                "distance",
                "Float"
              ],
              [
                "_score",
                "Int32"
              ]
            ],
            [
              "Aries",
              "Tower",
              "11x11",
              0.0,
              1
            ],
            [
              "Cancer",
              "Tower",
              "12x12",
              0.0435875803232193,
              1
            ],
            [
              "Leo",
              "Tower",
              "11x13",
              0.06164214760065079,
              1
            ],
            [
              "Pisces",
              "Tower",
              "9x9",
              0.0871751606464386,
              1
            ],
            [
              "Libra",
              "Tower",
              "14x14",
              0.1307627409696579,
              1
            ]
          ]
        ]
      ]

  - 上記の例では、 `_score` によるソートは意味をなしません。 `category == "Tower"` によって、 `_score` の値は全て `1` になるためです。しかし、 `socre_column` を使うことで、中心座標からの距離でソートできます。

- [Windows] クラッシュしていないくてもエラー時にはバックトレースが出力されるようになりました。

- [Windows] 古いWindowsのサポートをやめました。

  - 10.0.3から、Windows 8 (Windows Server 2012) 以降を要求します。

- [select] 参照可能なソートキーとそうでないソートキーが混在しているときのソートパフォーマンスを改善しました。

  - 参照可能なソートキーとそうでないソートキーが混在していて、参照可能なキーが2つ以上あるときのソートパフォーマンスを改善しました。

    - 参照可能なソートキーとは以下のソートキー以外のことです。

      - 圧縮されたカラム

      - ドリルダウンのキーに複数の値が指定されているドリルダウンの値を格納する `_value`

      - `ShortText` 型のキーを持たないパトリシアトライテーブルの `_key`

      - `_score`

  - 文字列以外のソートキーが多いほど、ソートに使用するメモリ使用量が少なくなります。

- [select] 全てのソートキーが参照可能なキーの時のソートのパフォーマンスを改善しました。

- [select] `_socre = column1*X + column2*Y + ...` の場合のスコアラーのパフォーマンスを改善しました。

  - この最適化は、 `_score` 内に多くの `+` または `*` がある場合に効きます。

  - 現状、 `+` と `*` に対してのみ効果があります。

- [select] フレーズ近傍検索をサポートしました。

  - フレーズ単位で近傍検索できます。

    - フレーズ近傍検索のクエリー構文は、 `*NP"Phrase1 phrase2 ..."` です。

    - フレーズ近傍検索のスクリプト構文は、 `column *NP "phrase1 phrase2 ..."` です。

    - 検索対象のフレーズにスペースを含む場合、 以下のようにフレーズを `"` で囲うことで検索できます。

          table_create Entries TABLE_NO_KEY
          column_create Entries content COLUMN_SCALAR Text

          table_create Terms TABLE_PAT_KEY ShortText \
            --default_tokenizer 'TokenNgram("unify_alphabet", false, \
                                            "unify_digit", false)' \
            --normalizer NormalizerNFKC121
          column_create Terms entries_content COLUMN_INDEX|WITH_POSITION Entries content

          load --table Entries
          [
          {"content": "I started to use Groonga. It's very fast!"},
          {"content": "I also started to use Groonga. It's also very fast! Really fast!"}
          ]

          select Entries --filter 'content *NP "\\"I started\\" \\"use Groonga\\""' --output_columns 'content'
          [
            [
              0,
              1590469700.715882,
              0.03997230529785156
            ],
            [
              [
                [
                  1
                ],
                [
                  [
                    "content",
                    "Text"
                  ]
                ],
                [
                  "I started to use Groonga. It's very fast!"
                ]
              ]
            ]
          ]

- [ベクターカラム] 重み付きベクターの重みに `float32` 型を追加しました。

  - `uint32` の代わりに `float32` として重みを格納できます。

  - この機能を使うには、 `column_create` 実行時に `WEIGHT_FLOAT32` フラグを追加する必要があります。

        column_create Records tags COLUMN_VECTOR|WITH_WEIGHT|WEIGHT_FLOAT32 Tags

  - 今の所、 `WEIGHT_FLOAT32` フラグは、 `COLUMN_INDEX` フラグと併用できません。

- 以下のAPIを公開しました。

  - `grn_obj_is_xxx` 関数を追加しました。詳細は以下の通りです。

    - `grn_obj_is_weight_vector(grn_ctx *ctx, grn_obj *obj)`

      - 重み付きベクターかどうかを `bool` として返します。

    - `grn_obj_is_uvector(grn_ctx *ctx, grn_obj *obj)`

      - `uvector` かどうかを `bool` として返します。

        - `uvector` とは、要素のサイズが固定の `vector` です。

    - `grn_obj_is_weight_uvector(grn_ctx *ctx, grn_obj *obj)`

      - 重み付きuvectorかどうかを `bool` として返します。

  - `grn_type_id_size(grn_ctx *ctx, grn_id id)` を追加しました。

    - Groongaのデータ型のサイズを `size_t` として返します。

  - `grn_selector_data_get_xxx` を追加しました。詳細は以下の通りです。

    - これらの関数はセレクター関連のデータを返します。

      - これらの関数はセレクターの中で呼び出すことを想定しています。セレクター以外の場所で呼び出された場合は、 `NULL` を返します。

        - `grn_selector_data_get(grn_ctx *ctx)`

          - セレクター呼び出しに関する全ての情報を `grn_selector_data *` 構造体として返します。

        - `grn_selector_data_get_selector(grn_ctx *ctx, grn_selector_data *data)`

          - セレクター自身を `grn_obj *` として返します。

        - `grn_selector_data_get_expr(grn_ctx *ctx, grn_selector_data *data)`

          - セレクターに使用されている、 `--filter` 条件や `--query` 条件を `grn_obj *` として返します。

        - `grn_selector_data_get_table(grn_ctx *ctx, grn_selector_data *data)`

          - 検索対象のテーブルを `grn_obj *` として返します。

        - `grn_selector_data_get_index(grn_ctx *ctx, grn_selector_data *data)`

          - セレクターに使われているインデックスを `grn_obj *` として返します。

        - `grn_selector_data_get_args(grn_ctx *ctx, grn_selector_data *data, size_t *n_args)`

          - セレクターが呼び出した関数の引数を `grn_obj *` として返します。

        - `grn_selector_data_get_result_set(grn_ctx *ctx, grn_selector_data *data)`

          - 結果テーブルを `grn_obj *` として返します。

        - `grn_selector_data_get_op(grn_ctx *ctx, grn_selector_data *data)`

          - 既存の結果セットに対してどう集合演算したかを `grn_operator` として返します。

  - `grn_plugin_proc_xxx` 関数を追加しました。詳細は以下の通りです。

    - `grn_plugin_proc_get_value_operator(grn_ctx *ctx, grn_obj *value, grn_operator default_operator, const char *context)`

      - クエリーオペレーターを `grn_operator` として返します。

        - 例えば、 `&&` は `GRN_OP_ANDP` として返されます。

    - `grn_plugin_proc_get_value_bool(grn_ctx *ctx, grn_obj *value, bool default_value, const char *tag)`

      - 以下の関数の引数 `with_transposition` のように `true` または `false` が指定される値を `bool` として返します。( `bool` はC言語のデータ型です。)

            fuzzy_search(column, query, {"max_distance": 1, "prefix_length": 0, "max_expansion": 0, "with_transposition": true})

  - `grn_proc_options_xxx` 関数を追加しました。詳細は以下の通りです。

    - これらは、 `query()` でのみ使えます。

      - `grn_proc_options_parsev(grn_ctx *ctx, grn_obj *options, const char *tag, const char *name, va_list args)` を追加しました。

        - オプションのパースを実行します。

        - 今までは、オプションのパースを自分で実装しなければなりませんでしたが、この関数を呼び出すだけでオプションをパースできます。

      - `grn_proc_options_parse(grn_ctx *ctx, grn_obj *options, const char *tag, const char *name, ...)`

        - `grn_proc_option_parsev()` を呼び出します。したがって、この関数の機能は、 `grn_proc_options_parsev()` と同じです。

        - `grn_proc_options_parsev()` とは、インターフェースだけが異なります。

  - `grn_text_printfv(grn_ctx *ctx, grn_obj *bulk, const char *format, va_list args)` を追加しました。

    - `grn_text_vprintf` は10.0.3から非推奨になりました。 代わりに `grn_text_printfv` を使ってください。

  - `grn_type_id_is_float_family(grn_ctx *ctx, grn_id id)` を追加しました。

    - `grn_type_id` が `GRN_DB_FLOAT32` または `GRN_DB_FLOAT` かどうかを `bool` として返します。

  - `grn_dat_cursor_get_max_n_records(grn_ctx *ctx, grn_dat_cursor *c)` を追加しました。

    - カーソルが保持できるレコード数の最大値を `size_t` として返します。(このAPIはDATテーブル用です。)

  - `grn_table_cursor_get_max_n_records(grn_ctx *ctx, grn_table_cursor *cursor)` を追加しました。

    - カーソルが保持できるレコード数の最大値を返します。

    - 全ての種類(`TABLE_NO_KEY`, `TABLE_HASH_KEY`, `TABLE_DAT_KEY`, `TABLE_PAT_KEY`)のテーブルで使えます。

  - `grn_result_set_add_xxx` を追加しました。詳細は以下の通りです。

    - `grn_result_set_add_record(grn_ctx *ctx, grn_hash *result_set, grn_posting *posting, grn_operator op)`

      - 結果セットのテーブルにレコードを追加します。

      - `grn_ii_posting_add_float` は10.0.3から非推奨になりました。代わりに `grn_rset_add_records()` を使ってください。

    - `grn_result_set_add_table(grn_ctx *ctx, grn_hash *result_set, grn_obj *table, double score, grn_operator op)`

      - 結果セットにテーブルを追加します。

    - `grn_result_set_add_table_cursor(grn_ctx *ctx, grn_hash *result_set, grn_table_cursor *cursor, double score, grn_operator op)`

      - 結果セットにカーソル内のレコードを追加します。

  - `grn_vector_copy(grn_ctx *ctx, grn_obj *src, grn_obj *dest)` を追加しました。

    - `vector` オブジェトをコピーします。 `vector` オブジェクトのコピーに成功したかどうかを返します。

  - `grn_obj_have_source(grn_ctx *ctx, grn_obj *obj)` を追加しました。

    - ソースカラムを持つカラムかどうかを `bool` として返します。

  - `grn_obj_is_token_column(grn_ctx *ctx, grn_obj *obj)` を追加しました。

    - トークンカラムかどうかを `bool` として返します。

  - `grn_hash_add_table_cursor(grn_ctx *ctx, grn_hash *hash, grn_table_cursor *cursor, double score)` を追加しました。

    - 結果セットを一括して挿入するための関数です。 `grn_ii_posting_add()` を使ってレコードを挿入するより高速です。

### 修正

- 複数のスレッドから、同時にモジュール(トークナイザー、ノーマライザー、トークンフィルター)が使われた場合にクラッシュする問題を修正しました。

- `Float32` の値を表示する際の精度を修正しました。

  - 10.0.3から `Float32` の値の精度は、 8桁から7桁になります。

- 動的カラムのパラメーターだけが違うクエリーが実行された時にGroongaが誤ったキャッシュを使用していた問題を修正しました。 [GitHub#1102 naoaさんがパッチ提供]

### 感謝

- naoaさん

## 10.0.2リリース - 2020-04-29

### 改良

- `time_classify_*` 関数が `uvector` に対応しました。 [GitHub#1089][naoaさんがパッチ提供]

  - `uvector` とは、要素のサイズが固定のベクターです。

  - 例えば、Time型の要素を格納しているベクターは `uvector` です。

- ゼロコピーで値を参照できないソートキーが混在しているケースでソートのパフォーマンスを改善しました。

  - いくつかのソートキー(例えば、 `_score` 等)の値はゼロコピーで値を参照できません。

  - これらの値が一つでも含まれる場合、以前は全てのソートキーの値をコピーしていました。

  - 今回の変更から、参照できないソートキーの値だけコピーし、参照可能なソートキーの値はコピーせずに参照するようにしました。

  - ただ、この変更で全てのソートキーの値が参照可能なケースでパフォーマンスが落ちる可能性があります。

- 重み付きベクターをJSON文字列としてロードできるようにしました。

  - 以下の例のように、重み付きベクターをJSON文字列としてロードできます。

        table_create Tags TABLE_PAT_KEY ShortText
        table_create Data TABLE_NO_KEY
        column_create Data tags COLUMN_VECTOR|WITH_WEIGHT Tags
        column_create Tags data_tags COLUMN_INDEX|WITH_WEIGHT Data tags
        load --table Data
        [
          {"tags": "{\"fruit\": 10, \"apple\": 100}"},
          {"tags": "{\"fruit\": 200}"}
        ]

- `Float32` 型をサポートしました。

  - Groongaは既に `Float` 型を持っていますが、これは、倍精度浮動小数点数です。したがって、単精度浮動小数点数のみを使う場合は、効率が悪いです。

  - `Float32` 型を追加することで、より適切な型を選択できるようになりました。

- 以下のAPIを公開しました。

  - `grn_obj_unref(grn_ctx *ctx, grn_obj *obj)`

    - このAPIは参照カウントモードのときのみ使用します。(参照カウントモードとは、 `GRN_ENABLE_REFERENCE_COUNT=yes` の状態のことです。)

      - このAPIは、参照カウントモードの時のみ `grn_obj_unlink()` を呼び出します。参照カウントモード以外の時は、何もしません。

      - 参照カウントモードの時のみ `grn_obj_unlink()` を呼び出す必要がある時に便利です。

      - 以下の例のように、参照カウントモードかどうかの条件を書かなくて良くなるためです。

        - `grn_obj_unref()` を使用しない場合の例です。

              if (grn_enable_reference_count) {
               grn_obj_unlink(ctx, obj);
              }

        - `grn_obj_ubref()` を使用する場合の例です。

              grn_obj_ubref(ctx, obj);

  - `grn_get_version_major(void)`

  - `grn_get_version_minor(void)`

  - `grn_get_version_micro(void)`

    - `uint32_t` としてGroongaのメジャー、マイナー、マイクロバージョンを返します。

  - `grn_posting_get_record_id(grn_ctx *ctx, grn_posting *posting)`

  - `grn_posting_get_section_id(grn_ctx *ctx, grn_posting *posting)`

  - `grn_posting_get_position(grn_ctx *ctx, grn_posting *posting)`

  - `grn_posting_get_tf(grn_ctx *ctx, grn_posting *posting)`

  - `grn_posting_get_weight(grn_ctx *ctx, grn_posting *posting)`

  - `grn_posting_get_weight_float(grn_ctx *ctx, grn_posting *posting)`

  - `grn_posting_get_rest(grn_ctx *ctx, grn_posting *posting)`

    - これらは、ポスティングリストの情報を返します。

    - これらのAPIは、 `grn_posting_get_weight_float` 以外は、 `uint32_t` として値を返します。

    - `grn_posting_get_weight_float` は `float` として値を返します。

    - `grn_posting_get_section_id(grn_ctx *ctx, grn_posting *posting)`

      - セクションIDとはカラム名の内部表現です。

      - カラム名を文字列としてポスティングリストに格納すると、情報量が多くなり無駄な容量を使います。

      - したがって、カラム名をセクションIDという数値としてポスティングリストに格納することで、情報量を圧縮し使用する容量を少なくしています。

    - `grn_posting_get_tf(grn_ctx *ctx, grn_posting *posting)`

      - `grn_posting_get_tf` の `tf` とは、単語の出現頻度です。

    - `grn_posting_get_weight_float(grn_ctx *ctx, grn_posting *posting)`

      - トークンの重みを `float` として返します。

      - 今後はトークンの重みを取得する際はこのAPIを使用することをおすすめします。

        - 近い将来、重みは内部的に `uint32_t` から `float` に変更するためです。

### 修正

- 32bit GUN/Linux等でGroongaがクラッシュすることがある問題を修正しました。

- 関係のないカラムの値をクリアーしてしまう問題を修正しました。 [GitHub#1087][sutaminさんの報告]

- `dump` コマンドでレコードをダンプした時にメモリリークする問題を修正しました。

- `output_columns` に無効な値を指定した時にメモリリークする問題を修正しました。

- `snippet` 関数を実行する時にメモリリークする問題を修正しました。

- 以下の条件を満たした時にメモリリークする問題を修正しました。

  - `initial` ステージで動的カラムを使用した場合。

  - `select` コマンドの引数 `slices` を使用した場合。

- `logical_table_remove` でテーブルを削除した際にメモリリークする問題を修正しました。

- 参照カウントモードを使用した時にメモリリークする問題を修正しました。

  - 参照カウントモードとは、 `GRN_ENABLE_REFERENCE_COUNT=yes` の状態のことです。

  - この機能は実験的です。パフォーマンスが低下することがあります。

- Apache Arrow形式でデータをロードした際に `_key` アクセサーを解放しすぎる問題を修正しました。

### 感謝

- sutaminさん

- naoaさん

## 10.0.1リリース - 2020-03-30

Groonga 10.0.0 のUbuntuとWindows(VC++版)のパッケージに誤りがあったため Groonga 10.0.1 をリリースしました。

既にCentOS、Debian、Windows(MinGW版)のGroonga 10.0.0を使用している方は、そのまま使っていただいて問題ありません。

### 修正

- Windows(VC++版)のパッケージに不足していたランタイム(vcruntime140_1.dll)を追加しました。

## 10.0.0リリース - 2020-03-29

### 改良

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

- [httpd] 出力形式を拡張子として指定できるようにしました。

  - 例えば、 `load?output_type=json` の代わりに `load.json` と書けます。

- [ログ] Linuxのdumpレベルのログにオープンしたファイルとクローズしたファイルのパスを出力するようにしました。

- [ログ] Windowsのdebugレベルのログにオープンしたファイルとクローズしたファイルのパスを出力するようにしました。

- 以下のAPIとマクロを追加しました。

  - `grn_timeval_from_double(grn_ctx, double)`

    - このAPIは、 `double` 型を `grn_timeval` 型に変換します。

    - `grn_timeval` 型の値を返します。

  - `GRN_TIMEVAL_TO_NSEC(timeval)`

    - このマクロは、 `grn_timeval` 型の値を `uint64_t` 型の値としてナノ秒に変換します。

  - `GRN_TIME_USEC_TO_SEC(usec)`

    - このマクロは、ミリ秒を秒に変換します。

- 以下のマクロを非推奨にしました。

  - `GRN_OBJ_FORMAT_FIN(grn_ctx, grn_obj_format)`

    - 10.0.0から代わりに `grn_obj_format_fin(grn_ctx, grn_obj_format)` を使ってください。

- [logical_range_filter],[dump] ストリーム出力に対応しました。

  - この機能は `command_version 3` 以降で使えます。headerがbodyの後に出力されます。

  - 現在、この機能をサポートしているのは、 `dump` と `logical_range_filter` のみです。

  - `logical_range_filter` は、 `command_version 3` 以降では、常に出力がstreamとして返ります。

  - この機能は以下の制限があります。

    - `limit` に指定できる負の値は -1 のみです。

    - MessagePack形式の出力はサポートしていません。

  - この変更で、JSONの応答内容を少し変更しています。

    - 以下のように以前のバージョンとは、キーの順序が異なっています。

      - 以前のバージョンのキーの順序

            {
              "header": {...},
              "body": {...}
            }

      - 本バージョン(10.0.0)のキーの順序

            {
              "body": {...},
              "header": {...}
            }

  - `dump` と `logical_range_filter` を `command_version 3` で実行した時はキャッシュが効きません。

    - 10.0.0から `dump` と `logical_range_filter` は `command_version 3` の時にストリームで応答を返すので、応答全体をキャッシュできないためです。

- [logical_range_filter] Apache Arrow形式での応答をサポートしました。

  - 以下のデータ型をサポートしています。

    - `UInt8`

    - `Int8`

    - `UInt16`

    - `Int16`

    - `UInt32`

    - `Int32`

    - `UInt64`

    - `Int64`

    - `Time`

    - `ShortText`

    - `Text`

    - `LongText`

    - `Vector` of `Int32`

    - `Reference vector`

- Ubuntu 20.04 (Focal Fossa)をサポートしました。

- Ubuntu 19.04 (Disco Dingo)のサポートをやめました。

  - このバージョンはEOLになっているためです。