- Neo4jを使ってみたのでその時のことをメモしておく
下記のステップで進めます
- Dockerコンテナの準備
- Dockerコンテナの起動
- Neo4j管理画面入室
- Cyperを利用したデータの操作
1. Dockerコンテナの準備
- Dockerhub neo4j
- neo4j のイメージを取得
$ mkdir graphdb-neo4j
$ cd graphdb-neo4j
$ docker pull neo4j
2. Dockerコンテナの起動
docker コマンドで起動
$ docker run \
--detach \
--publish=7474:7474 --publish=7687:7687 \
--volume=$HOME/neo4j/data:/data \
--volume=$HOME/neo4j/logs:/logs \
--volume=$HOME/neo4j/conf:/conf \
--ulimit=nofile=40000:40000 \
neo4j:latest
# 確認
$ docker CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
905109eecfc6 neo4j:latest "/sbin/tini -g -- /d…" 12 seconds ago Up 11 seconds 0.0.0.0:7474->7474/tcp, 7473/tcp, 0.0.0.0:7687->7687/tcp affectionate_elgamal
# コンテナに入る
$ docker exec -it neo4j bin/cypher-shell
username:****
password:****
# 退出
$ :exit
docker-compose.ymlの場合
version: '2'
services:
neo4j:
image: neo4j:latest
ports:
- "7474:7474"
- "7687:7687"
volumes:
- ${HOME}/neo4j/data:/data
- ${HOME}/neo4j/logs:/logs
- ${HOME}/neo4j/conf:/conf
ulimits:
nofile:
soft: 40000
hard: 40000
docker-compose.ymlで起動
$ docker-compsoe up -d
$ docker-compose Name Command State Ports
------------------------------------------------------------------------------------------------------------------------------
neo4j_neo4j_1_12ca70742005 /sbin/tini -g -- /docker-e ... Up 7473/tcp, 0.0.0.0:7474->7474/tcp, 0.0.0.0:7687->7687/tcp
# コンテナに入る
$ docker-compose exec neo4j bin/cypher-shell
username:****
password:****
# 退出
$ :exit
3. Neo4j管理画面入室
- 起動が確認できたらブラウザからNeo4jの管理画面に入室します
- 192.168.33.10:7474
- ホストアドレスは自分の環境に合わせて変更
- 初回はusernameとpasswordの初期設定を求められるもよう
4. Cyperを利用したデータの操作
- 公式ドキュメントを参考に軽くテストしてく
ノード作成
- ノードとはデータ点のこと
基本構文
CREATE (ParameterName:Label { field1: value1, field2: value2 })
一意制約
MATCH (ParameterName:Label { field1: value1, field2: value2 }) CREATE UNIQUE (ParameterName)
複数のラベルを指定
CREATE (ParameterName:Label1:Label2 { field1: value1, field2: value2 })
複数ノード作成*
CREATE (node1),(node2),...
結果を取得
CREATE (node1) RETURN paramName.field1
ノードと一緒にリレーションも作成
CREATE (node1:Label{field1:value})-[:relationName]->(node2:label{field1:value})
# ノードを2件作成
$ CREATE (n1:Person:Japanese { name: 'Sato', blood: 'A', age:25}),(n2:Person:Korea {name:'Kim', blood:'O', age:23})
# ノード3件とリレーションも作成
$ CREATE (n1:Person:Japanese { name: 'Endo', blood: 'AB', age:20}),(n2:Person:Japanese {name:'Aoki', blood:'A', age:18}),(n3:Person:Japanese {name:'Takagi', blood:'B', age:30}),(n1)-[:friends]->(n2)-[:friends]->(n3)-[:friends]->(n1)-[:friends]->(n3)
リレーションを追加
- リレーションとはエッジ(辺)のこと
基本構文
CREATE (node1)-[:Relations]->(node2)
相互リレーション
CREATE (node1)-[:Relations]->(node2)-[:relation]->(node1)
# SatoさんとKimさんは友達同士という関係を追加
$ MATCH (n1:Person { name: 'Sato'}),(n2:Person {name:'Kim'}) CREATE (n1)-[:friends]->(n2)-[:friends]->(n1)
# SatoさんはAokiさんと友達という関係を追加
$ MATCH (n1 {name:'Sato'}),(n2 {name:'Aoki'}) CREATE (n1)-[:friends]->(n2)
データを取得
基本構文
MATCH (n) RETURN n
# 全件取得
$ MATCH (n) RETURN n
ラベル検索
MATCH (n:LabelName) RETURN n
# 日本人というラベルで検索
$ MATCH (n:Japanese) RETURN n
属性検索 ※属性検索ではラベルは必須ではありません
MATCH (n:LabelName { name:'value' }) RETURN n
# Kimさんを検索
$ MATCH (n:Person {name:'Kim'}) RETURN n
WHERE句を使った検索
MATCH (n) WHERE n.field=value RETURN n
# Kimさんを検索
$ MATCH (n) WHERE n.name='Kim' RETURN n
前方一致
UNWIND list as v MATCH (n) WHERE left(n.name, size(v))=v return n
後方一致
UNWIND list as v MATCH (n) WHERE right(n.name, size(v))=v return n
# Ki,Satで始まるnameを検索さんを検索
$ UNWIND ['Ki','Sat'] as v MATCH (n) WHERE left(n.name, size(v))=v RETURN n
関係データを取得
構文
MATCH (node1)-[:Relations]->(node2) return node1, node2
# Satoさんの友達を検索(Satoさんの友達はKimさんとAokiさん
$ MATCH (n1 {name:'Sato'})-[:friends]->(n2) return n2
# Satoさんと友達同士の人を検索(友達同士なのはKimさんだけ)
$ MATCH (n1 {name:'Sato'})-[:friends]->(n2)-[:friends]->(n1) return n1, n2
ノードの階層を指定
MATCH (node1)-[:Relation*1..3]-(node2)
# Kimさんの友達の友達の友達を取得
$ MATCH (n1 {name:'Kim'})-[:friends*1..3]->(n2) RETURN n2
# Kimさんの友達の友達を友達と友達関係にある人物
$ MATCH (n1 {name:'Kim'})-[:friends*1..3]->(n2)-[:friends*]->(n3)-[:friends*]->(n2) RETURN n3
データを更新
ノードのプロパティを更新
MATCH (node) SET node.field = value
# Endoさんの年齢を30に更新
$ MATCH (node {name:'Endo'}) SET node.age = 30 return node
# Endoさんの性別、女性を追加
$ MATCH (node {name:'Endo'}) SET node.sex= 'femaile' return node
ノードのラベルを更新
MATCH (node1) SET node1:Label
# AokiさんにStudentというラベルを追加
$ MATCH (node1 {name:'Aoki'}) SET node1:Student
リレーションの属性(情報)を更新
MATCH (node1)<-[r:Relations]->(node2) SET r.type = 'value'
# SatoさんとKimさんの関係が親密であるという情報(属性)を追加
$ MATCH (node1{name:'Sato'})<-[relation1:friends]->(node2{name:'Kim'}) SET relation1.type = "intimate"
データを削除
ノードを削除
MATCH (node1) DELETE node1
リレーションも含めて削除
MATCH (node1) DETACH DELETE node1
リレーションだけ削除
MATCH (node1)-[r:Relation] DELETE r
# 削除用のデータを作成
$ CREATE (n1 {test:'hogehoge'}) return n1
# テストデータを削除
$ MATCH (node) WHERE node.test='hogehoge' DELETE node RETURN node
csvファイルからデータ取りこみ
ファイル名:./csv/node.csv
※こんな感じのデータ
1,Taro,20
2,Hanako,18
3,Kenta,22
4,Namihei,58
LOAD CSV FROM './csv/node.csv' AS line CREATE (:Person { name: line[1], age: toInteger(line[2])})
終わり
ドキュメントを参考にCRUDの使い方だけさらっと、それからリレーションの探索のところもさらっとやってみました。
前方(後方)一致検索について情報が載ってなかったのでメモです。
前方一致はともかく、後方一致や部分一致は検索が遅いであろうことは想像つきますので実用的ではないですが。