GoogleCloudDatastoreのEntityについての覚書

#はじめに
CloudDatastoreを使い始めるにあたって、Entityについての覚書です。


#ドキュメント

データ整合性の説明
https://cloud.google.com/datastore/docs/concepts/structuring_for_strong_consistency?hl=ja

クエリの書き方
https://cloud.google.com/datastore/docs/concepts/queries?hl=ja

クエリの書き方
https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/google-cloud-datastore/v0.23.0/google/cloud/datastore

Datastore/Go のデータ設計のコツ
http://pospome.hatenablog.com/entry/2017/02/05/171635

#イベンチュアルコンシステンシー(結果整合性)とストロングコンシステンシー(強整合性)

GoogleCloudDatastoreでは
一般的なNoSQLで使われる"イベンチュアルコンシステンシー"と呼ばれる動作->clientデータが即座に検索結果に反映されない
に加えて、
"ストロングコンシステンシー"を持った検索を併せ持つ。

#クエリの検索方法
グローバルクエリ | Ancestorクエリー

例えば、ショッピングカートの例を考える

Users | Sales　という2個のKind(RDBではtableと同様)があった時に、下記のように設計できる。

```
Users ('Users':5639445604728832)
Users ('Users':5659313586569216)

Sales Key(Users, 5639445604728832, Sales, 5629499534213120)
Sales Key(Users, 5659313586569216, Sales, 5629499534213120)
Sales Key(Users, 5659313586569216, Sales, 5668600916475904)
Sales Key(Users, 5659313586569216, Sales, 5707702298738688)
```
<img width="965" alt="スクリーンショット 2018-01-19 15.42.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/aa3cb68e-8500-b6fc-a93b-da09a06ff632.png">
<img width="968" alt="スクリーンショット 2018-01-19 15.42.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/3bfdcff4-b4df-6c9c-1781-726f8ac91c39.png">


これを2種類の検索方法で検索してみる

```grobal_query.sql
select * from Sales where user_id = 2
```

```ancestor_query.sql
select * from Sales where __key__ 
has ancestor key(Users, 5659313586569216)
```
<img width="960" alt="スクリーンショット 2018-01-19 15.49.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/43766/20152a76-b438-c296-bc8b-9e725d168411.png">


この場合、どちらも同じ検索結果が取得できるが、グローバルクエリの場合は、イベンチュアルコンシステンシーとなるので、
必ずしも最新の状態でない可能性がある。
そのため、ショッピングカートなどの記述においては、Ancestorクエリーで取る。



また、グローバルクエリで取る場合は、indexを作製が必要。

```
indexes : 
-kind : Sales
	ancestor:no <-　グローバルクエリー用のインデックス
	properties:
		- name: user_id
```

次に、Ancestorクエリのindexの場合は、例えば、where句にprocess_data >= '2018-01-01'などを条件に加える場合は

```
indexes : 
-kind : Sales
	ancestor:yes <-　Ancestorクエリ用のインデックス
	properties:
		- name: process_data
```

#パフォーマンス

1つのエンティティグループの書き込み処理については、1秒に1回。

例えば、上記のUser,Salesの例でいくと、秒速で、カートに追加されるなどのことがなければ、
ユーザー毎にエンティティグループを分けているので大丈夫なはず。

トランザクション処理も可能なので、決済成功後に、Salesのstatusを決済済に更新する。
決済に失敗した場合はロールバックして未決済にするようなことも可能となる。


#Railsでglobalとancestorを書き分ける

```global_and_ancestor.rb
  def self.global_query_search
    query = Google::Cloud::Datastore::Query.new
    query.kind("Sales").
      where("process_data", "=", "2018/01/01")
    results = dataset.run query
  end

  def self.ancestor_query_search
    query = Google::Cloud::Datastore::Query.new
    query.kind("Sales").
      where("process_data", "=", "2018/01/01")
    parent_key = dataset.key "Users", 12345
    query.ancestor(parent_key)
    results = dataset.run query
  end
```

#そのほかの参考サイト

Google::Cloud::Datastore【訳】　
https://qiita.com/kotazi_/items/2bc9a0c8542f75809da9

Google App Engine と Cloud Datastore だけでオークションサイトを作った
http://mitomemel.hatenablog.com/entry/2016/09/28/231157

Cloud Datastore は Entity 毎になぜ秒間1回の書き込み制約があるのか
http://addsict.hatenablog.com/entry/2017/12/10/232320

Cloud Datastore を用い、大規模ゲームでのランキング処理を 1 時間から 5 秒に短縮　
https://cloud-ja.googleblog.com/2014/09/cloud-datastore-1-5_8.html

送金のトランザクションパターン
http://songofcloud.gluegent.com/2009/11/blog-post_18.html

これで怖くない Datastore のトランザクション
http://www.apps-gcp.com/datastore-transaction/

GAEでハマったこと(´･ω･`)
https://qiita.com/hogedigo/items/25b4dbefe694dbfc7dbc