[groonga-dev,04026] [ANN] Groonga 6.0.3

Back to archive index

Kentaro Hayashi hayas****@clear*****
2016年 5月 29日 (日) 21:04:54 JST


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

  http://groonga.org/ja/blog/2016/05/29/groonga-6-0-3.html

# 変更内容

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

  * command version 3を導入しました
  * インデックスを使わない場合の最適化によりbetween()を高速化しました
  * 新規プラグインを2つ追加しました
  * ウィンドウ関数をサポートしました

また、クラッシュしてしまう不具合が修正されていたりするのでアップグ
レードをおすすめします。

細かな変更点についてはニュースをご確認下さい。

  http://groonga.org/ja/docs/news.html#release-6-0-3-2016-05-29

以下、主な変更点について紹介します。

## command version 3を導入しました

今回のリリースでは、コマンドバージョン3を導入しました。

Groongaにはコマンドにバージョンの概念があります。

  http://groonga.org/ja/docs/reference/command/command_version.html

従来は[HEADER, BODY]という形式でレスポンスを返していました。

    > status
    [
      [0,1464342851.826973,0.0002036094665527344],
      {
        "alloc_count":273,
        "starttime":1464342849,
        "start_time":1464342849,
        "uptime":2,
        "version":"6.0.3",
        "n_queries":0,
        "cache_hit_rate":0.0,
        "command_version":1,
        "default_command_version":1,
        "max_command_version":3
      }
    ]

コマンドバージョン 3を指定すると、レスポンスは次のようにオブジェクトリ
テラル形式となります。

    > status --command_version 3
    {
      "header":{
        "return_code":0,
        "start_time":1464342859.177147,
        "elapsed_time":0.0001118183135986328
      },
      "body":{
        "alloc_count":276,
        "starttime":1464342849,
        "start_time":1464342849,
        "uptime":10,
        "version":"6.0.3",
        "n_queries":0,
        "cache_hit_rate":0.0,
        "command_version":3,
        "default_command_version":1,
        "max_command_version":3
      }
    }

コマンドバージョン 3がサポートされたことで、例えば、JavaScriptなどから
レスポンスを扱いやすくなりますね。

## インデックスを使わない場合の最適化によりbetween()を高速化しました

今回のリリースでは、インデックスを使わない場合の最適化によりbetween()
を高速化することができました。

インデックスを使った場合は速かったのですが、それに比べるとインデックス
を使わなかった時のパフォーマンスに問題がありました。今回はそのパフォー
マンスの問題が改善されています。

どれくらい改善されたかというのをベンチマークを示します。

テストケースには次のようなスキーマを使いました。

    table_create Entries TABLE_NO_KEY
    column_create Entries rank COLUMN_SCALAR Int32

インデックスを使わずに、シーケンシャルサーチが行われるケースです。

テストデータは千件から百万件の4つのパターンを用意しました。

  * 1,000件
  * 10,000件
  * 100,000件
  * 1,000,000件

シーケンシャルな連番をrankとして設定されているデータです。

これに対して、次のようにbetween()を適用してみました。
100件だけ範囲検索するケースです。

* 1000件(rankの値が500より大きく、600以下)
* 10,000件(rankの値が5000より大きく、5100以下)
* 100,000件(rankの値が50,000より大きく、50,100以下)
* 1,000,000件(rankの値が500,000より大きく、500,100以下)

クエリは例えば次のようなものです。

    select Entries --cache no --filter 'between(rank, 500, "exclude", 600, "include")'

ベンチマークの結果は次のようになりました。10回実行した中央値をだしてい
ます。

Groonga 6.0.2からGroonga 6.0.3でかなり改善していることがわかります。

  * 1,000件 4.3ms -> 0.2590ms
  * 10,000件 39.5ms -> 0.6440ms
  * 100,000件 390ms -> 5.1ms
  * 1,000,000件 3798.3ms -> 44.2ms

ぱっと見でもその違いがわかりますが、これを対数グラフ化するとこんな風になります。
(6.0.3リリースに関する記事のなかほどに結果のグラフがあります。)

  http://groonga.org/ja/blog/2016/05/29/groonga-6.0.3.html

#### 新規プラグインを2つ追加しました

今回のリリースでは、新規プラグインが2つ追加されました。timeプラグイン
とnumberプラグインです。

どちらも、特定の範囲の値を同じ値とみなすことができるようになります。こ
れにより、numberプラグインを使うと同一価格帯のものをまとめたりできます。

timeプラグインを使うと同時期のデータをまとめることができるようになりま
す。

numberプラグインはnumber_classify関数を提供しています。

どんなふうに使えるのかサンプルを紹介します。価格がキーであるデータがい
くつか登録されているとします。これを100円ごとのデータは同一価格帯の商
品として分類してみましょう。スキーマとサンプルは以下の通りです。

    plugin_register functions/number
    table_create Prices TABLE_PAT_KEY Int32

    load --table Prices
    [
    {"_key": 0},
    {"_key": 1},
    {"_key": 99},
    {"_key": 100},
    {"_key": 101},
    {"_key": 199},
    {"_key": 200},
    {"_key": 201}
    ]

number_classifyを使って実現するには次のようなクエリを実行します。

    select Prices --sortby _id --limit -1 --output_columns '_key, number_classify(_key, 100)'

number_classify(_key, 100)は分類には_keyの値を使うこと、値の範囲は100
区切りで分類する、というのを指定しています。

    [
      [
        [8],
        [
          ["_key","Int32"],
          ["number_classify",null]
        ],
        [0,0],
        [1,0],
        [99,0],
        [100,100],
        [101,100],
        [199,100],
        [200,200],
        [201,200]
      ]
    ]

100円ごと、なので100から199までは同一価格帯の100としてみなしていること
がわかりますね。

timeプラグインも時刻に関して似たようなことができます。次のような分類用
の関数を提供しています。

  * time_classify_second
  * time_classify_minute
  * time_classify_hour
  * time_classify_day
  * time_classify_week
  * time_classify_month
  * time_classify_year

こんどは10分ごとを同一のタイムスタンプだとみなして分類してみましょう。
サンプルのスキーマとデータは次の通りです。

    plugin_register functions/time
    table_create Timestamps TABLE_PAT_KEY Time
    load --table Timestamps
    [
    {"_key": "2016-05-05 22:29:59.999999"},
    {"_key": "2016-05-05 22:30:00.000000"},
    {"_key": "2016-05-05 22:30:00.000001"},
    {"_key": "2016-05-05 22:39:59.999999"},
    {"_key": "2016-05-05 22:40:00.000000"},
    {"_key": "2016-05-05 22:40:00.000001"}
    ]

分ごとなので、time_classify_minuteを使います。次のようなクエリを実行し
てみましょう。

    select Timestamps --sortby _id --limit -1 --output_columns '_key, time_classify_minute(_key, 10)'

結果はこんなふうになります。

    [
      [
        [6],
        [
          ["_key","Time"],
          ["time_classify_minute",null]
        ],
        [1462454999.999999,1462454400.0],
        [1462455000.0,1462455000.0],
        [1462455000.000001,1462455000.0],
        [1462455599.999999,1462455000.0],
        [1462455600.0,1462455600.0],
        [1462455600.000001,1462455600.0]
      ]
    ]

10分ごとなので、22:30分から22:39分までのデータが同一時刻(1462455000.0)
としてみなされていることがわかります。

#### ウィンドウ関数をサポートしました

今回のリリースでは、ウィンドウ関数をサポートしました。例えば、連番を振
るrecord_numberを利用することができるようになりました。

サンプルのスキーマとデータは次の通りです。

    table_create Items TABLE_HASH_KEY ShortText
    column_create Items price COLUMN_SCALAR UInt32

    load --table Items
    [
    {"_key": "item1", "price": 666},
    {"_key": "item2", "price": 999},
    {"_key": "item3", "price": 777},
    {"_key": "item4", "price": 111},
    {"_key": "item5", "price": 333},
    {"_key": "item6", "price": 222}
    ]

これをもとに、価格の安い順だと何番目のレコードになるかを取得してみましょ
う。クエリは次のようになります。

    select Items \
      --columns[nth_record].stage initial \
      --columns[nth_record].value 'record_number()' \
      --columns[nth_record].type UInt32 \
      --columns[nth_record].window.sort_keys price \
      --output_columns '_key, price, nth_record'

動的カラムnth_recordにrecord_number()の値を設定しているのがポイントで
す。

    [
      [
        [6],
        [
          ["_key","ShortText"],
          ["price","UInt32"],
          ["nth_record","UInt32"]
        ],
        ["item1",666,4],
        ["item2",999,6],
        ["item3",777,5],
        ["item4",111,1],
        ["item5",333,3],
        ["item6",222,2]
      ]
    ]

それぞれのアイテムが価格の安い順だと何番目のレコードになっているのかが
これでわかります。

## イベントのおしらせ

来月以降、以下のイベントが予定されています。

* MySQLとPostgreSQLと日本語全文検索2 https://groonga.doorkeeper.jp/events/41770
  日時: 2016-06-09(木)20:00 - 22:00
  場所: DMM.comラボ
  概要:「MySQLとPostgreSQLと日本語全文検索」の第2弾です。前回はMySQL・
        PostgreSQLの日本語全文検索機能を使ったことがない人向けの内容でし
        たが、今回は使ったことがある(触ってみたくらいで十分)人向けの内
        容です。

* Groongaで学ぶ全文検索 2016-06-17 https://groonga.doorkeeper.jp/events/45556
  日時: 2016-06-17(金)20:00 - 22:30
  場所: 東京都渋谷区広尾1-1-39 恵比寿プライムスクエアタワー20階
        (株式会社イーライセンスシステムズ)
  概要: 予習復習なしで全文検索とGroongaについて学ぶことができるイベント
        です。ほぼ隔週で開催されています。内容は参加者にあわせてその場で
        決めるので、前の回に参加していないとついていけない、ということは
        ありません。

興味があるイベントがあればぜひご参加ください!

## 改良

  * [実験的] GRN_II_OVERLAP_TOKEN_SKIP_ENABLE と
    GRN_NGRAM_TOKENIZER_REMOVE_BLANK_DISABLE 環境変数をN-gramトークナ
    イザーのパフォーマンス向上のために追加しました。[GitHub#533][村上
    さんがパッチ提供]

  * [table_create] 存在しないデフォルトトークナイザーやノーマライザー、
    トークンフィルターを指定したときに無視しないようにしました。過去の
    バージョンでは --default_tokenizer や --normalizer 、
    --token_filters の指定が誤っていても無視するだけで、何もエラー表示
    をしていませんでした。 これは問題の発覚を遅らせてしまっていました。

  * [select] output_columns v1: snippet_html(...) などの式を
    output_columns に指定できるようにしました。

  * [select] ラベルつきドリルダウンの制限をなくしました。これまでは、
    ラベルつきドリルダウンの最大数は10に制限されていました。

  * [number_classify] number プラグインを追加しました。number_classify
    を使うと同じような値を1つにまとめることができます。価格帯ごとにま
    とめたいときに有用です。

  * time プラグインを追加しました。time_classify_second,
    time_classify_minute, time_classify_hour, time_classify_day,
    time_classify_week, time_classify_month, time_classify_year 関数を
    使うと同じようなタイムスタンプごとにまとめることができます。

  * [select] 動的カラムを output_columns, drilldown や sortby に指定で
    きるようになりました。 [GitHub#539,#541,#542,#544,#545][村上さんが
    パッチ提供]:

    select \
      --columns[LABEL].stage filtered \
      --columns[LABEL].type ShortText \
      --columns[LABEL].flags COLUMN_SCALAR \
      --columns[LABEL].value 'script syntax expression' \
      ...

  * [実験的][select] 範囲検索で十分にフィルタされている場合のパフォー
    マンスを改善しました。 有効にするには、
    GRN_TABLE_SELECT_ENOUGH_FILTERED_RATIO 環境変数に値を設定します。

  * [select] フィルタした結果テーブルに対してインデックスを使って検索
    できるようになりました。

  * データベースを変更後に閉じられていない場合を検出できるようになりま
    した。Groongaが意図せずクラッシュしたときなど、データベースの整合
    性が失なわれてしまったかどうかを確認するのに便利です。

  * [grndb] データベースが正常に閉じられなかった場合を検出できるように
    なりました。

  * --dirlldown_filter を追加しました。

  * ラベルつきドリルダウンで filter をサポートしました。

  * インデックスを使わない場合の [between] のパフォーマンスを改善しま
    した。between()の最適化で以前のバージョンに比べ、100倍範囲検索が高
    速になる場合があります。

  * [record_number] ウィンドウ関数をサポートしました。

  * [実験的][select] --slices をサポートしました。

  * [select] --sortby と --drilldown_sortby は非推奨になりました。
    --sort_keys と -drilldown_sort_keys を使うようにしてください。

  * [select] --drilldown[...] は非推奨になりました。 --drilldowns[...]
    を使うようにしてください。

  * [コマンドバージョン 3] を追加しました。コマンドバージョン3ではオブ
    ジェクトリテラル表記になります。

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

## 修正

  * [select] output_columns v2: * が正しく展開されない不具合を修正しま
    した。

  * タイムスタンプの値から1usecの情報が失なわれてしまう不具合を修正し
    ました。

  * mrubyのプラグインが複数のスレッドから初期化されるとクラッシュする
    不具合を修正しました。

  * ポスティングリストが非常に長くなると、静的インデックス構築時にクラッ
    シュする不具合を修正しました。これはデータベースのサイズが非常に大
    きいと発生する可能性があります。

## 感謝

  * 村上さん
--
Kentaro Hayashi <hayas****@clear*****>
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: 無し
型:         application/pgp-signature
サイズ:     819 バイト
説明:       無し
下載 



groonga-dev メーリングリストの案内
Back to archive index