LoginSignup
8
4

More than 1 year has passed since last update.

Neo4j + Pythonの使い方あれこれ

Posted at

はじめに

この記事は、AMBL株式会社 Advent Calendar 2022の15日目の記事になります。是非、他の記事も読んで見て下さい〜:santa_tone2:

最近、業務でグラフ型DBであるNeo4jを使う機会があったのですが、筆者はグラフDBを扱うのが初めてだった事もあり、色々と四苦八苦した部分もあり...

今回の記事は、シンプルにNeo4jにPythonを用いてデータ登録するまでの流れを簡単にメモ書きしていきます。

環境設定

今回実装していた筆者の環境は、macOS Big Sur (version 11.6)になります。
まずは必要なツールを、ターミナル上でインストールします。

とは言っても、特にこれといって面倒な作業はありません。
下記の homebrew コマンドを叩けばOKです。

$ brew install neo4j

pythonは3.7以降のversionであれば、問題なく動きます。
今回使用するライブラリは以下の二つです。

$ pip3 install neo4j
$ pip3 install pandas

pythonからNeo4jを操作するために必要なdriverはneo4jライブラリ1個で完結しています。
めっちゃ便利ですね。
今回は登録するデータをCSV形式で持っている、という前提で進めていきますので、CSVを読み込むようにpandasを使用します。(楽なので)

Neo4j 起動

上記のコマンドが正常に完了したら、neo4jのサーバを起動します。

サーバ起動コマンド
$ neo4j start

サーバ終了コマンド
$ neo4j stop

サーバ状態確認コマンド
$ neo4j status

正常に起動すれば、下記のようなログが表示されます。
最後にThere may be a short delay until the server is ready.と表示されていれば問題ないです。
image.png

ちなみに、default設定でneo4jのサーバを起動した際はローカルにNeo4jサーバが立ち上げられます。
その際の利用ポートの設定状態は、下記の通りです。

Port 説明
7687 Neo4j本体
7474 管理コンソール(Neo4j Browser)のホスティング用

では、管理コンソール画面に移動してみます。
ブラウザ上でhttp://localhost:7474/にアクセスしましょう。

Neo4j コンソール画面

http://localhost:7474/にアクセスすると、初期状態ではこのような画面が表示されます。

image.png

ここでは、ログインIDとpasswordを求められます。
ログイン情報の初期設定値はこちらになります↓

ID Password
neo4j neo4j

* ログイン後、passwordの変更求められます。ご対応ください。

ログインができれば、コンソール画面に正常に遷移します。
とは言っても、この段階では特にデータ登録などされていないので、空っぽのDBがあるだけです。
では、早速Pythonからデータ登録をしていきましょう。

image.png

Neo4jへのデータ登録

今回、登録するデータはこちら。

relation from_node_type from_node to_node_type to_node
テレパシー アーニャ・フォージャー スパイ ロイド・フォージャー
テレパシー アーニャ・フォージャー 暗殺者 ヨル・フォージャー
飼い犬 テレパシー アーニャ・フォージャー 予知能力 ボンド・フォージャー
母の弟 テレパシー アーニャ・フォージャー 特殊警察 ユーリ・ブライアン
もじゃもじゃ テレパシー アーニャ・フォージャー 情報屋 フランキー
怖い人 テレパシー アーニャ・フォージャー スパイ フィオナ・フロスト
スパイ ロイド・フォージャー 暗殺者 ヨル・フォージャー
暗殺者 ヨル・フォージャー スパイ ロイド・フォージャー
pet スパイ ロイド・フォージャー 予知能力 ボンド・フォージャー
pet 暗殺者 ヨル・フォージャー 予知能力 ボンド・フォージャー
シスコン 特殊警察 ユーリ・ブライアン 暗殺者 ヨル・フォージャー
恋慕 スパイ フィオナ・フロスト スパイ ロイド・フォージャー
特殊警察 ユーリ・ブライアン スパイ ロイド・フォージャー
恋敵 スパイ フィオナ・フロスト 暗殺者 ヨル・フォージャー
仲間 情報屋 フランキー スパイ ロイド・フォージャー

必要あれば、上記の表をexcelにコピペして作成してみてください。
では、上記のデータをまとめたcsvファイルにtest.csvとし、実際にDBに登録していきましょう。

まずは、ライブラリのインストール。

neo4j_test.ipynb
from neo4j import GraphDatabase, basic_auth
import pandas as pd

その後、Neo4jserverに接続・操作を行うdriverの設定。

neo4j_test.ipynb
# neo4j serverに接続するdriverの設定
driver = GraphDatabase.driver('neo4j://localhost:7687', auth=('neo4j', '****'))

ここまでできれば、接続準備は完了。
実際に、読み込むデータのロード。

neo4j_test.ipynb
demo_path = 'test.csv'
df = pd.read_csv(demo_path, encoding='sjis')

正しく読み込めていればこんな感じ。
image.png

今回はNeo4jにデータを登録する手順として、

  1. まずnode情報の登録する
  2. 登録されたnodeにrelationを作成する
    の順番に処理します。
    実際に処理する関数をここでは先に定義しています。
  • nodeを登録するNeo4jのクエリコマンド
    CREATE (f:{label}:character [name: $name]) RETURN f

  • relationを登録するNeo4jのクエリコマンド
    MATCH (f1:character {name: $from_node})
    MATCH (f2:character {name: $to_node})
    f'CREATE (f1)-[:{relation}]->(f2)

ここでは、上記のコマンドでデータを登録しているんだな、くらいに思ってもらえればOKです。

neo4j_test.ipynb
def add_node(tx, pair_node_info):
    for name, label  in pair_node_info:
        query = f'CREATE (f:{label}:character [name: $name]) RETURN f'
        query = query.replace("[", "{").replace("]", "}")
        tx.run(query, name=name)

def add_relation(tx, row):
    from_node = row["from_node"]
    to_node = row["to_node"]
    relation = row["relation"]

    tx.run('MATCH (f1:character {name: $from_node})'
            'MATCH (f2:character {name: $to_node})'
            f'CREATE (f1)-[:{relation}]->(f2)',
            from_node=from_node, relation=relation, to_node=to_node)

では、早速node情報を登録していきましょう。
そのコマンドはこちら。

neo4j_test.ipynb
node_list = []
label_list = []
node_list += df["from_node"].to_list()
label_list += df["from_node_type"].to_list()

node_list += df["to_node"].to_list()
label_list += df["to_node_type"].to_list()

pair_node_info = []
for idx in range(len(node_list)):
    pair_node_info.append((node_list[idx], label_list[idx]))

pair_node_info = list(set(pair_node_info))
with driver.session() as session:
    session.write_transaction(add_node, pair_node_info)

次に、relation情報を登録していきましょう。
そのコマンドはこちら。

neo4j_test.ipynb
def apply_relation(row):
    with driver.session() as session:
        session.write_transaction(add_relation, row)

df.apply(apply_relation, axis=1)

これらを実行して登録は完了。
結構あっさりしていたかなと思います。
では、コンソール画面に戻って実際にみてみましょう。

画面のコマンド入力部分にMATCH (n) RETURN n LIMIT 25と入力すると、
下記のような画面が表示されます。(見やすいように形だけ、整形しています。)

image.png

簡単な人物相関図ができました:clap::clap::clap:

とまぁ、こんな感じで簡単にデータの登録ができました。
ちょっと遊んでみる分にはいろいろ面白いですね。

最後に、登録した情報を全て削除したい場合は、下記を実行。
(コメントアウトしております。)

neo4j_test.ipynb
# def clear_db(tx):
#     tx.run('MATCH (n) DETACH DELETE n')

# with driver.session() as session:
#     session.write_transaction(clear_db)

終わりに

いかがでしたでしょうか?
グラフ型DBは使い所が難しい気もしますが、DBとして関係性を情報として検索できるのは結構面白いですよね。皆様も機会があれば触ってみてください。
最後に、今回使用したソースコードを貼っておきます。

neo4j_test.py

from neo4j import GraphDatabase, basic_auth
import pandas as pd

def add_node(tx, pair_node_info):
    for name, label  in pair_node_info:

        query = f'CREATE (f:{label}:character [name: $name]) RETURN f'
        query = query.replace("[", "{").replace("]", "}")
        tx.run(query, name=name)

def add_relation(tx, row):
    from_node = row["from_node"]
    to_node = row["to_node"]
    relation = row["relation"]

    tx.run('MATCH (f1:character {name: $from_node})'
            'MATCH (f2:character {name: $to_node})'
            f'CREATE (f1)-[:{relation}]->(f2)',
            from_node=from_node, relation=relation, to_node=to_node)

def apply_relation(row):
    with driver.session() as session:
        session.write_transaction(add_relation, row)

def main():
    driver = GraphDatabase.driver('neo4j://localhost:7687', auth=('neo4j', 'ambl-neo4j'))

    demo_path = 'test.csv'
    df = pd.read_csv(demo_path, encoding='sjis')

    node_list = []
    label_list = []
    node_list += df["from_node"].to_list()
    label_list += df["from_node_type"].to_list()
    node_list += df["to_node"].to_list()
    label_list += df["to_node_type"].to_list()

    pair_node_info = []
    for idx in range(len(node_list)):
        pair_node_info.append((node_list[idx], label_list[idx]))

    pair_node_info = list(set(pair_node_info))
    with driver.session() as session:
        session.write_transaction(add_node, pair_node_info)
    
    df.apply(apply_relation, axis=1)

if __name__ == ('__main__'):
    main()

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4