リレーションシップの作成
ここからはリレーションシップのコードになります。
まずは、リレーションシップの作成のコードです。
処理の流れとしては、リレーションシップのRowを作成(94~107行目)した後に、リレーションシップの最新順インデックスのRowを作成(112~125行目)しています。
リレーションシップのRowの作成は、ノードのRowの作成とほぼ同じです。
リレーションシップのRowにプロパティ、作成時間、更新時間をColumnとして入れています。
また、checkAndPutをしてPutすることで、リレーションシップがすでに存在している場合はfalseが返り、処理が中断されます。
リレーションシップの最新順インデックスのRowについては、IMCOMINGとOUTGOINGの2つのRowがPutされます。
リレーションシップのRowの作成時間を、PutオブジェクトのTimestampとして指定しています。
リレーションシップのプロパティの取得
次は、リレーションシップのプロパティの取得する処理です。
このコードは、ノードのプロパティを取得するコードと同様に、単純にリレーションシップのRowをGetしてプロパティを取得してます(290~297行目)。
Getをする際に、プロパティのColumnに限定して取得しています(294行目)。
リレーションシップのプロパティの追加・更新・削除
リレーションシップのプロパティを追加・更新・削除するコードは以下になります。
処理の流れとしては、リレーションシップのRowを更新(444~508行目)した後に、リレーションシップの最新順インデックスのRowを更新(513~526行目)しています。
リレーションシップのRowを更新の処理は以下のような流れになっています。基本的にはノードのRowの更新と同じです。
- 指定のリレーションシップの現在の更新時間、プロパティを取り出す(457~475行目)
- 新しい更新時間、新しいプロパティを生成(478~496行目)(新しい更新時間は必ず、現在の更新時間より後になるようにする)
- 更新時間に対するcheckAndPutを行う(504行目)。falseが返ってきたら、(1)に戻る(PutのTimestampには新しい更新時間を指定する)
上記の処理が成功した後に、リレーションシップの最新順インデックスのRowをPutします。
その際に、新しい更新時間をPutオブジェクトのTimestampとして指定しています(520行目)。
更新時間は単調に増加することが保証されているので、同時にリレーションシップのプロパティの更新リクエストが来た際に、それぞれのPutオブジェクトのTimestampは必ず(3)のcheckAndPutが成功した順番になります。
これにより、同時にリレーションシップのプロパティの更新リクエストが来た際にも、リレーションシップの最新順インデックスのプロパティがずれてしまうことはありません(※3)。
リレーションシップの削除
以下は、リレーションシップを削除するコードです。
処理の流れとしては、リレーションシップのRowを削除(192~229行目)した後に、リレーションシップの最新順インデックスのRowを削除(234~246行目)しています。
リレーションシップのRow削除の処理は、以下のような流れになっています。基本的にはノードのRowの更新と同じです。
- 指定のリレーションシップの現在の更新時間を取り出す(119~212行目)
- 削除時間を生成(215~219行目)(削除時間は必ず、現在の更新時間より後になるようにする)
- 更新時間に対するcheckAndDeleteを行う(225行目)。falseが返ってきたら、(1)に戻る(DeleteのTimestampには削除時間を指定する)
上記の処理が成功した後に、リレーションシップの最新順インデックスのRowをDeleteします。
その際に、新しい更新時間をDeleteオブジェクトのTimestampとして指定しています。
隣接リレーションシップの取得(最新順)
最後に、隣接リレーションシップを最新順で取得するコードです。
実際に、リレーションシップの最新順インデックスのRowをScanするコードです。
startRowには、hash(nodeId)-2-nodeId-direction-type を指定(317行目)し、stopRowにはそれをインクリメントしたものを指定(320~321行目)します。
これは、前回までに説明したパーシャルScanというテクニックです。
Valueに入っているプロパティとRowKeyに入ってるノードIDを取り出してRelationshipオブジェクトに詰め込み、それを結果として返しています(333~360行目)。
まとめ
今回は、株式会社サイバーエージェントでのHBaseのユースケースの一つであるグラフDBを作成しました。
CAS操作(checkAndPutやcheckAndDelete)を多用しているので、慣れていない方には多少分かりにくかったかもしれません。CAS操作を使うことで、ロックフリーなアルゴリズムを実装することができ、大変便利です。
次回は、今回作成したグラフDBにさらに機能を追加していきます。
また、株式会社サイバーエージェントでは、Hadoop/HBaseエンジニアを募集しています。ご興味のある方はこちらからエントリーしていただければと思います。エンジニア>R&Dエンジニア>R&Dエンジニアを選択しエントリーしていただければ幸いです。