BloGroonga

2023-09-29

Groonga 13.0.8リリース

Groonga 13.0.8をリリースしました!

それぞれの環境毎のインストール方法: インストール

変更内容

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

改良

  • [column_create] column_create に新しいフラグ COLUMN_FILTER_SHUFFLE, COLUMN_FILTER_BYTE_DELTA, COMPRESS_FILTER_TRUNCATE_PRECISION_1BYTE, COMPRESS_FILTER_TRUNCATE_PRECISION_2BYTES を追加しました。

    これらのフラグは、圧縮前にデータをフィルタリングすることによって COMPRESS_ZLIB, COMPRESS_LZ4, COMPRESS_ZSTD の圧縮率を高めるためのフラグです。 データによっては、これらのフラグを使っても圧縮率が上がらないこともあります。また、これらのフラグを使うと、カラムの保存や参照に追加の処理が加わるので、これらのフラグを使うと、カラムの保存や参照は確実に遅くなります。

    効果のあるフラグのみを使う事が重要です。

    COMPRESS_ZLIB, COMPRESS_LZ4, COMPRESS_ZSTD を指定してない場合でも、これらのフラグは、圧縮アルゴリズムとして BloscLZ を使うので、これらのフラグを使うことで、ほとんどの場合で非圧縮のカラムよりもカラムサイズを小さくできます。 ただ、データによっては、 COMPRESS_ZLIB, COMPRESS_LZ4, COMPRESS_ZSTD を使うだけで十分な場合もあります。 そのため、データによって適切なフラグを設定することをおすすめします。

    これらのフラグは、 COLUMN_VECTOR でのみ使用できます。 COLUMN_SCALAR の場合は、これらのフラグは無視されます。

    では、各フラグにとってどのようなデータが適切かを記載します。

    • COLUMN_FILTER_SHUFFLE

      このフラグはNバイト目の要素に着目してデータを並び替えます。

      このフラグは、まずベクターカラム内の各要素の0バイト目だけのデータを集めて連続で配置します。 その後、同様に1バイト目のデータだけを集めて連続で配置するということをすべてのバイトに対して繰り返します。

      COMPRESS_ZLIBCOMPRESS_LZ4COMPRESS_ZSTD といった圧縮アルゴリズムは同じ値が連続しているデータだと圧縮率が高くなる傾向があります。 このフラグのポイントは、Nバイトごとにデータを並び替えることで同じ値が連続しているデータを作り出すことです。

      では、具体的にどのような操作をするのかを記載します。

      例えば、UInt32のベクターカラム[1, 1051, 515]があるとします。 これをリトルエンディアンのバイト列で表現すると以下のようになります。

      | Byte 0 | Byte 1 |  | Byte 0 | Byte 1 |  | Byte 0 | Byte 1 |
      |--------|--------|  |--------|--------|  |--------|--------|
      | 0x00   | 0x01   |, | 0x04   | 0x1b   |, | 0x02   | 0x03   |
      

      このフラグは、上記のByte 0の値をまとめて、その後Byte 1のデータをまとめ以下のようなデータを作るフラグです。 この、Nバイト毎にまとめる操作を以後、シャッフルと呼びます。

      | Byte 0 | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 | Byte 1 |
      |--------|--------|--------|  |--------|--------|--------|
      | 0x00   | 0x04   | 0x02   |, | 0x01   | 0x1b   | 0x03   |
      

      ポイントは「同じ値が連続する箇所があるかどうか?」です。 上記の例を見てみると、シャッフル後のデータは同じ値が連続している箇所がありません。 このようなデータでは、シャッフルしても圧縮率の向上に寄与しないため、このフラグを適用するには不向きなデータです。

      一方で、UInt32のベクターカラム[1,2,3]というデータでは、シャッフルすると以下のようになります。

      まず、説明のためUInt32:[1,2,3]を以下のようなバイト列表現にします。

      | Byte 0 | Byte 1 |  | Byte 0 | Byte 1 |  | Byte 0 | Byte 1 |
      |--------|--------|  |--------|--------|  |--------|--------|
      | 0x00   | 0x01   |, | 0x00   | 0x02   |, | 0x00   | 0x03   |
      

      そして、UInt32:[1,2,3]をシャッフルすると以下のようなデータになります。

      | Byte 0 | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 | Byte 1 |
      |--------|--------|--------|  |--------|--------|--------|
      | 0x00   | 0x00   | 0x00   |, | 0x01   | 0x02   | 0x03   |
      

      UInt32:[1,2,3]というデータだと、シャッフル後にByte 0のデータがすべて0になり、同じ値が連続することになります。 したがって、このようなデータは圧縮率の向上に寄与するので、このフラグを適用するのに向いているデータです。 浮動小数点数であれば、符号と指数部が同じデータが該当します。 IEEE 754 形式の単精度浮動小数点数の場合、符号は31ビット目に配置され、指数部は30ビット目から23ビット目に配置されます。 符号ビットと指数部の上位7ビットで最上位のバイトが構成されるので符号ビットと指数部の上位7ビットが同じになれば、シャッフル後は同じ値が連続することになるからです。

      例えば、Float32:[0.5, 0.6]というデータは、IEEE 754 形式の単精度浮動小数点数で表現すると以下のように符号ビットと指数部が同一です。

      | 符号(1bit) | 指数部(8bit) | 仮数部(23bit)                 |
      |------------|-------------|------------------------------|
      | 0          | 0111 1110   | 000 0000 0000 0000 0000 0000 |
      | 0          | 0111 1110   | 001 1001 1001 1001 1001 1010 |
      

      これを、シャッフルすると以下のようになり、 Byte 3に同じ値が連続することになります。

      | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 |  | Byte 2 | Byte 2 |  | Byte 3 | Byte 3 | 
      |--------|--------|  |--------|--------|  |--------|--------|  |--------|--------| 
      | 0x00   | 0x9a   |, | 0x00   | 0x99   |, | 0x00   | 0x19   |, | 0x3f   | 0x3f   | 
      
    • COLUMN_FILTER_BYTE_DELTA

      このフラグは、圧縮対象の値のバイト間の差分を計算するフラグです。 このフラグは、隣り合うバイトの差分を計算します。例えばUInt8のベクターカラム[1,2,3,4,5]というデータの場合、このフラグを適用すると[1,(2-1),(3-2),(4-3),(5-4)]=[1,1,1,1,1]というデータになります。

      上記のように差分データを計算することで、同じ値が連続するデータを作り圧縮率を向上させることを狙っています。 ポイントは、各要素間の差分を計算することで、同じ値が連続するデータを作り出すことにあります。

      したがって、差分を計算しても同じ値が連続するデータを作り出すことができないデータは、このフラグを適用するには不向きなデータです。 どのようなデータであれば、差分を計算して同じ値が連続するようになるのかを以下に記載します。

      まずは、前述の例でもあげた、UInt8:[1,2,3,4,5]というような一定のペースで値が増加していくデータです。 一定のペースなので、UInt8:[1,11,21,31,41]のように10ずつ値が増加するようなデータでも良いです。

      次に、UInt8:[5,5,5,5,5]のように同じ値が連続するデータです。 このデータは差分を計算すると[5,0,0,0,0]となり、0が連続するようになります。

      逆に、UInt8:[1, 255, 2, 200, 1]のように差分を計算しても同じ値が連続しないデータは、このフラグには不向きなデータです。

    • COMPRESS_FILTER_TRUNCATE_PRECISION_1BYTE

      このフラグは、 Float/Float32のデータでのみ有効です。COLUMN_FILTER_SHUFFLE と組み合わせて使うことを想定しています。

      Float/Float32ベクターカラムの各要素の精度を1バイト落とします。精度を落とすとは、浮動小数点数の最下位バイトをすべて0にすることです。

      例えば、Float32:[1.25, 3.67, 4.55]というデータは、IEEE 754 形式の単精度浮動小数点数で表現すると以下のように表現できます。

      | 符号(1bit) | 指数部(8bit) | 仮数部(23bit)                 |
      |------------|-------------|------------------------------|
      | 0          | 0111 1111   | 010 0000 0000 0000 0000 0000 |
      | 0          | 1000 0000   | 110 1010 1110 0001 0100 1000 |
      | 0          | 1000 0001   | 001 0001 1001 1001 1001 1010 |
      

      このフラグを適用すると、最下位バイトをすべて0にするので以下のようなデータになります。 仮数部の最下位バイトが0になっていることに注目してください。

      | 符号(1bit) | 指数部(8bit) | 仮数部(23bit)                 |
      |------------|-------------|------------------------------|
      | 0          | 0111 1111   | 010 0000 0000 0000 0000 0000 |
      | 0          | 1000 0000   | 110 1010 1110 0001 0000 0000 |
      | 0          | 1000 0001   | 001 0001 1001 1001 0000 0000 |
      

      ここまでが、このフラグの効果です。 前述の通り、このフラグは、 COLUMN_FILTER_SHUFFLE と組み合わせて使うことを想定しています。 そのため、ここから更にデータをシャッフルすることで、圧縮率の向上を期待しています。

      COMPRESS_FILTER_TRUNCATE_PRECISION_1BYTE を適用したデータをシャッフルすると以下のようなデータになります。

      | Byte 0 | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 | Byte 1 |  | Byte 2 | Byte 2 | Byte 2 |  | Byte 3 | Byte 3 | Byte 3 | 
      |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------| 
      | 0x00   | 0x00   | 0x00   |, | 0x00   | 0xe1   | 0x99   |, | 0xa0   | 0x6a   | 0x91   |, | 0x3f   | 0x40   | 0x40   | 
      

      Byte 0に注目してください。Byte 0に0が連続するデータになります。 COMPRESS_FILTER_TRUNCATE_PRECISION_1BYTE を適用せずにシャッフルすると以下のようなデータになり、どのバイトも同じ値が連続しなくなります。このように単純にシャッフルしただけでは、圧縮率の向上が見込めないデータでも COMPRESS_FILTER_TRUNCATE_PRECISION_1BYTE を適用することで、圧縮率の向上が見込める場合があります。

      | Byte 0 | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 | Byte 1 |  | Byte 2 | Byte 2 | Byte 2 |  | Byte 3 | Byte 3 | Byte 3 | 
      |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------| 
      | 0x00   | 0x48   | 0x9a   |, | 0x00   | 0xe1   | 0x99   |, | 0xa0   | 0x6a   | 0x91   |, | 0x3f   | 0x40   | 0x40   | 
      

      ただし、圧縮対象の浮動小数点数の精度が1バイト分落ちるので、その分不正確なデータになることに注意してください。

    • COMPRESS_FILTER_TRUNCATE_PRECISION_2BYTES

      このフラグは、 Float/Float32のデータでのみ有効です。COLUMN_FILTER_SHUFFLE と組み合わせて使うことを想定しています。

      Float/Float32ベクターカラムの各要素の精度を2バイト落とします。精度を落とすとは、浮動小数点数の下位2バイトをすべて0にすることです。

      例えば、Float32:[1.25, 3.67, 4.55]というデータは、IEEE 754 形式の単精度浮動小数点数で表現すると以下のように表現できます。

      | 符号(1bit) | 指数部(8bit) | 仮数部(23bit)                 |
      |------------|-------------|------------------------------|
      | 0          | 0111 1111   | 010 0000 0000 0000 0000 0000 |
      | 0          | 1000 0000   | 110 1010 1110 0001 0100 1000 |
      | 0          | 1000 0001   | 001 0001 1001 1001 1001 1010 |
      

      このフラグを適用すると、下位2バイトをすべて0にするので以下のようなデータになります。 仮数部の下位2バイトが0になっていることに注目してください。

      | 符号(1bit) | 指数部(8bit) | 仮数部(23bit)                 |
      |------------|-------------|------------------------------|
      | 0          | 0111 1111   | 010 0000 0000 0000 0000 0000 |
      | 0          | 1000 0000   | 110 1010 0000 0000 0000 0000 |
      | 0          | 1000 0001   | 001 0001 0000 0000 0000 0000 |
      

      ここまでが、このフラグの効果です。

      前述の通り、このフラグは、 COLUMN_FILTER_SHUFFLE と組み合わせて使うことを想定しています。 そのため、ここから更にデータをシャッフルすることで、圧縮率の向上を期待しています。

      COMPRESS_FILTER_TRUNCATE_PRECISION_2BYTE を適用したデータをシャッフルすると以下のようなデータになります。

      | Byte 0 | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 | Byte 1 |  | Byte 2 | Byte 2 | Byte 2 |  | Byte 3 | Byte 3 | Byte 3 | 
      |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------| 
      | 0x00   | 0x00   | 0x00   |, | 0x00   | 0x00   | 0x00   |, | 0xa0   | 0x6a   | 0x91   |, | 0x3f   | 0x40   | 0x40   | 
      

      Byte 0Byte 1に注目してください。Byte 0Byte 1に0が連続するデータになります。 COMPRESS_FILTER_TRUNCATE_PRECISION_2BYTE を適用せずにシャッフルすると以下のようなデータになり、どのバイトも同じ値が連続しなくなります。このように単純にシャッフルしただけでは、圧縮率の向上が見込めないデータでも COMPRESS_FILTER_TRUNCATE_PRECISION_2BYTE を適用することで、圧縮率の向上が見込める場合があります。

      | Byte 0 | Byte 0 | Byte 0 |  | Byte 1 | Byte 1 | Byte 1 |  | Byte 2 | Byte 2 | Byte 2 |  | Byte 3 | Byte 3 | Byte 3 | 
      |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------|  |--------|--------|--------| 
      | 0x00   | 0x48   | 0x9a   |, | 0x00   | 0xe1   | 0x99   |, | 0xa0   | 0x6a   | 0x91   |, | 0x3f   | 0x40   | 0x40   | 
      

      ただし、圧縮対象の浮動小数点数の精度が2バイト分落ちるので、その分不正確なデータになることに注意してください。

  • 新しくBloscライブラリーをバンドルしました。

    COLUMN_FILTER_SHUFFLE, COLUMN_FILTER_BYTE_DELTA, COMPRESS_FILTER_TRUNCATE_PRECISION_1BYTE, COMPRESS_FILTER_TRUNCATE_PRECISION_2BYTES フラグがBloscを要求するためです。

  • [status] 新しく status の出力に "blosc" を追加しました。

  • [groonga] 新しく groonga --version の出力に blosc を追加しました。

  • [select] 新しく select の引数に --fuzzy_max_distance を追加しました。(実験的)

    この引数は、誤字を許容する検索を実行する時に有用です。ユーザーの誤字を自動で補正することができます。

    この引数が指定された場合、以下のようにマッチしないクエリーが与えられた時、Groongaは語彙表から --fuzzy_max_distance 以下の編集距離の語を探して、再度検索します。

    table_create Memos TABLE_NO_KEY
    column_create Memos content COLUMN_SCALAR ShortText
    
    table_create Lexicon TABLE_PAT_KEY ShortText   --default_tokenizer TokenNgram   --normalizer NormalizerNFKC150
    column_create Lexicon memos_content   COLUMN_INDEX|WITH_POSITION Memos content
    load --table Memos
    [
    {"content": "This is a pen"},
    {"content": "That is a pen"}
    ]
    
    select Memos   --match_columns content   --query "Thjs"   --fuzzy_max_distance 1   --output_columns *,_score
    [
      [
        0,
        0.0,
        0.0
      ],
      [
        [
          [
            1
          ],
          [
            [
              "content",
              "ShortText"
            ],
            [
              "_score",
              "Int32"
            ]
          ],
          [
            "This is a pen",
            1
          ]
        ]
      ]
    ]
    
  • [select] 新しく select の引数に --fuzzy_max_expansions を追加しました。(実験的)

    --fuzzy_max_distance を使うと、与えられたクエリーがマッチしない時、語彙表の中から --fuzzy_max_distance 以下の編集距離の語を使って再度検索します。

    例えば、語彙表にThisThatが存在しているとします。 --fuzzy_max_distance 10Thjsというクエリーが与えられた時に、Thjsでマッチしない場合は、語彙表にあるThisThatで検索します。

    上記の例では、語彙表に --fuzzy_max_distance が10以下の語が2つしかありませんが、もし、編集距離が10以下の語が大量に語彙表に存在した場合、それらの語すべてを使って検索するため、パフォーマンスが落ちます。

    --fuzzy_max_expansions を使うことで検索に使う編集距離の近い語の数を制限できます。 この引数を使って、ヒット数と検索パフォーマンスのバランスを取ることができます。

    --fuzzy_max_expansions のデフォルト値は0で、0の場合は語彙表にある編集距離が--fuzzy_max_distance 以下の語すべてを使って検索をします。

  • [select] 新しく select の引数に --fuzzy_max_distance_ratio を追加しました。(実験的)

    --fuzzy_max_distance はすべてのクエリーに対して同じ値が設定されます。したがって、例えば "abc OR defghijklmn" というクエリーが与えられたときは "abc" と "defghijklmn" の両方に --fuzzy_max_distance の値が設定されます。

    しかし、検索するキーワードによって、誤字をどのくらい許容するかは異なっていることが多いです。 例えば、"abc"は文字数が少ないので、誤字は1文字だけ許容する一方、"defghijklmn"は文字数が多いので、誤字は3文字許容するというようなことが発生します。

    --fuzzy_max_distance_ratio は文字数によって、編集距離を自動で変更するためのものです。 この引数によって、キーワード毎に異なる編集距離を設定できます。

    --fuzzy_max_distance_ratio FUZZY_MAX_DISTANCE とすると、編集距離は"文字数 * FUZZY_MAX_DISTANCE"(小数点以下は切り捨てされます)と計算されます。 "FUZZY_MAX_DISTANCE" は 0.34 を推奨しています。 これは、0.34にするとElasticsearchの fuzziness=AUTOとほぼ同じ値になるためです。

  • [select] 新しく select の引数に --fuzzy_prefix_length を追加しました。(実験的)

    --fuzzy_max_distanceを使う検索を高速化するための引数です。

    検索キーワードの先頭から --fuzzy_prefix_length に設定した文字数分が共通のデータのみヒットするようになります。

    --fuzzy_max_distance が大きくなると、処理対象が増加し遅くなるため、最初に先頭N文字が共通な文字列にのみ処理対象を絞ることで高速に処理できることが多いです。

  • [cast] 以下のように、 "[0.0, 1.0, 1.1, ...]"Float/Float32 のベクターカラムへのキャストできるようにしました。

    plugin_register functions/vector
    
    table_create Data TABLE_NO_KEY
    column_create Data numbers COLUMN_VECTOR Float32
    
    table_create Numbers TABLE_PAT_KEY Float32
    column_create Numbers data_numbers COLUMN_INDEX Data numbers
    
    load --table Data
    [
    {"numbers": "[0.1, 0.0, -0.2]"},
    {"numbers": "[-3, 2, -4294967296, 4294967296]"}
    ]
    
    dump   --dump_plugins no   --dump_schema no
    load --table Data
    [
    ["_id","numbers"],
    [1,[0.1,0.0,-0.2]],
    [2,[-3.0,2.0,-4.294967e+09,4.294967e+09]]
    ]
    
    column_create Numbers data_numbers COLUMN_INDEX Data numbers
    select Data --filter 'vector_size(numbers) == 3'
    [
      [
        0,
        0.0,
        0.0
      ],
      [
        [
          [
            1
          ],
          [
            [
              "_id",
              "UInt32"
            ],
            [
              "numbers",
              "Float32"
            ]
          ],
          [
            1,
            [
              0.1,
              0.0,
              -0.2
            ]
          ]
        ]
      ]
    ]
    
  • [fuzzy_search] max_expansion オプションの名前を max_expansions に変更しました。

    max_expansion オプションは非推奨になりますが、後方互換性を維持するため引き続き使えます。

  • masterブランチの名前をmainに変更しました。

  • [RPM] CMakeを使ってビルドするようにしました。

  • [Debian] Debian trixie をサポートしました。

修正

  • [fuzzy_search] ヒットするはずのレコードがヒットしない問題を修正しました。

  • [near-phrase-search] 以下のように最初のフレーズグループに何もヒットしない時にGroongaがクラッシュする問題を修正しました。

    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": "x y z"}
    ]
    select Entries \
      --match_columns Terms.entries_content.content \
      --query '*NPP1"(NONEXISTENT) (z)"' \
      --output_columns '_score, content'