GraphDB 入門
TinkerPop の使い方
Shoshi Tamaki
Nobuyasu Oshiro
08 Sep 2012
Shoshi Tamaki
Nobuyasu Oshiro
08 Sep 2012
Graph構造を保存するためのデータベース.
Graph構造とは,たとえばこんなもの
このような構造をしたGraphはPropertyGraphと呼ばれる.
PropertyGraphとは,
関係・人物・名前・特徴はVertex・Edge・Label・Propertyと呼ばれる.
GraphDBは,保存されたGraphのVertex,Edgeを渡り歩き,目的のデータを取得するようなデータベースである.
渡り歩くことをTraverseという.
TinkerPopはGraphDBを利用するためのツール群である.
Blueprintsは,PropertyGraphのJavaのinterfaceを提供する.
GraphDBの世界のJDBCの立場を目指している.
GraphをTraverseするための言語.Groovyがベースである.GraphDBに対してQueryを発行することが出来る.コンソールも利用できる.
gremlin> graph.v(1).out.name ==>vadas ==>lop ==>josh
GremlinはPipesを利用して,GraphをTraverseする..out.nameがPipeである..
PipesはGraphを処理するためのフレームワークである.Pipeという処理の単位を複数連結し,複雑なTraverseを実現する.
graph.v(1)はGraphからIDか1のVertexを取得する,.out .name がぞれぞれPipeに値する.
この例題の動作は・・・
gremlin> g.v(1).out.name ==>vadas ==>lop ==>josh
outはVertexから外向きのEdgeで繋がっているVertex一覧を取得する,nameはProperty名でPipeではVertexのnameを取得している.
まずは,TinkerGraphにストライクウィッチーズの相関図を入力する.
hg clone https://bitbucket.org/suikwasha/graphdb_javakuche
Mavenというプロジェクト管理ツールを利用したプロジェクトになってます.
ビルド方法・解凍したディレクトリに移動して $ mvn compile
Blueprintsは,GraphDBへのインターフェイスを提供する.TinkerGraphはBlueprintsを用いて利用できる.
相関図のGraphを作るためには,Graphを作成し人物(Vertex)と関係(Edge),特徴(Property)を作る必要がある.
// 相関図(Graph)の作成,データを保存するディレクトリを引数に取る Graph g = new TinkerGraph();
// 人物(Vertex)の作成,設定したいIDを引数に取る Vertex character = g.addVertex(ID);
// 関係(Edge)の作成,設定したいIDを引数に取る Edge relation = g.addEdge(ID,From,To,Label);
// 特徴(Property)の作成 , Vertex・Edgeともに同様のメソッド character.setProperty(PropertyName,PropertyValue);
これを入力します.
画像を見ながらコードに書き起こすと・・・
Graph g = new TinkerGraph("./strikewitches"); // 保存ディレクトリ Vertex strikeWitches = g.addVertex("StrikeWitches"); Vertex yoshika = g.addVertex("yoshika"); yoshika.setProperty(propName,"宮藤芳佳"); yoshika.setProperty(propRank,"軍曹"); yoshika.setProperty(propAge,14); yoshika.setProperty(propCV,"福圓美里"); yoshika.setProperty(propUnit,"扶桑皇国海軍遣欧艦隊"); yoshika.setProperty(propPersonality,"明るく前向きで一生懸命"); Vertex lynett = g.addVertex("lynett"); lynett.setProperty(propName,"リネット・ビショップ"); lynett.setProperty(propRank,"軍曹"); lynett.setProperty(propAge, 15); lynett.setProperty(propCV,"名塚佳織"); lynett.setProperty(propUnit,"ブリタニア空軍"); lynett.setProperty(propPersonality,"家庭的で戦闘は苦手"); g.addEdge(null,yoshika,lynett,"仲良し新人コンビ"); g.addEdge(null,lynett,yoshika,"仲良し新人コンビ");
実際にコードを動作させてTinkerGraphに入力する.
mvn exec:java -Dexec.mainClass=suikwasha.javakuche.CreateStrikeWitchesGraph
プロジェクトのディレクトリにstrikwitchesが作成される.
Blueprintsを用いてTinkerGraphに相関図を書き込むことが出来た.
今回は,Graph探索のサンプルのため"StrikeWitches"というキャラクター全員が所属する頂点を追加してある.
では,Gremlinを利用して相関図を解析してみる.
Gremlinのセットアップ
% ./gremlin.sh [~/Downloads/gremlin-groovy-2.1.0/bin] \,,,/ (o o) -----oOOo-(_)-oOOo----- gremlin>
こんなの表示される.
Gremlin に相関図を食べさせて,解析開始.
gremlin> g = new TinkerGraph("path_to_graph"); ==>tinkergraph[vertices:12 edges:32 directory:path_to_graph] gremlin>
Vertexの一覧を取得してみる.
gremlin> g.V // GraphのVertex一覧 ==>v[mio] ... ==>v[minna] ==>v[lynett] ... ==>v[gertrud] ==>v[francesca]
宮藤芳佳の年齢を取得.
gremlin> g.v("yoshika").age ==>14
宮藤芳佳を指導しているのは誰?
gremlin> g.v("yoshika").in("指導").name ==>坂本美緒
宮藤芳佳のことをきっー!なんなんですのアナタは!?と思っている人が勤務態度に不満を持っている人たち
gremlin> g.v("yoshika").in("きっー!なんなんですのアナタは!?") .out("勤務態度に不満").name ==>シャーロット・E・イエーガー ==>フランチェスカ・ルッキーニ
宮藤芳佳のことをきっー!なんなんですのアナタは!?と思っている人が勤務態度に不満を持っている人たち
gremlin> g.v("yoshika").in("きっー!なんなんですのアナタは!?") .out("勤務態度に不満").name ==>シャーロット・E・イエーガー ==>フランチェスカ・ルッキーニ
16歳以下のウィッチ一覧
gremlin> g.v("StrikeWitches").out.filter{it.age < 16}.name ==>宮藤芳佳 ==>エイラ・イルマタル・ユーティライネン ==>サーニャ・V・リトヴャク ==>リネット・ビショップ ==>ペリーヌ・クロステルマン ==>フランチェスカ・ルッキーニ
{it.age < 16}はクロージャである.outで出力されたキャラクターのVertexが,それぞれitに格納される.Groovyでitは暗黙に定義されるクロージャの変数であり,第一引数が自動的に割り当てられる.
GremlinをJavaから使うためには,Mavenを利用するのが簡単である.
Mavenはプロジェクト管理ツールであり,他のプロジェクトのライブラリを簡単に取り込むことができる.
pom.xmlにGremlinを取り込むように記述する.
<dependency> <groupId>com.tinkerpop.gremlin</groupId> <artifactId>gremlin-java</artifactId> <version>2.1.0</version> </dependency>
"Using Gremlin through Java" よりtinkerpop/gremlin wiki
TinkerGraphで作った,相関図を読み込む
Graph g = new TinkerGraph("path_to_graph");
GremlinPipeline の作成
GremlinPipeline<Vertex,String> pipe = new GremlinPipeline<Vertex,String>(); pipe.start(g.getVertex("yoshika"))....
GremlinはGraphに対して処理をするPipeをつなげて,複雑な探索を可能にする.Gremlin コンソールでは見えないが,JavaではPipesを利用しているのが確認できる.
宮藤芳佳を指導しているのは誰?
pipe.start(g.getVertex("yoshika")).in("指導").property("name"); for(String name : pipe){ System.out.println("name") }
宮藤芳佳のことをきっー!なんなんですのアナタは!?と思っている人が勤務態度に不満を持っている人たちの年齢
pipe.start(g.getVertex("yoshika")).in("きっー!なんなんですのアナタは!?") .out("勤務態度に不満").property("age"); for(Integer age : pipe){ System.out.println(age); }
15歳以上のウィッチーズの名前
pipe.start(g.getVertex("StrikeWitches")).out("member") .filter(new PipeFunction<Vertex,Boolean>(){ public Boolean compute(Vertex _argument){ return (Integer)_argument.getProperty("age") >= 15; } }).name; for(String name : pipe){ System.out.println(name); }
書き方としては,Gremlin コンソールでのほうが簡潔.
gremlin> g.v("StrikeWitches").out.filter{it.age > 15}.name
Gremlin コンソールでの書き方を Java で利用することができる.
Pipe pipe = Gremlin.compile("_().out.filter{it.age > 15}.name"); pipe.setStarts( new SingleIterator<Vertex>(g.getVertex("StrikeWitches")); for(Object name : pipe){ System.out.println(name); }
_()はGremlinePipelineに定義されている何もしないPipe
JavaでPipeを直接構築するより,こっちのほうが簡単である.
これまでに,ストライクウィッチーズの相関図を利用してGraphDBの概要とTinkerPopの簡単な使い方を見てきた.
この発表で大体のイメージが掴めてもらえれば幸いです.
次に,具体的な利用例としてPageRankのGraphDBでの表現について発表する.
例:アンサイクロペディア内のページ『琉球大学』のリンクの関係
PR(A) = (1-d) + d (PR(T1)/C(T1) + ... + PR(Tn)/C(Tn))
*各ページの情報は XML から取り出し Blueprints を用いて TinkerGraph に書き込み済み。
Graph graph = ... GremlinPipeline pipe = new GremlinPipeline(); pipe.start(graph.getVertex(id)); pipe.in("HasLink"); for (Object inVerObj : pipe) { Vertex inVer = (Vertex)inVerObj; : }
Graph graph = ... GremlinPipeline pipe = new GremlinPipeline(); pipe.start(graph.getVertex(id)); pipe.out("HasLink"); long linkNum = pipe.count();
final double weight = 0.85; double sum = 0.0; double pageRank = 0.0; Vertex v = graph.getVertex(id); GremlinPipeline pipe = new GremlinPipeline(); pipe.start(graph.getVertex(id)).in("HasLink"); for (Object inVerObj : pipe) { Vertex inVer = (Vertex) inVerObj; Object inVerId = inVer.getId(); GremlinPipeline inPipe = new GremlinPipeline(); inPipe.start(graph.getVertex(inVerId)).out("HasLink"); long linkNum = inPipe.count(); double pr = (Double) inVer.getProperty(PAGE_RANK); sum += (double) pr / linkNum; } pageRank = (double) 1 - weight + (double) sum * weight; v.setProperty(PAGE_RANK, pageRank);
ページ名 | リンク数 | PageRank |
ユーモア枯渇症 | 7162 | 71.120 |
日本 | 3537 | 54.584 |
アンサイクロペディア | 3887 | 54.164 |
ウィキペディア | 2414 | 44.617 |
ニンジャスター | 177 | 36.167 |
ページ数 | 10回の計算にかかった時間(単位:ms) |
100 | 21 |
1000 | 67 |
10000 | 976 |
50000 | 7140 |
100000 | 26150 |
200000 | 74130 |
242014 | 93512 |