neo4jのクエリ結果をファイルにリダイレクトする方法

# 背景
- neo4j内のデータを定期的にチェックする必要があった
- 外部からスクリプトでクエリを実行し、その結果をログとしてファイル出力したかった
- すぐに方法が見つからなかったのでメモ

# 結論
- neo4jにログインしてからクエリを実行するのではなく、cypher-shellにクエリ内容を渡してバッチ実行
- 実行結果をリダイレクトしてファイル出力

# 環境
- OS: CentOS7
- ne4j:4.3.2-community(docker)

# 実行例
## まずはクエリ内容と結果の確認
今回は下記のようなクエリを実行します

```
neo4j@neo4j> match (p:Person{name:"Tom Hanks"})-[ACTED_IN]->(m:Movie) return p.name, m.title;
+----------------------------------------+
| p.name      | m.title                  |
+----------------------------------------+
| "Tom Hanks" | "Apollo 13"              |
| "Tom Hanks" | "You've Got Mail"        |
| "Tom Hanks" | "A League of Their Own"  |
| "Tom Hanks" | "Joe Versus the Volcano" |
| "Tom Hanks" | "That Thing You Do"      |
| "Tom Hanks" | "The Da Vinci Code"      |
| "Tom Hanks" | "Cloud Atlas"            |
| "Tom Hanks" | "Cast Away"              |
| "Tom Hanks" | "The Green Mile"         |
| "Tom Hanks" | "Sleepless in Seattle"   |
| "Tom Hanks" | "The Polar Express"      |
| "Tom Hanks" | "Charlie Wilson's War"   |
| "Tom Hanks" | "That Thing You Do"      |
+----------------------------------------+

13 rows
ready to start consuming query after 43 ms, results consumed after another 2 ms
neo4j@neo4j>
```

## cypher-shell からバッチ実行する
### パターン１：cypher-shell の引数にクエリを指定する

```
# cypher-shell -u neo4j -p naisyo --format verbose 'match (p:Person{name:"Tom Hanks"})-[ACTED_IN]->(m:Movie) return p.name, m.title;'
+----------------------------------------+
| p.name      | m.title                  |
+----------------------------------------+
| "Tom Hanks" | "Apollo 13"              |
| "Tom Hanks" | "You've Got Mail"        |
| "Tom Hanks" | "A League of Their Own"  |
| "Tom Hanks" | "Joe Versus the Volcano" |
| "Tom Hanks" | "That Thing You Do"      |
| "Tom Hanks" | "The Da Vinci Code"      |
| "Tom Hanks" | "Cloud Atlas"            |
| "Tom Hanks" | "Cast Away"              |
| "Tom Hanks" | "The Green Mile"         |
| "Tom Hanks" | "Sleepless in Seattle"   |
| "Tom Hanks" | "The Polar Express"      |
| "Tom Hanks" | "Charlie Wilson's War"   |
| "Tom Hanks" | "That Thing You Do"      |
+----------------------------------------+

13 rows
ready to start consuming query after 2 ms, results consumed after another 2 ms
```

### パターン２：クエリ内容をファイルに記述し、ファイル内容を cypher-shell に渡して実行

```
# echo 'match (p:Person{name:"Tom Hanks"})-[ACTED_IN]->(m:Movie) return p.name, m.title;' > sample_query.cypher
# 
# cat sample_query.cypher 
match (p:Person{name:"Tom Hanks"})-[ACTED_IN]->(m:Movie) return p.name, m.title;
# 
# cat sample_query.cypher | cypher-shell -u neo4j -p naisyo --format verbose
+----------------------------------------+
| p.name      | m.title                  |
+----------------------------------------+
| "Tom Hanks" | "Apollo 13"              |
| "Tom Hanks" | "You've Got Mail"        |
| "Tom Hanks" | "A League of Their Own"  |
| "Tom Hanks" | "Joe Versus the Volcano" |
| "Tom Hanks" | "That Thing You Do"      |
| "Tom Hanks" | "The Da Vinci Code"      |
| "Tom Hanks" | "Cloud Atlas"            |
| "Tom Hanks" | "Cast Away"              |
| "Tom Hanks" | "The Green Mile"         |
| "Tom Hanks" | "Sleepless in Seattle"   |
| "Tom Hanks" | "The Polar Express"      |
| "Tom Hanks" | "Charlie Wilson's War"   |
| "Tom Hanks" | "That Thing You Do"      |
+----------------------------------------+

13 rows
ready to start consuming query after 0 ms, results consumed after another 2 ms
```
## あとは「>」でリダイレクトするだけ

## パターン１の場合

```
# cypher-shell -u neo4j -p naisyo --format verbose 'match (p:Person{name:"Tom Hanks"})-[ACTED_IN]->(m:Movie) return p.name, m.title;' > kekka1
#
# cat kekka1 
+----------------------------------------+
| p.name      | m.title                  |
+----------------------------------------+
| "Tom Hanks" | "Apollo 13"              |
| "Tom Hanks" | "You've Got Mail"        |
| "Tom Hanks" | "A League of Their Own"  |
| "Tom Hanks" | "Joe Versus the Volcano" |
| "Tom Hanks" | "That Thing You Do"      |
| "Tom Hanks" | "The Da Vinci Code"      |
| "Tom Hanks" | "Cloud Atlas"            |
| "Tom Hanks" | "Cast Away"              |
| "Tom Hanks" | "The Green Mile"         |
| "Tom Hanks" | "Sleepless in Seattle"   |
| "Tom Hanks" | "The Polar Express"      |
| "Tom Hanks" | "Charlie Wilson's War"   |
| "Tom Hanks" | "That Thing You Do"      |
+----------------------------------------+

13 rows
ready to start consuming query after 1 ms, results consumed after another 1 ms
```

## パターン２の場合

```
# cat sample_query.cypher | cypher-shell -u neo4j -p naisyo --format verbose > kekka2
# cat kekka2
+----------------------------------------+
| p.name      | m.title                  |
+----------------------------------------+
| "Tom Hanks" | "Apollo 13"              |
| "Tom Hanks" | "You've Got Mail"        |
| "Tom Hanks" | "A League of Their Own"  |
| "Tom Hanks" | "Joe Versus the Volcano" |
| "Tom Hanks" | "That Thing You Do"      |
| "Tom Hanks" | "The Da Vinci Code"      |
| "Tom Hanks" | "Cloud Atlas"            |
| "Tom Hanks" | "Cast Away"              |
| "Tom Hanks" | "The Green Mile"         |
| "Tom Hanks" | "Sleepless in Seattle"   |
| "Tom Hanks" | "The Polar Express"      |
| "Tom Hanks" | "Charlie Wilson's War"   |
| "Tom Hanks" | "That Thing You Do"      |
+----------------------------------------+

13 rows
ready to start consuming query after 0 ms, results consumed after another 1 ms
```

# その他
--format オプションには verbose 以外に plain も指定でき、出力結果が異なるので、目的に合わせて選択してください

例：

```
# cypher-shell -u neo4j -p naisyo --format plain 'match (p:Person{name:"Tom Hanks"})-[ACTED_IN]->(m:Movie) return p.name, m.title;'
p.name, m.title
"Tom Hanks", "Apollo 13"
"Tom Hanks", "You've Got Mail"
"Tom Hanks", "A League of Their Own"
"Tom Hanks", "Joe Versus the Volcano"
"Tom Hanks", "That Thing You Do"
"Tom Hanks", "The Da Vinci Code"
"Tom Hanks", "Cloud Atlas"
"Tom Hanks", "Cast Away"
"Tom Hanks", "The Green Mile"
"Tom Hanks", "Sleepless in Seattle"
"Tom Hanks", "The Polar Express"
"Tom Hanks", "Charlie Wilson's War"
"Tom Hanks", "That Thing You Do"
```

# まとめ
neo4j は最近触り始めたばかりですが、日本語のドキュメントが少ない印象なので、だれかの参考になれば幸いです。