Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Skip Listによる
高速な順位・平
均等の計算方法
appengine ja night #8 koher


2         0         1    0
J    u    n    e    0    4
アンケート
 突然ですが質問です
Q1. O(N)という表記の意味を知っていますか?
1.  余裕で知ってる!
2.  見たことある。
3.  何それ?

Q2. log Nってわかりますか?(底は何でもいい)
1.  どれくらいの値かイメージできる。
2.  logは知っているけどイメージはできない。
3.  昔やったけど忘れた/logって丸太ですか?



2         0         1    0
J    u    n    e    0    4
                              2
appengine ja night #8 koher
koherって誰?
 普段は京都GTUG主催のappengine ja night in kansaiに参加
•  koher(id:koherent、@koher)
    •  読み方は「コヒー」。koherentを省略。
•  普段は京都GTUG(※)で@bufferingsさんが中心となって開催さ
   れているappengine ja night in kansaiに参加している。
•  App Engineは昨冬(2009年12月)から触り始める。
•  Qonceptという会社でAR(拡張現実)関連の仕事に従事。
    •  現在発売中の「GQ JAPAN 7月号」に収録されているバーチャル試着
       のARプログラムを開発したり。よかったら買ってね!
                                                        WEBでバーチャルの時計を表示
※GTUG
Google Technology User Groupの略で、世
界中に支部を持つGoogleの技術のユーザ団体。
京都GTUGのサイトは http://bit.ly/d1nMLN


2          0          1    0
J    u     n    e     0    4
                                    (引用: http://bit.ly/arupc6 のPDFより)   3
appengine ja night #8 koher
今回発表することになった経緯
 ajn7→Skip Listでランキングを実装→声をかけていただく
•  ajn7でランキング問題が取り上げられた。
    •  「#appengine でランキングを実装するには?androidアプリのゲーム
       で得点を元にユーザが何位だったのかを算出したい。昨日これを聞かれ
       て、あーなかなか思ったよりも難しいなーと考え中。みんなならどうす
       る?(ユーザ数は仮に10万だとして考える)」by @bluerabbit777jpさん
         (引用: App Engineでランキングを実装する問題 http://bit.ly/dmgEiI より)
•  Indexable Skip Listを使えば解決できそうだと考え実装。
    •  「Google App Engineでランキングやページングを実現する 」
          http://bit.ly/auyI3S
•  PIAX開発者の@kibayosさんの発言から、App Engineで集約関数
   が実現できるのではないかという話に。
•  @kazunori_279さんに発表の機会をいただく。

2          0           1    0
J    u     n     e     0    4
                                                                 4
appengine ja night #8 koher
発表のテーマ
 Skip Listによる高速な順位・平均等の計算方法
•  Indexable Skip Listというデータ構造を使えば、順位計算や指定範
   囲に対する集約関数の実行が高速に実現できる。
    •  RANK、COUNT、SUM、AVG、MIN、MAX、MEDIANを実現!
        •  ただし、万能ではない…。
•  App Engine上にどうやって実装するか。問題点は何か。




2         0         1    0
J    u    n    e    0    4
                                               5
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47




2         0         1    0
J    u    n    e    0    4
                                                   6
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       O(log N)の二分探索で
                              11を検索    ソート済配列から値を
2         0         1    0             検索する例
J    u    n    e    0    4
                                                   7
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       初めに検索対象の11を
                              11を検索    真ん中の19と比較する
2         0         1    0
J    u    n    e    0    4
                                                   8
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       11は19より小さいの
                              11を検索    で19の右側は対象外
2         0         1    0             →半分に絞り込める
J    u    n    e    0    4
                                                   9
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       次は11を残りの真ん中
                              11を検索    の値である7と比較
2         0         1    0
J    u    n    e    0    4
                                                   10
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       11は7より大きいので
                              11を検索    7の左側は対象外
2         0         1    0             →さらに対象を半分に
J    u    n    e    0    4
                                                   11
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       値が見つかるまで同じ
                              11を検索    処理を繰り返す
2         0         1    0
J    u    n    e    0    4
                                                   12
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       1回の処理で対象を半
                              11を検索    分に絞り込めるので、
2         0         1    0             大量のデータからも高
J    u    n    e    0    4             速に検索できる
                                                   13
appengine ja night #8 koher
O(log N)とは
 1000個→10回、100万個→20回、10憶個→30回の処理
•  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。
     •  O(N)のように表され、「Nのオーダー」と読む。
         •  厳密にはO、Ω、Θなどの表記が区別される。
     •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき
        ることを表す(Nはデータの個数など)。
•  O(log N)のときは、N=1000→10回、100万→20回、10憶→30
   回程度で処理が終わると覚えておくとイメージしやすい。

 2    3    5    7   11 13 17 19 23 29 31 37 41 43 47


                                       11を発見!
                              11を検索
2         0         1    0
J    u    n    e    0    4
                                                   14
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17   19   T




2         0            1   0
J    u    n    e       0   4
                                                       15
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)
              5
 H                             17       13           11

              3           19        7
                                             データはどのような位
                                             置に格納されていても、
2         0           1    0
                               T             ポインタでつながって
J    u    n       e   0    4                 いればよい
                                                     16
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17    19     T


                                             Linked Listは前から順
                                    4番目を     に要素にアクセスしな
                                     参照      ければならない
2         0            1   0
J    u    n    e       0   4
                                                          17
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17   19   T


                                             先頭ノードから順々に
                                    4番目を     たどっていく
                                     参照      →O(N)と遅い
2         0            1   0
J    u    n    e       0   4
                                                       18
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17    19   T


                                             0番目
                                    4番目を
                                     参照
2         0            1   0
J    u    n    e       0   4
                                                        19
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17    19   T


                                             1番目
                                    4番目を
                                     参照
2         0            1   0
J    u    n    e       0   4
                                                        20
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17    19   T


                                             2番目
                                    4番目を
                                     参照
2         0            1   0
J    u    n    e       0   4
                                                        21
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17    19   T


                                             3番目
                                    4番目を
                                     参照
2         0            1   0
J    u    n    e       0   4
                                                        22
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17   19    T


                                             4番目
                                    4番目を     →目標の値に到着
                                     参照
2         0            1   0
J    u    n    e       0   4
                                                        23
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17   19   T


                                             挿入・削除時に配列の
                                     先頭に     ように後ろの要素をず
                                    2を挿入     らす必要がない
2         0            1   0
J    u    n    e       0   4
                                                       24
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17   19   T

     2
                                             挿入するノードを作成
                                     先頭に
                                    2を挿入
2         0            1   0
J    u    n    e       0   4
                                                       25
appengine ja night #8 koher
Linked List
 Skip Listのデータ構造のベースはLinked List
•  Skip Listのデータ構造はLinked Listをベースにしている。
•  Linked Listは配列のように複数の値を格納するためのデータ構造。
     •  各ノードは値と次ノードへのポインタを持つ(下図)。
•  先頭ノードから順次アクセスするため参照は遅い→O(N)
•  先頭への要素の挿入・削除は速い→O(1)
•  要素がソート済であっても値の検索は遅い→O(N)


 H       3         5           7   11   13   17   19   T

     2
                                             ポインタをつなぎ替え
                                     先頭に     →後ろの要素をずらす
                                    2を挿入     必要はない
2         0            1   0
J    u    n    e       0   4
                                                       26
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                                         T
 H                 3           5               11                        T
 H       2         3           5      7        11         13   17        T


                                   William Pugh, Skip Lists: A Probabilistic
2         0            1   0       Alternative to Balanced Trees, (1990)
J    u    n    e       0   4       http://bit.ly/dxfh4D
                                                                         27
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T

                                            最上位階層の先頭ノー
2         0            1   0       13を検索    ドから検索開始
J    u    n    e       0   4
                                                      28
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T

                                            次ノードがないので下
2         0            1   0       13を検索    の階層に下りる
J    u    n    e       0   4                (次ノードが13より大
                                             きい場合も同様) 29
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T

                                            次ノードが13より小さ
2         0            1   0       13を検索    いので次ノードへ進む
J    u    n    e       0   4
                                                      30
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T

                                            次ノードがないので下
2         0            1   0       13を検索    の階層に下りる
J    u    n    e       0   4
                                                      31
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T

                                            次ノードが13より小さ
2         0            1   0       13を検索    いので次ノードへ進む
J    u    n    e       0   4
                                                      32
appengine ja night #8 koher
Skip List ‒ 基本データ構造と検索
 Skip Listを用いれば高速な(O(log N)の)検索が可能
•  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。
     •  最下層だけみるとただのLinked List。
     •  上位階層になるほど要素が間引かれる。
•  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた
   どることで高速な(O(log N)の)検索を実現。


 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T

                                            13を発見!
2         0            1   0       13を検索
J    u    n    e       0   4
                                                      33
appengine ja night #8 koher
Skip List ‒ 挿入と削除 (1)
 挿入・削除の際に要素の分布を維持することは困難
•  どのように上位階層の要素を間引くべきか。
     •  上の階層に上るごとに、要素を半分ずつ間引いていけば効率的(下図)。
         •  下から2階層目では偶数番目、3階層目では4の倍数番目、4階層目
            では8の倍数番目以外の要素は間引かれる。
         •  この場合検索は効率的だが、要素の挿入・削除時にこのような要素
            の分布を維持することは困難。

 H                                 7                  T
 H                 3               7        13        T
 H       2         3           5   7   11   13   17   T



2         0            1   0
J    u    n    e       0   4
                                                      34
appengine ja night #8 koher
Skip List ‒ 挿入と削除 (2)
 確率的に要素の分布を維持することで高速な挿入・削除を実現
•  挿入時に適切な確率に基づいてノードのレベル(階層数)を決定す
   ることで、理想的な分布と同程度の検索効率を実現できる。
     •  任意のp>1について、レベルiのノードを(1/p)^iの確率で生成。
         •  例えば、p=1/2のとき、50%の確率でレベル0、25%の確率でレベ
            ル1、12.5%の確率でレベル2、…のノードが生成される。
•  ノードのレベルはノード作成時に決定し、その後は変化しない。

 H                             5                      T
 H                 3           5       11             T
 H       2         3           5   7   11   13   17   T



2         0            1   0
J    u    n    e       0   4
                                                      35
appengine ja night #8 koher
Indexable Skip List ‒ 要素番号の計算
 要素番号の計算のため次ノードへのポインタに距離を付加
•  次ノードへのポインタに距離情報を付加したIndexable Skip Listを
   用いれば、O(log N)で要素番号や順位を計算できる(下図)。
     •  検索時には通ったルートの距離の和によって要素番号を計算。
     •  挿入・削除の際にはポインタの距離も更新する。
     •  最上位層の距離をすべて足せばリストの全要素数も計算できる。

              3                                         5
 H                                 5                                          T
          2                1               2                     3
 H                 3               5               11                         T
     1        1            1           1       1        1        1        1
 H       2         3               5       7       11       13       17       T



2         0            1       0
J    u    n    e       0       4
                                                                              36
appengine ja night #8 koher
Indexable Skip List ‒ 要素番号による検索
 要素番号によって値を検索することもできる
•  ノードを検索するときに、キー値での検索同様に要素番号によって
   O(log N)で検索することもできる。
     •  キー値との比較を行うでのはなく、指定された要素番号と現在のノー
        ドの要素番号を比較しながら検索を行う。



              3                                         5
 H                                 5                                          T
          2                1               2                     3
 H                 3               5               11                         T
     1        1            1           1       1        1        1        1
 H       2         3               5       7       11       13       17       T



2         0            1       0
J    u    n    e       0       4
                                                                              37
appengine ja night #8 koher
Indexable Skip List ‒ 挿入・削除
 挿入・削除時は全階層分の距離の更新が必要となる
•  Indexable Skip Listにノードを挿入・削除する場合、対象ノードの
   レベルに関わらず全階層分のデータを更新する必要がある。
     •  最上位ノードまで距離情報を更新しなければならないため。
     •  それでも挿入・削除の計算量はO(log N)。
•  処理が途中で打ち切られた場合、データに不整合が生じる。

              3                                         5
 H                                 5                                          T
          2                1               2                     3
 H                 3               5               11                         T
     1        1            1           1       1        1        1        1
 H       2         3               5       7       11       13       17       T



2         0            1       0
J    u    n    e       0       4
                                                                              38
appengine ja night #8 koher
Indexable Skip List ‒ 総和の計算
 ポインタに値の区間の総和を付加すれば、総和を計算できる
•  ポインタにその区間のキー値の総和を持たせれば、総和を計算する
   こともできる。
•  総和を要素数(ノードの順位)で割れば平均も計算できる。
     •  要素数は順位計算の原理で計算。
         •  この場合、ポインタに和と距離の両方の情報を持たせる。

              10                                          48
 H                                 5                                              T
          5                5               18                       30
 H                 3               5                 11                           T
     2        3            5           7        11        13        17        0
 H       2         3               5       7         11        13        17       T



2         0            1       0
J    u    n    e       0       4
                                                                                  39
appengine ja night #8 koher
Indexable Skip List ‒ 範囲に対する集約
 要素番号や総和の差をとることで、範囲内の集約ができる
•  キー値や要素番号による任意の範囲を指定して、その範囲内の要素
   数や総和・平均を計算することもできる。
     •  例えば3<KEY<=13の範囲の要素数を求めるには、13のノードの要素
        番号から3のノードの要素番号を引く。
     •  指定した範囲に対して、SQLのCOUNT、SUM、AVGのような計算が
        できるようになる。
              3                                         5
 H                                 5                                          T
          2                1               2                     3
 H                 3               5               11                         T
     1        1            1           1       1        1        1        1
 H       2         3               5       7       11       13       17       T



2         0            1       0
J    u    n    e       0       4
                                                                              40
appengine ja night #8 koher
Indexable Skip List ‒ 最大・最小・中央値
 最初のノードが最小、最後が最大、真ん中が中央値
•  任意の範囲に対して(もちろんリスト全体に対しても)、キー値の
   最大・最小・中央値を簡単に計算できる。
     •  最初のノードの値が最小値(昇順の場合)→O(1)
     •  最後のノードの値が最大値(降順の場合)→O(1)
     •  真ん中(要素数/2番目)のノードの値が中央値→O(log N)

              3                                         5
 H                                 5                                          T
          2                1               2                     3
 H                 3               5               11                         T
     1        1            1           1       1        1        1        1
 H       2         3               5       7       11       13       17       T



2         0            1       0
J    u    n    e       0       4
                                                                              41
appengine ja night #8 koher
Indexable Skip List ‒ キー値以外の集約 (1)
 キーに紐付けられた値の総和を計算することもできる
•  ポインタにキー値そのものではなくキーに紐付けられた値の和を持
   たせることで、その値の総和をO(log N)で計算することができる。




                123                                             116
 H                                     5                                                 T
          100                 23                 50                        66
 H                    3                5                   11                            T
     43         57            23            19        31        37         29        0
 H        2           3                5         7         11         13        17       T
          43          57               23        19        31         37        29

2          0              1        0
J    u     n     e        0        4
                                                                                         42
appengine ja night #8 koher
Indexable Skip List ‒ キー値以外の集約 (2)
 キー値以外の最大・最小も求められるが少々困難
•  ポインタに、区間内の最大・最小の情報を付加すれば、キーに紐付
   けられた値の最大・最小をO(log N)で求めることもできる。
     •  範囲検索が難しい。
         •  最下層から上位階層に登って再び最下層に下りる、山型のサーチパ
            スならO(log N)で計算可?他にもっと良い方法があるかも。
     •  削除時に、削除されるノードを除いた最大・最小の再計算が必要。
               57                                             37
 H                                   5                                                  T
          57                23                 31                       37
 H                  3                5                   11                             T
     43        57           23            19        31        37        29        N/A
 H        2         3                5         7         11        13        17         T
          43        57               23        19        31        37        29

2         0             1        0
J    u    n     e       0        4
                                                                                        43
appengine ja night #8 koher
App Engine上での実装 ‒ Entityとノード (1)
 方法1: 1ノード、1エンティティで表す
•  1個のノードを1個のエンティティで表し、実装する。
     •  次ノードへのポインタはリストプロパティに格納する。
     •  4月25日のブログエントリー http://bit.ly/auyI3S の実装はこの方法。
     •  ノードを1個ずつたどることになるので、getが遅いDatastoreではパ
        フォーマンスが悪い。
         •  N=10000で要素番号の計算に平均2.8秒。

 H                             5                          T
 H                 3           5       11                 T
 H       2         3           5   7   11   13    17      T
                                                 Entity

2         0            1   0
J    u    n    e       0   4
                                                          44
appengine ja night #8 koher
App Engine上での実装 ‒ Entityとノード (2)
 方法2: 複数のノードを1個のエンティティで表す
•  ノードを階層ごとに分解し、同階層で複数のノードをまとめて1個
   のエンティティに格納する。
     •  例えばp=1000に設定すると、3階層で10憶ノード程度を格納できる。
         •  参照系の処理を数百ミリ秒まで縮められるか?
     •  エンティティの内部は二分探索で検索可。


 H                             5                          T
 H                             5                  17      T
 H       2         3           5   7   11   13    17      T
                                                 Entity

2         0            1   0
J    u    n    e       0   4
                                                          45
appengine ja night #8 koher
App Engine上での実装 ‒ 考慮すべき点
 不整合を防ぐためにGlobal Transactionがほしい
•  Indexableだと処理が途中で打ち切られた場合に不整合が発生する。
    →  定期的に不整合を検出して修正する。
    →  Global Transactionを用いる。
•  同時実行制御の必要あり。
•  開始ノードにアクセスが集中するとスケールしないかも?
    •  「私の理解だと、最近できたConsistencyモードを弱く設定しないと常に
       マスタノードを読みにいく感じですね。」
         by @ashigeruさん http://bit.ly/aBdxUn
    •  Log Counterのような方法も使えるかも?
       「LogCounterはどうでしょう?・実装編 」 @kazunori_279さん
           http://bit.ly/cxlNUv
    •  Skip Listの発展形であるSkip GraphならスケールするけどIndexableにで
       きる?App Engine上で集約Skip Graphは可能?
•  Indexableだと上位階層のエンティティの更新が競合しやすい。

2           0           1     0
J    u      n     e     0     4
                                                     46
appengine ja night #8 koher
MVCC ‒ Global Transactionの実現
 MVCCでGlobal Transactionを実現できそう
•  MVCCはMulti Version Concurrency Control(多版型同時実行
   制御)の略で、同時実行制御の方式。
    •  OracleやPostgreSQLはMVCCでトランザクションを実現している。
    •  更新時にデータを上書きするのではなく、複数のバージョンのデータを
       保持することで対応する。
    •  読み込みと書き込みが互いにロックしないことが特徴。
•  Slim3のGlobal Transactionを用いることもできるが、ライブラリ
   に依存関係が生まれてしまう。
•  MVCCレイヤーだけ切り出して、DatastoreServiceインタフェー
   スを実装しようかと考え中。
    •  きちんと検証できてないので、本当に実装できるかビミョー…。


2         0         1    0
J    u    n    e    0    4
                                                    47
appengine ja night #8 koher
MVCC ‒ 追記型のMVCC
 追記型のMVCCではレコードを更新するのではなく追記する
•  追記型のMVCCはデータ更新時にレコードを追記する。
    •  トランザクションIDの有効区間(下表のStart、End)を持ち、Start
       (含む)からEnd(含まない)の区間にトランザクションIDが含まれて
       いる場合だけそのレコードを有効とする。
    •  追記型のMVCCはPostgreSQLで採用されている。


         Key             Start   End        Data
         A001            100     105         A
         A001            105     999         B



                                       トランザクションIDが
2           0       1    0             100∼104は1行目、
J    u      n   e   0    4             105∼は2行目が有効
                                                   48
appengine ja night #8 koher
MVCC ‒ 追記型のMVCC
 追記型のMVCCではレコードを更新するのではなく追記する
•  追記型のMVCCはデータ更新時にレコードを追記する。
    •  トランザクションIDの有効区間(下表のStart、End)を持ち、Start
       (含む)からEnd(含まない)の区間にトランザクションIDが含まれて
       いる場合だけそのレコードを有効とする。
    •  追記型のMVCCはPostgreSQLで採用されている。


         Key             Start       End        Data
         A001            100         105         A
         A001            105         108         B
         A001            108         999         C


                                           トランザクションID
2           0       1    0
                                 Update    108でDataをCに更新
J    u      n   e   0    4
                                                       49
appengine ja night #8 koher
MVCC ‒ 追記型のMVCC
 追記型のMVCCではレコードを更新するのではなく追記する
•  追記型のMVCCはデータ更新時にレコードを追記する。
    •  トランザクションIDの有効区間(下表のStart、End)を持ち、Start
       (含む)からEnd(含まない)の区間にトランザクションIDが含まれて
       いる場合だけそのレコードを有効とする。
    •  追記型のMVCCはPostgreSQLで採用されている。


         Key             Start       End        Data
         A001            100         105         A
         A001            105         108         B
         A001            108         110         C


                                           トランザクションID
2           0       1    0
                                 Delete    110で削除
J    u      n   e   0    4                 →110以降では有効レ
                                                     50
appengine ja night #8 koher                 コードなし
MVCC ‒ App Engine上での実装の工夫
 Queryを使うと遅いので、Keyで検索できるようにする
•  有効なエンティティをQueryで検索すると遅い。
•  Queryではなく、Keyでエンティティを検索できるようにする。
      •  Keyで最新のEntityを検索し、Transaction IDが当てはまらない場合だ
         け、Linked Listの要領で過去のエンティティをたどるようにする。
      •  更新の際には、現在のエンティティを複製し、元のエンティティを上書
         きする際に複製されたエンティティへのポインタを持たせる。

    name =                              name =
    _A0001                              100_105_1_A0001

    start = 100                         start = 100
    end = 105                           end = 105
    value = B                           value = A

                                                      Entity
2             0       1   0
J      u      n   e   0   4
                                                          51
appengine ja night #8 koher
MVCC ‒ App Engine上での実装の工夫
 Queryを使うと遅いので、Keyで検索できるようにする
•  有効なエンティティをQueryで検索すると遅い。
•  Queryではなく、Keyでエンティティを検索できるようにする。
      •  Keyで最新のEntityを検索し、Transaction IDが当てはまらない場合だ
         け、Linked Listの要領で過去のエンティティをたどるようにする。
      •  更新の際には、現在のエンティティを複製し、元のエンティティを上書
         きする際に複製されたエンティティへのポインタを持たせる。

    name =                    name =                 name =
    _A0001                    105_108_1_A0001        100_105_1_A0001

    start = 108               start = 105            start = 100
    end = 999                 end = 108              end = 105
    value = C                 value = B              value = A

                                                                   Entity
2             0       1   0
J      u      n   e   0   4
                                            Update
                                                                       52
appengine ja night #8 koher
ライブラリの仕様
 指定範囲に対して集約関数を実行可能なJavaのライブラリ
•  指定範囲に対してCOUNT、MIN、MAX、SUM、AVG、MEDIAN
   相当の機能をJavaで実装。もちろんイテレーションも可能。
•  Comparatorでキーの大小関係を自由に指定可能に。
    •  Datastoreで実現できない複雑なルールに基づく並び順も実現可。
•  LongやDouble以外の値に対しても加算の演算ルールを実装すれば、
   任意の型に対して総和や平均を計算可能に。
    •  (例)方向を単位ベクトルに変換して方向の平均を計算する。
•  双方向にポインタを持たせて逆順のリストを取得可能に。
•  部分リストを取得可能に(指定範囲の集約は部分リストを利用)。
    •  (例)部分リストから要素を取り出せばページングを実現できる。
•  キー値だけでなく、キーに紐づいた値の集約も可能に。

2         0         1    0        気長にお待ち
J    u    n    e    0    4
                                   下さい…
                                            53
appengine ja night #8 koher
まとめ
 Indexable Skip Listによって集約関数を実現する方法を紹介
•  Indexable Skip Listを使えば、App Engine上で集約関数のような
   計算が可能になる。
    •  ただし、予め決定したソート順のある範囲に対してのみ実効できる。
    •  ソート順はComparatorで自由に指定できる。
    •  要素番号や順位、COUNTがO(log N)で計算でき、ページングにも利用
       できる。
    •  キーに対してはSUM、AVG、MIN、MAX、MEDIANが計算できる。
    •  紐づいた値にもSUM、AVG、MIN、MAXが計算できる。
•  ライブラリ化するんで気長にお待ち下さいm(_ _)m




2         0         1    0
J    u    n    e    0    4
                                              54
appengine ja night #8 koher
御清聴ありがと
うございました。
appengine ja night #8 koher


2         0         1    0
J    u    n    e    0    4

More Related Content

Skiplists20100604

  • 2. アンケート 突然ですが質問です Q1. O(N)という表記の意味を知っていますか? 1.  余裕で知ってる! 2.  見たことある。 3.  何それ? Q2. log Nってわかりますか?(底は何でもいい) 1.  どれくらいの値かイメージできる。 2.  logは知っているけどイメージはできない。 3.  昔やったけど忘れた/logって丸太ですか? 2 0 1 0 J u n e 0 4 2 appengine ja night #8 koher
  • 3. koherって誰? 普段は京都GTUG主催のappengine ja night in kansaiに参加 •  koher(id:koherent、@koher) •  読み方は「コヒー」。koherentを省略。 •  普段は京都GTUG(※)で@bufferingsさんが中心となって開催さ れているappengine ja night in kansaiに参加している。 •  App Engineは昨冬(2009年12月)から触り始める。 •  Qonceptという会社でAR(拡張現実)関連の仕事に従事。 •  現在発売中の「GQ JAPAN 7月号」に収録されているバーチャル試着 のARプログラムを開発したり。よかったら買ってね! WEBでバーチャルの時計を表示 ※GTUG Google Technology User Groupの略で、世 界中に支部を持つGoogleの技術のユーザ団体。 京都GTUGのサイトは http://bit.ly/d1nMLN 2 0 1 0 J u n e 0 4 (引用: http://bit.ly/arupc6 のPDFより) 3 appengine ja night #8 koher
  • 4. 今回発表することになった経緯 ajn7→Skip Listでランキングを実装→声をかけていただく •  ajn7でランキング問題が取り上げられた。 •  「#appengine でランキングを実装するには?androidアプリのゲーム で得点を元にユーザが何位だったのかを算出したい。昨日これを聞かれ て、あーなかなか思ったよりも難しいなーと考え中。みんなならどうす る?(ユーザ数は仮に10万だとして考える)」by @bluerabbit777jpさん (引用: App Engineでランキングを実装する問題 http://bit.ly/dmgEiI より) •  Indexable Skip Listを使えば解決できそうだと考え実装。 •  「Google App Engineでランキングやページングを実現する 」 http://bit.ly/auyI3S •  PIAX開発者の@kibayosさんの発言から、App Engineで集約関数 が実現できるのではないかという話に。 •  @kazunori_279さんに発表の機会をいただく。 2 0 1 0 J u n e 0 4 4 appengine ja night #8 koher
  • 5. 発表のテーマ Skip Listによる高速な順位・平均等の計算方法 •  Indexable Skip Listというデータ構造を使えば、順位計算や指定範 囲に対する集約関数の実行が高速に実現できる。 •  RANK、COUNT、SUM、AVG、MIN、MAX、MEDIANを実現! •  ただし、万能ではない…。 •  App Engine上にどうやって実装するか。問題点は何か。 2 0 1 0 J u n e 0 4 5 appengine ja night #8 koher
  • 6. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 2 0 1 0 J u n e 0 4 6 appengine ja night #8 koher
  • 7. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 O(log N)の二分探索で 11を検索 ソート済配列から値を 2 0 1 0 検索する例 J u n e 0 4 7 appengine ja night #8 koher
  • 8. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 初めに検索対象の11を 11を検索 真ん中の19と比較する 2 0 1 0 J u n e 0 4 8 appengine ja night #8 koher
  • 9. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 11は19より小さいの 11を検索 で19の右側は対象外 2 0 1 0 →半分に絞り込める J u n e 0 4 9 appengine ja night #8 koher
  • 10. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 次は11を残りの真ん中 11を検索 の値である7と比較 2 0 1 0 J u n e 0 4 10 appengine ja night #8 koher
  • 11. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 11は7より大きいので 11を検索 7の左側は対象外 2 0 1 0 →さらに対象を半分に J u n e 0 4 11 appengine ja night #8 koher
  • 12. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 値が見つかるまで同じ 11を検索 処理を繰り返す 2 0 1 0 J u n e 0 4 12 appengine ja night #8 koher
  • 13. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 1回の処理で対象を半 11を検索 分に絞り込めるので、 2 0 1 0 大量のデータからも高 J u n e 0 4 速に検索できる 13 appengine ja night #8 koher
  • 14. O(log N)とは 1000個→10回、100万個→20回、10憶個→30回の処理 •  アルゴリズムの速さは時間計算量のオーダーで表されることが多い。 •  O(N)のように表され、「Nのオーダー」と読む。 •  厳密にはO、Ω、Θなどの表記が区別される。 •  時間計算量がO(N)とは、N回の定数倍の処理でアルゴリズムが実行でき ることを表す(Nはデータの個数など)。 •  O(log N)のときは、N=1000→10回、100万→20回、10憶→30 回程度で処理が終わると覚えておくとイメージしやすい。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 11を発見! 11を検索 2 0 1 0 J u n e 0 4 14 appengine ja night #8 koher
  • 15. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 2 0 1 0 J u n e 0 4 15 appengine ja night #8 koher
  • 16. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) 5 H 17 13 11 3 19 7 データはどのような位 置に格納されていても、 2 0 1 0 T ポインタでつながって J u n e 0 4 いればよい 16 appengine ja night #8 koher
  • 17. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T Linked Listは前から順 4番目を に要素にアクセスしな 参照 ければならない 2 0 1 0 J u n e 0 4 17 appengine ja night #8 koher
  • 18. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 先頭ノードから順々に 4番目を たどっていく 参照 →O(N)と遅い 2 0 1 0 J u n e 0 4 18 appengine ja night #8 koher
  • 19. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 0番目 4番目を 参照 2 0 1 0 J u n e 0 4 19 appengine ja night #8 koher
  • 20. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 1番目 4番目を 参照 2 0 1 0 J u n e 0 4 20 appengine ja night #8 koher
  • 21. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 2番目 4番目を 参照 2 0 1 0 J u n e 0 4 21 appengine ja night #8 koher
  • 22. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 3番目 4番目を 参照 2 0 1 0 J u n e 0 4 22 appengine ja night #8 koher
  • 23. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 4番目 4番目を →目標の値に到着 参照 2 0 1 0 J u n e 0 4 23 appengine ja night #8 koher
  • 24. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 挿入・削除時に配列の 先頭に ように後ろの要素をず 2を挿入 らす必要がない 2 0 1 0 J u n e 0 4 24 appengine ja night #8 koher
  • 25. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 2 挿入するノードを作成 先頭に 2を挿入 2 0 1 0 J u n e 0 4 25 appengine ja night #8 koher
  • 26. Linked List Skip Listのデータ構造のベースはLinked List •  Skip Listのデータ構造はLinked Listをベースにしている。 •  Linked Listは配列のように複数の値を格納するためのデータ構造。 •  各ノードは値と次ノードへのポインタを持つ(下図)。 •  先頭ノードから順次アクセスするため参照は遅い→O(N) •  先頭への要素の挿入・削除は速い→O(1) •  要素がソート済であっても値の検索は遅い→O(N) H 3 5 7 11 13 17 19 T 2 ポインタをつなぎ替え 先頭に →後ろの要素をずらす 2を挿入 必要はない 2 0 1 0 J u n e 0 4 26 appengine ja night #8 koher
  • 27. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T William Pugh, Skip Lists: A Probabilistic 2 0 1 0 Alternative to Balanced Trees, (1990) J u n e 0 4 http://bit.ly/dxfh4D 27 appengine ja night #8 koher
  • 28. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 最上位階層の先頭ノー 2 0 1 0 13を検索 ドから検索開始 J u n e 0 4 28 appengine ja night #8 koher
  • 29. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 次ノードがないので下 2 0 1 0 13を検索 の階層に下りる J u n e 0 4 (次ノードが13より大 きい場合も同様) 29 appengine ja night #8 koher
  • 30. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 次ノードが13より小さ 2 0 1 0 13を検索 いので次ノードへ進む J u n e 0 4 30 appengine ja night #8 koher
  • 31. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 次ノードがないので下 2 0 1 0 13を検索 の階層に下りる J u n e 0 4 31 appengine ja night #8 koher
  • 32. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 次ノードが13より小さ 2 0 1 0 13を検索 いので次ノードへ進む J u n e 0 4 32 appengine ja night #8 koher
  • 33. Skip List ‒ 基本データ構造と検索 Skip Listを用いれば高速な(O(log N)の)検索が可能 •  Skip ListはLinked Listを複数階層積み上げたようなデータ構造。 •  最下層だけみるとただのLinked List。 •  上位階層になるほど要素が間引かれる。 •  特急→急行→各停と電車を乗り継ぐように上位階層からノードをた どることで高速な(O(log N)の)検索を実現。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 13を発見! 2 0 1 0 13を検索 J u n e 0 4 33 appengine ja night #8 koher
  • 34. Skip List ‒ 挿入と削除 (1) 挿入・削除の際に要素の分布を維持することは困難 •  どのように上位階層の要素を間引くべきか。 •  上の階層に上るごとに、要素を半分ずつ間引いていけば効率的(下図)。 •  下から2階層目では偶数番目、3階層目では4の倍数番目、4階層目 では8の倍数番目以外の要素は間引かれる。 •  この場合検索は効率的だが、要素の挿入・削除時にこのような要素 の分布を維持することは困難。 H 7 T H 3 7 13 T H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 34 appengine ja night #8 koher
  • 35. Skip List ‒ 挿入と削除 (2) 確率的に要素の分布を維持することで高速な挿入・削除を実現 •  挿入時に適切な確率に基づいてノードのレベル(階層数)を決定す ることで、理想的な分布と同程度の検索効率を実現できる。 •  任意のp>1について、レベルiのノードを(1/p)^iの確率で生成。 •  例えば、p=1/2のとき、50%の確率でレベル0、25%の確率でレベ ル1、12.5%の確率でレベル2、…のノードが生成される。 •  ノードのレベルはノード作成時に決定し、その後は変化しない。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 35 appengine ja night #8 koher
  • 36. Indexable Skip List ‒ 要素番号の計算 要素番号の計算のため次ノードへのポインタに距離を付加 •  次ノードへのポインタに距離情報を付加したIndexable Skip Listを 用いれば、O(log N)で要素番号や順位を計算できる(下図)。 •  検索時には通ったルートの距離の和によって要素番号を計算。 •  挿入・削除の際にはポインタの距離も更新する。 •  最上位層の距離をすべて足せばリストの全要素数も計算できる。 3 5 H 5 T 2 1 2 3 H 3 5 11 T 1 1 1 1 1 1 1 1 H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 36 appengine ja night #8 koher
  • 37. Indexable Skip List ‒ 要素番号による検索 要素番号によって値を検索することもできる •  ノードを検索するときに、キー値での検索同様に要素番号によって O(log N)で検索することもできる。 •  キー値との比較を行うでのはなく、指定された要素番号と現在のノー ドの要素番号を比較しながら検索を行う。 3 5 H 5 T 2 1 2 3 H 3 5 11 T 1 1 1 1 1 1 1 1 H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 37 appengine ja night #8 koher
  • 38. Indexable Skip List ‒ 挿入・削除 挿入・削除時は全階層分の距離の更新が必要となる •  Indexable Skip Listにノードを挿入・削除する場合、対象ノードの レベルに関わらず全階層分のデータを更新する必要がある。 •  最上位ノードまで距離情報を更新しなければならないため。 •  それでも挿入・削除の計算量はO(log N)。 •  処理が途中で打ち切られた場合、データに不整合が生じる。 3 5 H 5 T 2 1 2 3 H 3 5 11 T 1 1 1 1 1 1 1 1 H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 38 appengine ja night #8 koher
  • 39. Indexable Skip List ‒ 総和の計算 ポインタに値の区間の総和を付加すれば、総和を計算できる •  ポインタにその区間のキー値の総和を持たせれば、総和を計算する こともできる。 •  総和を要素数(ノードの順位)で割れば平均も計算できる。 •  要素数は順位計算の原理で計算。 •  この場合、ポインタに和と距離の両方の情報を持たせる。 10 48 H 5 T 5 5 18 30 H 3 5 11 T 2 3 5 7 11 13 17 0 H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 39 appengine ja night #8 koher
  • 40. Indexable Skip List ‒ 範囲に対する集約 要素番号や総和の差をとることで、範囲内の集約ができる •  キー値や要素番号による任意の範囲を指定して、その範囲内の要素 数や総和・平均を計算することもできる。 •  例えば3<KEY<=13の範囲の要素数を求めるには、13のノードの要素 番号から3のノードの要素番号を引く。 •  指定した範囲に対して、SQLのCOUNT、SUM、AVGのような計算が できるようになる。 3 5 H 5 T 2 1 2 3 H 3 5 11 T 1 1 1 1 1 1 1 1 H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 40 appengine ja night #8 koher
  • 41. Indexable Skip List ‒ 最大・最小・中央値 最初のノードが最小、最後が最大、真ん中が中央値 •  任意の範囲に対して(もちろんリスト全体に対しても)、キー値の 最大・最小・中央値を簡単に計算できる。 •  最初のノードの値が最小値(昇順の場合)→O(1) •  最後のノードの値が最大値(降順の場合)→O(1) •  真ん中(要素数/2番目)のノードの値が中央値→O(log N) 3 5 H 5 T 2 1 2 3 H 3 5 11 T 1 1 1 1 1 1 1 1 H 2 3 5 7 11 13 17 T 2 0 1 0 J u n e 0 4 41 appengine ja night #8 koher
  • 42. Indexable Skip List ‒ キー値以外の集約 (1) キーに紐付けられた値の総和を計算することもできる •  ポインタにキー値そのものではなくキーに紐付けられた値の和を持 たせることで、その値の総和をO(log N)で計算することができる。 123 116 H 5 T 100 23 50 66 H 3 5 11 T 43 57 23 19 31 37 29 0 H 2 3 5 7 11 13 17 T 43 57 23 19 31 37 29 2 0 1 0 J u n e 0 4 42 appengine ja night #8 koher
  • 43. Indexable Skip List ‒ キー値以外の集約 (2) キー値以外の最大・最小も求められるが少々困難 •  ポインタに、区間内の最大・最小の情報を付加すれば、キーに紐付 けられた値の最大・最小をO(log N)で求めることもできる。 •  範囲検索が難しい。 •  最下層から上位階層に登って再び最下層に下りる、山型のサーチパ スならO(log N)で計算可?他にもっと良い方法があるかも。 •  削除時に、削除されるノードを除いた最大・最小の再計算が必要。 57 37 H 5 T 57 23 31 37 H 3 5 11 T 43 57 23 19 31 37 29 N/A H 2 3 5 7 11 13 17 T 43 57 23 19 31 37 29 2 0 1 0 J u n e 0 4 43 appengine ja night #8 koher
  • 44. App Engine上での実装 ‒ Entityとノード (1) 方法1: 1ノード、1エンティティで表す •  1個のノードを1個のエンティティで表し、実装する。 •  次ノードへのポインタはリストプロパティに格納する。 •  4月25日のブログエントリー http://bit.ly/auyI3S の実装はこの方法。 •  ノードを1個ずつたどることになるので、getが遅いDatastoreではパ フォーマンスが悪い。 •  N=10000で要素番号の計算に平均2.8秒。 H 5 T H 3 5 11 T H 2 3 5 7 11 13 17 T Entity 2 0 1 0 J u n e 0 4 44 appengine ja night #8 koher
  • 45. App Engine上での実装 ‒ Entityとノード (2) 方法2: 複数のノードを1個のエンティティで表す •  ノードを階層ごとに分解し、同階層で複数のノードをまとめて1個 のエンティティに格納する。 •  例えばp=1000に設定すると、3階層で10憶ノード程度を格納できる。 •  参照系の処理を数百ミリ秒まで縮められるか? •  エンティティの内部は二分探索で検索可。 H 5 T H 5 17 T H 2 3 5 7 11 13 17 T Entity 2 0 1 0 J u n e 0 4 45 appengine ja night #8 koher
  • 46. App Engine上での実装 ‒ 考慮すべき点 不整合を防ぐためにGlobal Transactionがほしい •  Indexableだと処理が途中で打ち切られた場合に不整合が発生する。 →  定期的に不整合を検出して修正する。 →  Global Transactionを用いる。 •  同時実行制御の必要あり。 •  開始ノードにアクセスが集中するとスケールしないかも? •  「私の理解だと、最近できたConsistencyモードを弱く設定しないと常に マスタノードを読みにいく感じですね。」 by @ashigeruさん http://bit.ly/aBdxUn •  Log Counterのような方法も使えるかも? 「LogCounterはどうでしょう?・実装編 」 @kazunori_279さん http://bit.ly/cxlNUv •  Skip Listの発展形であるSkip GraphならスケールするけどIndexableにで きる?App Engine上で集約Skip Graphは可能? •  Indexableだと上位階層のエンティティの更新が競合しやすい。 2 0 1 0 J u n e 0 4 46 appengine ja night #8 koher
  • 47. MVCC ‒ Global Transactionの実現 MVCCでGlobal Transactionを実現できそう •  MVCCはMulti Version Concurrency Control(多版型同時実行 制御)の略で、同時実行制御の方式。 •  OracleやPostgreSQLはMVCCでトランザクションを実現している。 •  更新時にデータを上書きするのではなく、複数のバージョンのデータを 保持することで対応する。 •  読み込みと書き込みが互いにロックしないことが特徴。 •  Slim3のGlobal Transactionを用いることもできるが、ライブラリ に依存関係が生まれてしまう。 •  MVCCレイヤーだけ切り出して、DatastoreServiceインタフェー スを実装しようかと考え中。 •  きちんと検証できてないので、本当に実装できるかビミョー…。 2 0 1 0 J u n e 0 4 47 appengine ja night #8 koher
  • 48. MVCC ‒ 追記型のMVCC 追記型のMVCCではレコードを更新するのではなく追記する •  追記型のMVCCはデータ更新時にレコードを追記する。 •  トランザクションIDの有効区間(下表のStart、End)を持ち、Start (含む)からEnd(含まない)の区間にトランザクションIDが含まれて いる場合だけそのレコードを有効とする。 •  追記型のMVCCはPostgreSQLで採用されている。 Key Start End Data A001 100 105 A A001 105 999 B トランザクションIDが 2 0 1 0 100∼104は1行目、 J u n e 0 4 105∼は2行目が有効 48 appengine ja night #8 koher
  • 49. MVCC ‒ 追記型のMVCC 追記型のMVCCではレコードを更新するのではなく追記する •  追記型のMVCCはデータ更新時にレコードを追記する。 •  トランザクションIDの有効区間(下表のStart、End)を持ち、Start (含む)からEnd(含まない)の区間にトランザクションIDが含まれて いる場合だけそのレコードを有効とする。 •  追記型のMVCCはPostgreSQLで採用されている。 Key Start End Data A001 100 105 A A001 105 108 B A001 108 999 C トランザクションID 2 0 1 0 Update 108でDataをCに更新 J u n e 0 4 49 appengine ja night #8 koher
  • 50. MVCC ‒ 追記型のMVCC 追記型のMVCCではレコードを更新するのではなく追記する •  追記型のMVCCはデータ更新時にレコードを追記する。 •  トランザクションIDの有効区間(下表のStart、End)を持ち、Start (含む)からEnd(含まない)の区間にトランザクションIDが含まれて いる場合だけそのレコードを有効とする。 •  追記型のMVCCはPostgreSQLで採用されている。 Key Start End Data A001 100 105 A A001 105 108 B A001 108 110 C トランザクションID 2 0 1 0 Delete 110で削除 J u n e 0 4 →110以降では有効レ 50 appengine ja night #8 koher コードなし
  • 51. MVCC ‒ App Engine上での実装の工夫 Queryを使うと遅いので、Keyで検索できるようにする •  有効なエンティティをQueryで検索すると遅い。 •  Queryではなく、Keyでエンティティを検索できるようにする。 •  Keyで最新のEntityを検索し、Transaction IDが当てはまらない場合だ け、Linked Listの要領で過去のエンティティをたどるようにする。 •  更新の際には、現在のエンティティを複製し、元のエンティティを上書 きする際に複製されたエンティティへのポインタを持たせる。 name = name = _A0001 100_105_1_A0001 start = 100 start = 100 end = 105 end = 105 value = B value = A Entity 2 0 1 0 J u n e 0 4 51 appengine ja night #8 koher
  • 52. MVCC ‒ App Engine上での実装の工夫 Queryを使うと遅いので、Keyで検索できるようにする •  有効なエンティティをQueryで検索すると遅い。 •  Queryではなく、Keyでエンティティを検索できるようにする。 •  Keyで最新のEntityを検索し、Transaction IDが当てはまらない場合だ け、Linked Listの要領で過去のエンティティをたどるようにする。 •  更新の際には、現在のエンティティを複製し、元のエンティティを上書 きする際に複製されたエンティティへのポインタを持たせる。 name = name = name = _A0001 105_108_1_A0001 100_105_1_A0001 start = 108 start = 105 start = 100 end = 999 end = 108 end = 105 value = C value = B value = A Entity 2 0 1 0 J u n e 0 4 Update 52 appengine ja night #8 koher
  • 53. ライブラリの仕様 指定範囲に対して集約関数を実行可能なJavaのライブラリ •  指定範囲に対してCOUNT、MIN、MAX、SUM、AVG、MEDIAN 相当の機能をJavaで実装。もちろんイテレーションも可能。 •  Comparatorでキーの大小関係を自由に指定可能に。 •  Datastoreで実現できない複雑なルールに基づく並び順も実現可。 •  LongやDouble以外の値に対しても加算の演算ルールを実装すれば、 任意の型に対して総和や平均を計算可能に。 •  (例)方向を単位ベクトルに変換して方向の平均を計算する。 •  双方向にポインタを持たせて逆順のリストを取得可能に。 •  部分リストを取得可能に(指定範囲の集約は部分リストを利用)。 •  (例)部分リストから要素を取り出せばページングを実現できる。 •  キー値だけでなく、キーに紐づいた値の集約も可能に。 2 0 1 0 気長にお待ち J u n e 0 4 下さい… 53 appengine ja night #8 koher
  • 54. まとめ Indexable Skip Listによって集約関数を実現する方法を紹介 •  Indexable Skip Listを使えば、App Engine上で集約関数のような 計算が可能になる。 •  ただし、予め決定したソート順のある範囲に対してのみ実効できる。 •  ソート順はComparatorで自由に指定できる。 •  要素番号や順位、COUNTがO(log N)で計算でき、ページングにも利用 できる。 •  キーに対してはSUM、AVG、MIN、MAX、MEDIANが計算できる。 •  紐づいた値にもSUM、AVG、MIN、MAXが計算できる。 •  ライブラリ化するんで気長にお待ち下さいm(_ _)m 2 0 1 0 J u n e 0 4 54 appengine ja night #8 koher