SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

初めてのHBase

HBaseを使ってグラフDBを作ってみよう(中編)

初めてのHBase 第6回

  • X ポスト
  • このエントリーをはてなブックマークに追加

スキーマ設計

 それでは、スキーマの設計を考えていきます。

 まず、簡単に前回に説明したリレーションシップのスキーマのおさらいをします。リレーションシップのスキーマは以下になります。

RowKey ColumnFamily Column Timestamp Value
hash(startNodeId)-1-startNodeId-type-endNodeId "g" "c" timestamp createTimestmp
hash(startNodeId)-1-startNodeId-type-endNodeId "g" "p" timestamp {PropertyName:PropertyValue, …}
hash(startNodeId)-1-startNodeId-type-endNodeId "g" "u" timestamp updateTimestamp
hash(endNodeId)-2-endNodeId-INCOMING-type-(Long.MAX_VALUE - createTimestmp)-startNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
hash(startNodeId)-2-startNodeId-OUTGOING-type-(Long.MAX_VALUE - createTimestmp)-endNodeId "g" "" timestamp {PropertyName:PropertyValue, …}

 最初にhash値があり、次にRowKeyのタイプが入っています。RowKeyのタイプは1がリレーションシップのRow、2が最新順インデックスのRowとなっています。

 リレーションシップのRowでは、プロパティと作成時間(createTimestmp)と更新時間(updateTimestamp)が同じRowの中で別のColumnとして入っています。

 最新順インデックスは取得する方向によって、INCOMINGとOUTGOINGの2種類のRowがあります。また、最新順インデックスのRowにもプロパティの値が入っており、最新順インデックスをScanするだけでプロパティの値をルックアップする必要がない設計(非正規化)になっています。

 セカンダリインデックスも、最新順インデックスと基本的な考え方は同様です。ただし、プロパティの値によってソートされる必要があるので、RowKeyの中にpropertyValueを入れます。また、制約として、propertyValueの最大のサイズを決める必要があります。プロパティの値をRowKeyの中に入れて正しくソートするためには、固定長でなくてはならないからです。最大のサイズに満たない場合は、0で埋める必要があります。

 今回は、最大のサイズを100バイトとして実装します。

 HBaseでは、RowをRowKeyの昇順でScanすることはできますが、降順でScanすることはできません。そのため、昇順用のセカンダリインデックス以外に、降順用のセカンダリインデックスも作成する必要があります。降順用のセカンダリインデックスは、プロパティの値をビット反転させた値を用いることで作成できます。

 ここまでをまとめると、以下のスキーマになります。

RowKey ColumnFamily Column Timestamp Value
endNodeId-INCOMING-type-propertyName-ASC-propertyValue-(Long.MAX_VALUE - createTimestmp)-startNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
endNodeId-INCOMING-type-propertyName-DESC-(inverse propertyValue)-(Long.MAX_VALUE - createTimestmp)-startNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
startNodeId-OUTGOING-type-propertyName-ASC-propertyValue-(Long.MAX_VALUE - createTimestmp)-endNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
startNodeId-OUTGOING-type-propertyName-DESC-(inverse propertyValue)-(Long.MAX_VALUE - createTimestmp)-endNodeId "g" "" timestamp {PropertyName:PropertyValue, …}

 最新順インデックスと同様に、ColumnFamilyは固定値"g"としており、Columnは空になっています。また、propertyValueの後ろに(Long.MAX_VALUE - createTimestmp)があるのは、プロパティの値が同じだった場合に、より新しいリレーションシップが先になるようにするためです。

 最後に、書き込みや読み込みの分散のために、RowKeyのプレフィックスにhash値をつけます。また、それぞれのRowを区別するために、それぞれのRowのhash値の後にRowKeyのタイプを入れます。

RowKey ColumnFamily Column Timestamp Value
hash(endNodeId)-3-endNodeId-INCOMING-type-propertyName-ASC-propertyValue-(Long.MAX_VALUE - createTimestmp)-startNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
hash(endNodeId)-3-endNodeId-INCOMING-type-propertyName-DESC-(inverse propertyValue)-(Long.MAX_VALUE - createTimestmp)-startNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
hash(startNodeId)-3-startNodeId-OUTGOING-type-propertyName-ASC-propertyValue-(Long.MAX_VALUE - createTimestmp)-endNodeId "g" "" timestamp {PropertyName:PropertyValue, …}
hash(startNodeId)-3-startNodeId-OUTGOING-type-propertyName-DESC-(inverse propertyValue)-(Long.MAX_VALUE - createTimestmp)-endNodeId "g" "" timestamp {PropertyName:PropertyValue, …}

 ここで、今回作成しているグラフDBの整合性について書きます。

 読者の中には、1つのリレーションシップを格納するために複数RowをPutすると、Putが一部失敗した際に不整合が起こるだろうと考える方もいるのではないかと思います。HBaseは、基本的にはRow内のトランザクションしかサポートしていませんので、今回作成しているグラフDBの設計では実際に不整合が発生する可能性はあります。

 今回作成しているグラフDBの戦略としては、データの不整合が生じた場合は、後からそれを修復するというアプローチをとっています。最新順インデックスのRowやセカンダリインデックスのRowで不整合が生じた場合は、リレーションシップのRowから復旧させることになります。

 また、別の問題として、1つのリレーションシップを格納するための複数RowのPutはアトミックに行われないということがあります。つまり、更新が最新順インデックスのRowには反映されているが、セカンダリインデックスのRowには反映されていないという状態が一瞬だけ起こり得るということです。

 ただし、クエリパターンとして、実際に同時にScanされるのは、最新順インデックスのRowかセカンダリインデックスのRowかのいずれかです。一瞬だけ不整合な状態があったとしても、同時に取得されることはないので問題はないという考え方をとっています。

 さらに、今回追加するセカンダリインデックスにおける整合性の問題があります。これは実装に依存した話なので、そちらで書きたいと思います。また、HBaseにおけるトランザクションについては、本連載の中でもっと詳細に取り扱う予定となっています。

次のページ
実装

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
初めてのHBase連載記事一覧

もっと読む

この記事の著者

鈴木 俊裕(スズキ トシヒロ)

株式会社サイバーエージェント アメーバ事業本部 Ameba Technology Laboratory 2008年4月に株式会社サイバーエージェントに新卒で入社。基盤システムの開発・運用に従事する。 2010年4月にHadoop/Hiveを用いたログ解析基盤の開発・運用を担当する。 2011年4月に、ログ解析、レコメンド、検索エンジンなどを開発するAmeba Technology Laboratoryの立ち上げメンバーとなる。 2011年10月からHBaseを用...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7486 2013/11/15 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング