🕸️

グラフデータベースを使って株式ポートフォリオを可視化したお話(後編: DB操作から)

2024/06/13に公開

前回の記事ではグラフデータベースとは何か、グラフデータベースを使えるDBaaSであるNeo4jワークスペースを開くまでを書きました。

後編では開いたNeo4jワークスペースを操作して、グラフを作ってみます。

この記事を書くために触って、作ってみたデータはこんな感じ。

こんな感じの銘柄、業種、それと銘柄取得する主目的の繋がりを可視化できるグラフを書いていきます。そんな記事。

Graph DBを操作する

Graph DBを操作する言語には複数あるらしいですが、Neo4jではOpenCypherと呼ばれる言語を使います。(Graph DBを操作するための言語はプロパティグラフクエリ言語というらしい)

画面上部でQueryタブに切り替えて、操作するためのクエリを入力。ctrl+Enterで実行していきます。

入力するクエリについて、この章では以下のように進めていきます。

  1. ノードを作成してみる
  2. ノードを検索してみる
  3. リレーションを作成してみる
  4. リレーションを検索してみる
  5. 間違えて作成したものを削除する
  6. グラフの画像を保存してみる

1. ノードを作成してみる

OpenCypherでノードを作成するときは以下のようなクエリを発行します。

CREATE (:Brand{name: "MHD"})

クエリの内容はこんな感じ。

CREATE (:<ノードのカテゴリ>{name: "ノード名"})

カテゴリとノード名を指定してCREATEするだけの簡単な構文。
"Mホールディングス"という名前で、カテゴリが銘柄(Brand)として作成します。
(冒頭の画像でいうオレンジのノードたちがBrandに属します)

他にも、業種カテゴリを作るためにIndustryCodeや、主目的カテゴリのためにPurposeを作っていきます。

CREATE(:IndustryCode{name: "食べ物"})
CREATE(:Purpose{name: "お菓子"})

これらのCreate文を全銘柄、全業種、全目的で実行していこう。全部作ってからまとめて実行していきました。

2. ノードを検索してみる

さて、CREATEで作成できたものを作成できているのか確認してみよう。
検索するにはMATCHを使います。

クエリの例を挙げるとこんな感じ。

MATCH(nodes:Brand{name:"MHD"})
RETURN nodes

構文としてはこんな感じ。

MATCH(<変数名>:<カテゴリ名>{name:"<名前>"})
return <変数名>

ここでは、1行目でのMATCHにて、
カテゴリがBrand、名前がMHDのものを検索して、変数nodesに代入します。
そして2行目のRETURNにて、nodesを出力すると、検索結果が表示されるというわけです。

複数検索をしたいときは、項目を空欄にしておくとワイルドカードのように検索できます。
カテゴリだけ指定したいときはこう。

MATCH(nodes:Brand)
RETURN nodes


ブランドカテゴリのノードが全て表示された。

ノード名だけ指定したいはこう。

MATCH(nodes{name: "食品"})
RETURN nodes


カテゴリ関係なく、"目的"、"業種"の両方から"食品"という名前のノードを検索している。

全検索するときはこんな感じ

MATCH(nodes)
RETURN nodes

作ったノード全部が出力されます。
表示をTableに切り替えると一覧で見れます。チェックするにはちょっと楽。

3. リレーションを作成してみる

リレーションの作成方法はこんな感じです

MATCH(MHD:Brand{name: 'MHD'})
MATCH(purpose:Purpose{name: 'お菓子'})
CREATE (MHD)-[:目的]->(purpose)

1行目にて、変数MHDに紐付ける銘柄を代入。
2行目にて、変数purposeに紐づける目的を代入。
3行目のCREATEで、MHDから見ると、purpose目的というリレーションを作成します。
そして>を使った矢印の方向で、リレーションの向きを表現しているわけです。

CREATE (<接続元>)-[:<関係>]->(<接続先>)

これを各リレーションの数だけ、24回実行していこう。
(わたしは面倒なので各リレーションをNumbersで一覧表にして、Numbers上でクエリを全部生成させました)

4. リレーションを検索してみる

さて、実際にリレーションが作成できているのか、確認しよう。
リレーションでも、検索にはMATCHを用いて、作成の時と同じように矢印を用いて表現します。
ここで、矢印の>を消してあげると、方向に関係なく検索できます。方向に関しても、指定しないことがワイルドカードになるということです。

MATCH(MHD:Brand{name: 'MHD'})
MATCH(purpose:Purpose{name: 'お菓子'})

MATCH (MHD)-[relation]->(purpose)
return relation

なんとなく、真ん中に代入するための変数が来るのに違和感を覚える。

MATCH (<接続元>)-[<変数名>]->(<接続先>)
return <変数名>

ここでも、空白にするとワイルドカードのようになるので、
全検索するときはこんな感じ。

MATCH ()-[relation]->()
return relation

リレーションだけ見ても何が何だかわからないので、接続元/先もそれぞれ変数r1r2に入れて表示してしまおう。

MATCH (r1)-[relation]->(r2)
return r1,relation, r2

各銘柄から、目的および業種のリレーションを伸ばしていることがわかる。
関係を全部出力する都合、多くなってしまうね。

5. 間違えて作成したものを削除する

ところで、間違えて生成したものは、検索したのちにDELETEつかうことで削除できます。

例えば、"施設利用"を間違えて"移設利用"と作ってしまった時の削除はこんな感じ。

MATCH (wrong: Purpose {name: "移設利用"})
DELETE wrong

RETURNで出力する代わりにDELETEで削除するわけです。

ここで削除対象が何かしらとリレーション張っている場合は削除できません。エラー吐かれます。

"移設利用"ノードに関する任意の繋がりを検索してみると、こんな感じ。

"移設利用"ノードを削除するにはこの接続を先に削除しておく必要があるわけです。

間違いノードwrongとワイルドカード(無記入)の繋がりrelationを検索して、DELETEで削除。

MATCH (wrong{name: "移設利用"})
MATCH ()-[relation]-(wrong)

DELETE relation

その後、間違いノード削除すると綺麗にすることができます。

MATCH (wrong{name: "移設利用"})
DELETE wrong

繋がりという要素が増えたぶん大変だ。

6. グラフの画像を保存してみる

さぁ、各種ノードとそれらのリレーション、そして間違いの修正まで済んだのでグラフを表示してみよう。

ワークスペース上部にあるExploreタブに切り替えて、検索ボックスから全てのリレーションを検索します。

(any)-<Any>-(Any)

と入力して、検索ボックス内右端の検索実行ボタン(再生マークのようなボタン)を押すと、検索されたグラフが出てきます。

ある業種だけに絞りたかったら、"ある業種コードと繋がっている銘柄を買う目的"まで絞り込んであげるといいわけです。(検索結果をハイライトする設定は右上の歯車マークからできる)

(IndustryCode name(equal):食品)-<any>-(Brand)-<any>-(Prupose)

ここまで表示できたら、右上ダウンロードするマークを押してExport screenshotから画像を保存します。
保存したものがこんな感じ。

あとは可視化したグラフから、目的の中でも矢印多い食品を重視しているんだなとか、業種コードごとのばらつきが激しいなとかを観察、分析していこう。

表示までしました。それをどう見て、どういう戦略を立てるのかはまた別のお話なので、この記事はここでおしまい。

Discussion