Closed s-yata closed 9 years ago
table_create Table TABLE_NO_KEY
column_create Table Col0 COLUMN_SCALAR Bool
column_create Table Col1 COLUMN_SCALAR Int16
column_create Table Col2 COLUMN_SCALAR Float
column_create Table Col3 COLUMN_SCALAR ShortText
Col0
true
or false
Col1
[0, 32768)
Col2
[0, 1)
Col3
["0", "2147483648")
100 万行を 10 行ずつ入力します. 1 行ずつでない理由は,コマンド単位で並列化をおこなうためです. 以下に例を示します.
load --table Table --columns 'Col0,Col1,Col2,Col3' --values '[[false,5711,0.6645600532184904,"939984059"],[true,26840,0.06563701921747622,"336122540"],[false,27545,0.5152126285020654,"1747278511"],[false,29140,0.31805817433032985,"1006933274"],[false,7451,0.6790846759202163,"469339106"],[true,1604,0.5706732760710226,"1852186258"],[false,4677,0.7525730355516119,"443632888"],[false,23003,0.5238203060500009,"60780408"],[true,22507,0.9752416188605784,"170625356"],[true,28219,0.692024587353112,"647515026"]]'
残念ながら,分散や並列化による高速化は実現できませんでした. むしろ,オーバーヘッドが大きく,大幅に遅くなってしまいました. 索引なしの単純なテーブルでは,効果は期待できないようです.
全文検索用の転置索引があれば,コマンドの実行にかかる時間が長くなるため,並列化による効果が期待できます.
まずは,データを分散させず,単一の DB に格納(load
)するのに要した時間です.
1 DB | |
---|---|
1 core | 2.9s |
次に,複数 DB に分散させた結果です. パースして JSON 化しなおす手間が追加され,さらにコマンドの実行回数が増えるため,かなり遅くなっています.
1 DB | 2 DBs | 3 DBs | 4 DBs | |
---|---|---|---|---|
1 core | 8.9s | 10.3s | 11.9s | 13.4s |
JSON 化とコマンドの実行に goroutine を使うようにしました.
また, runtime.GOMAXPROCS(NCPU)
により並列度を変更しました.
1 DB | 2 DBs | 3 DBs | 4 DBs | |
---|---|---|---|---|
1 core | 9.3s | 11.8s | 14.6s | 16.8s |
2 cores | 14.1s | 19.2s | 19.6s | 21.4s |
3 cores | 14.3s | 19.8s | 21.3s | 22.6s |
4 cores | 14.2s | 20.3s | 22.3s | 23.0s |
全文検索索引があるとどうかを確かめるため,新しい設定を用意しました.
全文検索索引を追加しました.
table_create Table TABLE_NO_KEY
column_create Table Col0 COLUMN_SCALAR Bool
column_create Table Col1 COLUMN_SCALAR Int16
column_create Table Col2 COLUMN_SCALAR Float
column_create Table Col3 COLUMN_SCALAR Text
table_create Idx3 TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram
column_create Idx3 Idx COLUMN_INDEX|WITH_POSITION Table Col3
Col0
, Col1
, Col2
はそのままで, Col3
には日本語版 Wikipedia の本文から段落を切り出して入力しました.
平均長は 100 bytes 程度です.
先のテストとほぼ同様ですが,実行時間の関係から合計 10 万行に減らしました. 入力は 10 行ずつなので,コマンドは 1 万件となります.
並列化により高速化できることもありそうな…という微妙な結果になりました. 現状では,まだ分散なしの方が良さそうです.
まずは,データを分散させず,単一の DB に格納(load)するのに要した時間です. 転置索引を更新するため,先の実験と比べて桁ひとつ長い時間がかかっています.
1 DB | |
---|---|
1 core | 5.5s |
元のコマンドが重いため,分散によるオーバーヘッドの割合が小さくなっています.
1 DB | 2 DBs | 3 DBs | 4 DBs | |
---|---|---|---|---|
1 core | 6.6s | 7.6s | 7.7s | 8.1s |
並列化により高速化されるケースもあるようです. しかし,わざわざ並列化をおこなうほどの効果は得られませんでした.
1 DB | 2 DBs | 3 DBs | 4 DBs | |
---|---|---|---|---|
1 core | 7.1s | 7.7s | 8.5s | 8.6s |
2 cores | 7.8s | 6.8s | 7.3s | 7.5s |
3 cores | 7.7s | 7.2s | 6.9s | 7.0s |
4 cores | 7.7s | 7.3s | 7.3s | 7.2s |
シングルスレッドと比べれば遅くなっていますが,全文検索用の転置索引があれば,並列化により遅くなることはないようです.
しかし,今回は平均長 100 bytes の Text
を 10 行ずつ入れるという条件なので, Text
が短くなったり一度に入力する行数が少なくなったりすれば,残念な結果になるかもしれません.
上のテストに追加で,一度に入力する行数を変更するとどうなるかを調べてみました. やはり,行数を減らすと効率が悪いようです(※). 一方で,コマンドが重ければ,実行時間を短縮できることがわかりました.
※ コマンド単位で並列化するので,そもそも並列化ができなくなってしまいます.
#rows/cmd | load |
1 DB, 1 core | 4 DBs, 4 cores |
---|---|---|---|
1 | 7.0s | 11.2s | 15.7s |
2 | 7.1s | 9.0s | 13.5s |
4 | 6.6s | 8.0s | 10.3s |
8 | 6.0s | 8.1s | 7.9s |
16 | 5.7s | 7.5s | 6.2s |
32 | 5.5s | 7.0s | 5.0s |
64 | 5.5s | 6.5s | 4.3s |
128 | 5.5s | 6.5s | 3.9s |
軽いコマンドではオーバーヘッドが厳しいこと,重いコマンドでは時間が短縮できることがわかっています. いずれにせよ,オーバーヘッドを抑えることが高速化につながるはずです.
別マシンで同様のテストをしてみます.
Xeon E5-2643 3.3GHz (up to 3.5GHz) x2 な環境で試してみました. 並列度を高めれば並列化の効果も上がるかと思いきや,オーバーヘッドも増えてしまったようで,期待通りの結果にはなりませんでした. どちらかといえば悪化しています.
分散・並列化なしでは以下の結果になりました.
1 DB | |
---|---|
1 core | 6.0s |
分散・並列化ありでは以下の結果になりました.
1 DB | 2 DBs | 3 DBs | 4 DBs | 5 DBs | 6 DBs | 7 DBs | 8 DBs | |
---|---|---|---|---|---|---|---|---|
1 core | 13.3s | 16.6s | 20.2s | 22.9s | 25.1s | 27.3s | 27.7s | 29.8s |
2 cores | 15.6s | 35.5s | 49.9s | 49.7s | 56.6s | 52.7s | 49.9s | 52.7s |
3 cores | 16.2s | 38.5s | 36.1s | 43.5s | 47.4s | 48.1s | 54.1s | 53.2s |
4 cores | 16.3s | 38.4s | 38.5s | 38.0s | 43.6s | 45.7s | 47.9s | 47.1s |
5 cores | 16.8s | 38.8s | 39.4s | 39.0s | 39.1s | 40.8s | 42.6s | 45.3s |
6 cores | 16.5s | 38.2s | 39.0s | 38.8s | 39.7s | 40.5s | 40.8s | 41.5s |
7 cores | 16.4s | 37.8s | 29.2s | 38.9s | 40.1s | 42.1s | 42.1s | 41.2s |
8 cores | 16.5s | 37.4s | 38.3s | 40.8s | 41.5s | 42.0s | 43.6s | 43.8s |
分散・並列化なしでは以下の結果になりました.
1 DB | |
---|---|
1 core | 8.6s |
分散・並列化ありでは以下の結果になりました.
1 DB | 2 DBs | 3 DBs | 4 DBs | 5 DBs | 6 DBs | 7 DBs | 8 DBs | |
---|---|---|---|---|---|---|---|---|
1 core | 9.7s | 10.1s | 10.9s | 11.3s | 11.9s | 12.9s | 12.2s | 12.5s |
2 cores | 10.3s | 14.6s | 14.1s | 13.6s | 14.8s | 14.5s | 12.8s | 13.3s |
3 cores | 10.3s | 17.7s | 16.7s | 16.0s | 13.9s | 14.7s | 15.5s | 16.5s |
4 cores | 10.3s | 17.9s | 17.6s | 16.0s | 16.4s | 15.8s | 15.3s | 15.0s |
5 cores | 10.1s | 18.9s | 17.8s | 17.2s | 16.0s | 16.1s | 15.3s | 14.7s |
6 cores | 10.1s | 17.7s | 16.9s | 16.6s | 16.3s | 15.8s | 15.5s | 15.7s |
7 cores | 10.3s | 17.8s | 17.6s | 16.7s | 16.8s | 16.2s | 16.0s | 16.0s |
8 cores | 10.4s | 17.8s | 17.3s | 17.1s | 16.7s | 16.3s | 16.1s | 16.0s |
最後に,一度に入力する行数を変更した結果です. cores は 8 に固定しました.
1 DB | 2 DBs | 4 DBs | 8 DBs | |
---|---|---|---|---|
1 row | 18.1s | 18.4s | 18.8s | 19.1s |
2 rows | 13.9s | 32.0s | 31.3s | 30.1s |
4 rows | 11.6s | 24.0s | 23.8s | 22.3s |
8 rows | 10.5s | 19.8s | 18.5s | 17.4s |
16 rows | 9.8s | 15.5s | 13.8s | 13.1s |
32 rows | 9.5s | 12.6s | 10.2s | 10.1s |
64 rows | 9.3s | 10.0s | 7.5s | 7.2s |
128 rows | 9.0s | 9.0s | 6.0s | 5.8s |
概要
与えられたデータを複数の Groonga DB に分けて
load
するとき,並列化によって高速化を実現できるか評価します.データの分配については,
_key
があるときはハッシュ値,_key
がないときは擬似乱数を使って格納する DB を選ぶようにします.入力には Groonga コマンドと同様の書式を使います. そのため,分散させるときは,与えられたデータ(JSON)をパースして,分散させた後に JSON 化しなおすことになります. パースは並列化できませんが, JSON 化については並列化することができます.