Google App Engine:
Datastore を理解しよう 2
@bufferings 2010/05/28
#appengine ja night in kansai 2 ( #ajnk2 )
京都 GTUG とは ?
正式名称
「Kyoto Google Technology User Group」
Kyoto GTUG 目的
純粋・シンプルにGoogleのテクノロジーを 理解・習得するための活動をする。
(これは、世界中のGTUG共通の目的)
*漢字表記の「京都GTUG」は国内のみの利用でお願いします。
#appengine ja night in kansai 2 ( #ajnk2 ) 3
Google Technology User Group
● 現在、全世界で 51 ヶ国 100 を超える地域でローカルな GTUG が設立されています。
http://www.gtugs.org/directory
● 各地域で、 Google のテクノロジーに興味のある方々が組 織を立ち上げています。
● 将来的には、地域を越えたイベントもやりたいよね!という 話が、マネージャの ML でやりとりされています。
● 京都 GTUG は Pulse 世界 1 位です! http://www.gtugs.org/pulse.jsp
京都 GTUG へ!
● まだ、参加してない方はぜひ参加して下さいね!
● 京都 GTUG
http://kyoto-gtug.org/
● 京都 GTUG (Google Group) http://group.kyoto-gtug.org/
#appengine ja night in kansai 2 ( #ajnk2 ) 5
後援:京都リサーチパーク株式会社
● 京都リサーチパーク株式会社 http://www.krp.co.jp/
● この会場は、京都リサーチパーク株式会社の後援
により提供していただいております。
#appengine ja night in kansai 2
( #ajnk2 )
関西のみんなで GoogleAppEngine(Java/Python) に ついての実践的なノウハウを共有していきましょう!
#appengine ja night in kansai 2 ( #ajnk2 ) 7
自己紹介
@bufferings
● Slim3 サイトの日本語化
http://sites.google.com/site/slim3documentja/
● Kotori Web JUnit Runner(ktrwjr ことーじゃ ) http://code.google.com/p/ktrwjr/
前回のおさらい
#appengine ja night in kansai 2 ( #ajnk2 ) 9
Datastore
Bigtable
#appengine ja night in kansai 2 ( #ajnk2 ) 11
Bigtable
Row name Row data
A distributed, shareded, sorted Array
Entity
#appengine ja night in kansai 2 ( #ajnk2 ) 13
Entity
Entities Table
#appengine ja night in kansai 2 ( #ajnk2 ) 15
Entities Table
Path
Entities Table
#appengine ja night in kansai 2 ( #ajnk2 ) 17
Entities Table
Protocol Buffers
●Bigtable や Google Wave で実運用されている オープンソースのシリアライザー
http://code.google.com/p/protobuf/
Entities Table
#appengine ja night in kansai 2 ( #ajnk2 ) 19
Entities Table > 例
※ この図は概念図です。実際の実装を表すものではありません。
Entity Group
#appengine ja night in kansai 2 ( #ajnk2 ) 21
Kind とスキーマ
ソフトスキーマ
#appengine ja night in kansai 2 ( #ajnk2 ) 23
Null 値と Unset
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
#appengine ja night in kansai 2 ( #ajnk2 ) 25
Read
Prefix Scan
#appengine ja night in kansai 2 ( #ajnk2 ) 27
Range Scan
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
#appengine ja night in kansai 2 ( #ajnk2 ) 29
Get
Get
● Key = MyApp/Person(1)/Person(10)
#appengine ja night in kansai 2 ( #ajnk2 ) 31
(参考) Batch Get
Query
#appengine ja night in kansai 2 ( #ajnk2 ) 33
Query
Query
#appengine ja night in kansai 2 ( #ajnk2 ) 35
Index
● 使用する全ての Query に対して Index が必要
● 問い合わせ時の計算・集約・ Join はできない
● プロパティの一部を返すことはできない ( キーだけを返すことは可能 )
● Entity を更新したら関係する Index が更新される
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
#appengine ja night in kansai 2 ( #ajnk2 ) 37
Query の構成
● Kind を指定
● 0 個以上のフィルタを指定
=, <=, <, >, >=, !=, IN
● 0 個以上のソート順を指定 ASC, DESC
※Kind を指定しない Kindless Query という特別な 種類の Query もあります
Query と Kind
● Query は単一の Kind の Entity だけを取得
→これが Kind の主な目的
#appengine ja night in kansai 2 ( #ajnk2 ) 39
制約
● あるプロパティをフィルタまたはソートするには、そ のプロパティが存在する必要がある
● 不等式フィルタが使用できるのは 1 つのプロパ ティに限られる
● 不等式フィルタで使用されているプロパティは他の ソート順よりも先にソートする必要がある
制約
● あるプロパティをフィルタまたはソートするには、そ のプロパティが存在する必要がある
● 不等式フィルタが使用できるのは 1 つのプロパ ティに限られる
● 不等式フィルタで使用されているプロパティは他の ソート順よりも先にソートする必要がある
Query の仕組みを知ることで
制約の理由がわかります。
→ 今日の目標
#appengine ja night in kansai 2 ( #ajnk2 ) 41
制約
● あるプロパティをフィルタまたはソートするには、そ のプロパティが存在する必要がある
● 不等式フィルタが使用できるのは 1 つのプロパ ティに限られる
● 不等式フィルタで使用されているプロパティは他の ソート順よりも先にソートする必要がある
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
#appengine ja night in kansai 2 ( #ajnk2 ) 43
Index Tables
● 自動で作成される Index
● Kind Index
● Single Property Index
● 定義が必要な Index
● Custom Index
Kind Index
#appengine ja night in kansai 2 ( #ajnk2 ) 45
Kind Index
● 特定の Kind の全 Entity を取得
Kind Index
● 特定の Kind の全 Entity を取得
● [Kind] Food
#appengine ja night in kansai 2 ( #ajnk2 ) 47
Single Property Index
● ASC
Single Property Index
● DESC
#appengine ja night in kansai 2 ( #ajnk2 ) 49
Single Property Index
● 1 つのプロパティに対する Filter
● 1 つのプロパティに対する Sort
● 1 つのプロパティに対する Filter と Sort
Single Property Index
● 1 つのプロパティに対する Filter
● [Filter] name = "Suzuki"
#appengine ja night in kansai 2 ( #ajnk2 ) 51
Single Property Index
● 1 つのプロパティに対する Filter
● [Filter] name > "B" and name < "T"
Single Property Index
● 1 つのプロパティに対する Sort
● [Sort] name DESC
#appengine ja night in kansai 2 ( #ajnk2 ) 53
Single Property Index
● 1 つのプロパティに対する Filter と Sort
● [Filter] name > "B" and name < "T"
● [Sort] name ASC
Custom Index
#appengine ja night in kansai 2 ( #ajnk2 ) 55
Custom Index
● 2 つ以上のプロパティに対する Sort
● 2 つ以上のプロパティに対する Filter
● Ancestor と Filter または Sort
● Key の降順ソート
※ Merge Join (後述)で可能な Query もあります。
Custom Index
● Custom Index の定義
#appengine ja night in kansai 2 ( #ajnk2 ) 57
Custom Index
● 2 つ以上のプロパティに対する Sort
● [Sort] height ASC, weight DESC
Custom Index
● 2 つ以上のプロパティに対する Filter
● [Filter] lastname = "Suzuki" and firstname = "Jiro"
#appengine ja night in kansai 2 ( #ajnk2 ) 59
Custom Index
● 2 つ以上のプロパティに対する Filter
● [Filter] lastname = "Suzuki" and
firstname >= "B" and firstname < "T"
Custom Index
● 2 つ以上のプロパティに対する Filter
● [Filter] height = "170"
● [Sort] height ASC, weight DESC
#appengine ja night in kansai 2 ( #ajnk2 ) 61
Custom Index
● 不等式フィルタ使用時の 3 つのルール
● その1
1 つの不等式フィルタと複数の等式フィルタがあ る場合は、まず等式フィルタのプロパティでソー トされ、次に不等式フィルタのプロパティでソート されなければならない
Custom Index
● [Filter] height >= 165 and weight = 70
● [Sort] height ASC, weight DESC
#appengine ja night in kansai 2 ( #ajnk2 ) 63
Custom Index
● 不等式フィルタ使用時の 3 つのルール
● その 2
1 つの不等式フィルタと複数のソート順がある場 合は、まず不等式フィルタのプロパティでソートさ れ、次にその他のプロパティでソートされなけれ ばならない
Custom Index
● [Filter] weight > 60
● [Sort] height ASC, weight DESC
#appengine ja night in kansai 2 ( #ajnk2 ) 65
Custom Index
● 不等式フィルタ使用時の 3 つのルール
● その 3
不等式フィルタは1つのプロパティにしか適用で きない
Custom Index
● [Filter] height >= 170 and weight >= 70
#appengine ja night in kansai 2 ( #ajnk2 ) 67
Custom Index
● [Filter] height >= 170 and weight >= 70
Custom Index
● Ancestor と Filter または Sort
● Ancestor Query は後述
#appengine ja night in kansai 2 ( #ajnk2 ) 69
Custom Index
● Key の降順 Sort には Custom Index が必要
ここまでのまとめ
● 自動で作成される Index
● Kind Index
– 特定の Kind の全 Entity を取得
● Single Property Index
– 1 つのプロパティに対する Filter
– 1 つのプロパティに対する Sort
– 1 つのプロパティに対する Filter と Sort
#appengine ja night in kansai 2 ( #ajnk2 ) 71
ここまでのまとめ
● 定義が必要な Index
● Custom Index
– 2 つ以上のプロパティに対する Sort
– 2 つ以上のプロパティに対する Filter
– Ancestor と Filter または Sort
– キーの降順 Sort
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
#appengine ja night in kansai 2 ( #ajnk2 ) 73
Merge Join
● 複数のプロパティに対して等式フィルタのみを適用 する場合は、 Custom Index を使用せずに Query を実行することができる
● 条件
● [Filter] 等式フィルタのみ
● [Sort] なし
Merge Join
● 複数の Single Property Index をマージしながら検 索⇒ "Merge Join"
● Key がソートされていることを利用して "zig-zag" ア ルゴリズムを使用
#appengine ja night in kansai 2 ( #ajnk2 ) 75
Merge Join
● [Filter] a=1 and b=2 and c=3
Merge Join
● [Filter] a=1 and b=2 and c=3
#appengine ja night in kansai 2 ( #ajnk2 ) 77
Merge Join
● [Filter] a=1 and b=2 and c=3
Merge Join
● [Filter] a=1 and b=2 and c=3
#appengine ja night in kansai 2 ( #ajnk2 ) 79
Merge Join
● [Filter] a=1 and b=2 and c=3
Merge Join
● [Filter] a=1 and b=2 and c=3
#appengine ja night in kansai 2 ( #ajnk2 ) 81
Merge Join
● [Filter] a=1 and b=2 and c=3
Merge Join
● [Filter] a=1 and b=2 and c=3
#appengine ja night in kansai 2 ( #ajnk2 ) 83
Merge Join
● [Filter] a=1 and b=2 and c=3
Merge Join
● [Filter] a=1 and b=2 and c=3
#appengine ja night in kansai 2 ( #ajnk2 ) 85
Merge Join
● データ量が増えてくると Merge Join では処理しき れなくなる
⇒「 Custom Index が必要」というエラーになる
● Custom Index が定義されている場合は Merge Join せずに Custom Index が使用される
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
#appengine ja night in kansai 2 ( #ajnk2 ) 87
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
● 制約
Keys Only Query
● Entity 全体ではなく、キーだけを返す Query
● Datastore Data Received from API quota
● Datastore CPU Time quota
● などを減らすことができる(特に Entity が大きな場 合)
#appengine ja night in kansai 2 ( #ajnk2 ) 89
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
● 制約
Queries on Key
● キーに対してフィルタを指定することも可能
● 等式フィルタを使用するなら Query ではなく Get を使用すればいい
● なので、通常は不等式フィルタを使用する
● キーの降順ソートには Custom Index が必要
#appengine ja night in kansai 2 ( #ajnk2 ) 91
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
● 制約
Kindless Queries
● Kind を指定しない Query
● プロパティに対するフィルタやソートは指定できな い
● Ancestor と Key フィルタのみ指定可能
※Java 版では Kindless Query には Key フィルタも使 用できない
#appengine ja night in kansai 2 ( #ajnk2 ) 93
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
● 制約
Not-Equal と IN フィルタ
● データストア側でサポートされているのではなく DatastoreAPI 側でサポートされている
● 複数の Query を実行してその結果をマージしてい る
#appengine ja night in kansai 2 ( #ajnk2 ) 95
Not-Equal フィルタ
● prop < value と prop > value の結果をマージ
● Not-Equal(!=) は実際は不等式フィルタを実行する ので、不等式フィルタと同じ制約がある
IN フィルタ
● IN は複数の等式フィルタをマージ
● 複数の IN を持つことは可能
● IN(4 コ ) and IN(3 コ ) だと 12 コの Query を走らせ ることになる
#appengine ja night in kansai 2 ( #ajnk2 ) 97
Not-Equal と IN フィルタ
● Not-Equal も IN も複数の Query を実行するので普 通の Query よりも遅い
● 使う前にパフォーマンスを見ておいたほうがいい
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
#appengine ja night in kansai 2 ( #ajnk2 ) 99
Unset and Nonindexed Properties
● プロパティが設定されていない場合、その Entity は、そのプロパティに対するフィルタやソートの結 果には含まれない
注: null が設定されている状態とプロパティが設 定されていない状態は異なることに注意
Unset and Nonindexed Properties
● プロパティが Text 型または Blob 型の場合は Index は作成されない
● プロパティが Unindexed 指定されている場合は Index は作成されない
● Index が作成されない場合は、そのプロパティに対 するフィルタやソートの結果には含まれない
#appengine ja night in kansai 2 ( #ajnk2 ) 101
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
● 制約
Sort Orders and Value Types
● プロパティのソート順は型によって決まっている
● 整数型⇒数値
● 文字列型⇒ Unicode
#appengine ja night in kansai 2 ( #ajnk2 ) 103
Sort Orders and Value Types
● ただし、 Entity はソフトスキーマであり同じプロパ ティに異なる型のデータを持つことができる
● Entity1: propA = 123
● Entity2: propA = " 田中 "
Sort Orders and Value Types
● 同じプロパティに異なる型のデータがある場合
GAE は、まず型でソートして、次にその型の中の値 でソートする。
● 例えば整数型は文字列型よりも先になる
● Entity1: propA = 100
● Entity2: propA = 200
● Entity3: propA = "10"
#appengine ja night in kansai 2 ( #ajnk2 ) 105
Sort Orders and Value Types
● 注意点:整数型は浮動小数型よりも先になる
● Entity1: propA = 15
● Entity2: propA = 20
● Entity3: propA = 10.5
● Entity4: propA = 15.5
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
#appengine ja night in kansai 2 ( #ajnk2 ) 107
Ancestor Query
● EntityGroup の祖先を指定して Entity を取得する Query
● Kindless Ancestor Query
– Kind 指定なし
– Key フィルタのみ使用可能 (Java は不可 )
● Ancestor Query
– Kind 指定あり
– プロパティフィルタ、ソート順を指定可能 ( 要 Custom Index)
Ancestor Query
● Kindless Ancestor Query
⇒ おそらく Entities Table
● Ancestor Query
⇒ おそらく Kind Index
● プロパティフィルタ、ソート順を指定
⇒Custom Index
#appengine ja night in kansai 2 ( #ajnk2 ) 109
Kindless Ancestor Query
● [Ancestor] Person(1)/Person(10)
Ancestor Query
● [Kind] Food [Ancestor] User1
#appengine ja night in kansai 2 ( #ajnk2 ) 111
Ancestor Query
● [Kind] Person [Ancestor] Foo1
● [Filter] height >= 170 [Sort] height ASC
Ancestor Query
● ルートまでに複数の祖先 Entity が存在する場
合、 Custom Index の Ancestor の部分は各 Entity に展開される
#appengine ja night in kansai 2 ( #ajnk2 ) 113
色々
● Keys Only Query
● Queries on Key
● Kindless Queries
● Not-Equal と IN フィルタ
● Unset and Nonindexed Properties
● Sort Orders and Value Types
● Ancestor Query
● 制約
制約
● あるプロパティをフィルタまたはソートするには、そ のプロパティが存在する必要がある
● 不等式フィルタが使用できるのは 1 つのプロパ ティに限られる
● 不等式フィルタで使用されているプロパティは他の ソート順よりも先にソートする必要がある
#appengine ja night in kansai 2 ( #ajnk2 ) 115
Query & Index Tables
● Bigtable からのデータ取得
● Datastore からのデータ取得
● Query
● Query と Index
● Merge Join
● 色々
● Query と MVP
MVP と等式フィルタ
● Entity1(Key1)
● favorite=["apple", "google"]
● Entity2(Key2)
● favorite=["google"]
● Entity3(Key3)
● favorite=["orange"]
#appengine ja night in kansai 2 ( #ajnk2 ) 117
MVP と等式フィルタ
MVP と等式フィルタ
● [Filter] favorite="google"
#appengine ja night in kansai 2 ( #ajnk2 ) 119
MVP と等式フィルタ
● リスト内のいずれかの値が等式フィルタに一致す れば取得される
MVP と等式フィルタ
● [Filter] favorite="google" and favorite="apple"
● Merge Join によって Entity1 が取得される
#appengine ja night in kansai 2 ( #ajnk2 ) 121
MVP と不等式フィルタ
● Entity1(Key1)
● val=[1, 3, 5]
● Entity2(Key2)
● val=[2, 3, 4]
MVP と不等式フィルタ
● Entity1(Key1)
● val=[1, 3, 5]
● Entity2(Key2)
● val=[2, 3, 4]
#appengine ja night in kansai 2 ( #ajnk2 ) 123
MVP と不等式フィルタ
● [Filter] val >= 3
● 最初にマッチしたものが採用される
MVP とソート順
● Entity1(Key1)
● val=[1, 3, 5]
● Entity2(Key2)
● val=[2, 3, 4]
#appengine ja night in kansai 2 ( #ajnk2 ) 125
MVP とソート順
MVP とソート順
● ASC でも DESC でも Entity1,Entity2 の順になる
#appengine ja night in kansai 2 ( #ajnk2 ) 127
インデックス爆発
● MVP に対するフィルタを複数持つ Custom Index を 作成した場合
● Entity1
● val1: 要素数 10
● val2: 要素数 10
● Custom Index
● [Sort] val1 ASC, val2 ASC
⇒Entity1 の Index は 100 行になる
インデックス爆発
● 1Entity に対するインデックス数は 5000 まで
● Entity2
● val1: 要素数 18
● val2: 要素数 18
● val3: 要素数 18
● Query
● [Filter] val1=x and val2=y and val3=z
#appengine ja night in kansai 2 ( #ajnk2 ) 129
インデックス爆発
● Ancestor Query の Custom Index
● Ancestor は展開される
● 深い EG を形成している場合に MVP との組み合 わせでインデックス爆発になりやすい
Next gen queries
● Merge Join と Multi Query(Custom Index を使用す るもの ) の実装がパワーアップするらしい
http://code.google.com/events/io/2010/sessions /next-gen-queries-appengine.html
#appengine ja night in kansai 2 ( #ajnk2 ) 131
参考
● Programming Google App Engine
http://www.amazon.co.jp/o/ASIN/059652272X
● Under the Covers of the Google App Engine Datastore
http://sites.google.com/site/io/under-the-covers-of-the-google-app-engine-datastore
スライドは
http://snarfed.org/space/datastore_talk.html
● @kazunori_279 さんの「 GAE/J ってどう使う?」
http://d.hatena.ne.jp/kazunori_279/20090617/1245224939
● @ashigeru さんの「レンジスキャンのアレ」
http://gist.github.com/294650
● Cacoo ( カクー )
http://cacoo.com/
ありがとうございました