GraphDB: Dgraph のすゝめ
この記事はAizu Advent Calendar 2017 - Adventar 22日目の記事です。
前の人はywkw1717さんのSmart ContractをデプロイするときにEVMで行われていること - yyyで、
次の人はyopioさんです。
はじめに
紹介欄ではKotlin, Rust, 強化学習のどれかを話そうと思ってたのですが、僕の周りでGraphDBの話が聞きたいという人がいたのでGraphDBの話をします。
インターンでかじった程度なので色々と雑になるかもしれませんので申し訳ありません...
GraphDBとは
GraphDBとはグラフデータベースです。よく使われるRDBでは構造は表のようになっています。
それに比べてGraphDBはグラフ指向型なので、構造がグラフ構造になっています。
DBをグラフ構造にする利点としては
- グラフ構造なので人間が理解しやすい
- 関係性を重視する構造に向いている (SNSなど)
- エッジとノードを辿るので多対多などに対しての探索コストが低い
などが挙げられます。
Dgraphとは
DgraphとはGo言語で実装されたGraphDBです。
github.com
GraphDBのなかではNeo4jが最も有名です。
Dgraphを使うのはNeo4jよりパフォーマンスが高いからです。
詳しくはこちらを見てください : Neo4j vs Dgraph - The numbers speak for themselves - Dgraph Blog
Dgraph入門
はじめに
Dgraphの事始めてきな感じのことを書こうと思います。
Golangで実装されGoのルールなのかわかりませんがA Tour of Dgraphがあります。
これから書くこととしては基本的にそちらにも書いてあるのでそちらを見てもらってもよいかもしれないです。
環境構築
docker
% docker pull dgraph/dgraph
でまずdocker imageを取得します。
# Directory to store data in. This would be passed to `-v` flag. % mkdir -p /tmp/data # Run Dgraph Zero % docker run -it -p 8080:8080 -p 9080:9080 -p 8081:8081 -v /tmp/data:/dgraph --name diggy dgraph/dgraph dgraph zero --port_offset -2000 # Run Dgraph Server % docker exec -it diggy dgraph server --memory_mb 2048 --zero localhost:5080 # Run Dgraph Ratel % docker exec -it diggy dgraph-ratel
こんな感じで行けます。
on Mac or Linux
% curl https://get.dgraph.io -sSf | bash
これでインストール自体は完了です。
# Start Dgraph zero % dgraph zero --port_offset -2000 # Strat Dgraph Server % dgraph server --memory_mb 2048 --zero localhost:5080 # Start Dgraph ratel % dgraph-ratel
こんな感じで走らせます。
Query
次に軽くQueryを解説します。
今回解説するのは下記の3つです。
- mutation (set, delete)
- schema
- function
mutaion
mutationはDBに直接的な変更があるブロックです。
CRUDでいうところの C, U, D を行うブロックです。
{ set { _:Tokyo <name> "東京" . _:Kanagawa <name> "神奈川" . _:Saitama <name> "埼玉" . _:Chiba <name> "千葉" . _:Ibaraki <name> "茨城" . _:Gunma <name> "群馬" . _:Tochigi <name> "栃木" . } }
{ delete { <0x1> <name> * . } }
上のがCreateで下のがDeleteです。
上の処理において、_:Tokyo
や_:Kanagawa
などはそのブロック内で有効な識別子です。これはブロック内でのみ有効なので、ブロックから外れる場合はuidで指定しなければなりません。
それぞれのエンティティから<name>
というエッジを使ってそれぞれ文字列の値と接続しています。
下の処理ではすでに識別子の有効期限は切れているのでuidで指定する必要があります。今回は例として適当にこちら側で振りましたが、実際はDgraph側で決定されます。
delete
ブロックでは<0x01>
のエンティティの<name>
エッジで接続しているものを全て消去するようなクエリです。
schema
次にSchemaです。とりあえずサンプルです。
name: string @index(exact, term), @count . near: uid @count .
こんな感じで書けます。
@index
や@count
はそのエッジとなる<name>, <near>
に使える機能を付与しています。
例えば@count
であれば1つのエンティティに複数のエンティティが接続している状態であるときにその接続している個数をカウントできたりhas関数などが使えるようになります。
今回は特別にname
に関しても@count
を付与します。
逆にこの@count
がないとこの行為は行えません。@index
では文字列周りの操作が細かく行えるようになります。exact
やterm
に関しては細かくなってくるので公式リファレンスを参照していただけると幸いです。
function
恐らく一番使いそうなfunctionについて解説します。
{ getLocation(func: has(name)) { name near { expand( _all_ ) } } }
getLocationという関数です。
まずhas(name)
で<name>
エッジでの接続を保持しているノードのみを選択します。そして帰ってくるjsonの欲しい値を記述していきます。
今回は<name>
と<near>
を取得するようにしています。expand( _all_ )
はそこの値をすべて返す関数です。
例えばschema
で説明したものだとエッジはname
, near
, uid
の3つあります。それらを全て展開するのがexpand( _all_ )
です。
この場合<near>
は他のuid
を保持する、つまりは他のエンティティを所持しているので、そのエンティティの情報を全て返すような形になっています。
今回使用したこの関数は同じブロック内であれば使用することも可能です。
まとめ
インターンでDgraphを触ってそれから触ってなかったのでもしかしたら間違えがあるかもしれません。あったらごめんなさい...
所感としてはガッチリと固いものを作るというよりゆるふわなものを作る印象が強かったです。
GraphDBとしてはまだSNS方面でしか使い道がないらしくいい感じに利用できたらなぁとか思いました。