scalaからneo4jを扱ってみる(embedded or restAPI)


scalaのプログラムからneo4jを扱ってみます．
今回はサンプルとしてscalaからneo4jでノードをcreateするところをやりたいと思います．

そして，扱う方法としては，neo4jを組み込む方法かrestAPIで操作する方法がありますのでどちらも書きます．

今回は`Play!2.4`を使ってやってみました．
(Playを使う必然性は全然ありません．．)
いくつかコードがでてきますが，前提としてはすでに`activator`でプロジェクトを作っていることとします．

コードについて詳しくは書いていないのでHow Toみたいな感じになってしまいました．

`build.sbt`の追加部分はplayを使っても使わなくても同じだし，`app/MatrixContorller`の`create`関数の中の処理もさほど変わらない思います！

## 雛形
### conf/routes

```scala:conf/routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

GET     /create                     controllers.MatrixController.create

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.versioned(path="/public", file: Asset)

```

`http://localhost:9000/create` でノードを作成することにします．

### app/MatrixController.scala

```scala:app/MatrixController.scala
package controllers

import play.api._
import play.api.mvc._


class MatrixController extends Controller {

  def create  = Action{
    //ここに処理書いていくってことで
    Ok(<p>Inserted nodes and rels</p>).as(HTML)
  }

}
```


## embedded
restAPIで操作するより，組み込んだ方が処理速度が10倍くらい速いっていうのをどっかのサイトで見た気がします．

ここからは実際にコードを書いていきます．

### build.sbt

```scala:build.sbt
name := """neo4j_play"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test,
  // 以下を追加
  "org.neo4j" % "neo4j" % "2.3.0"
)

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator
```

`libraryDependencies`にneo4jのライブラリを追加しました．

### app/MatrixController.scala

```scala:app/MatrixController.scala
package controllers

import play.api._
import play.api.mvc._
//以下を追加
import org.neo4j.cypher.ExecutionEngine
import org.neo4j.graphdb.GraphDatabaseService
import org.neo4j.graphdb.factory.GraphDatabaseFactory


class MatrixController extends Controller {

  def create  = Action{
    val db: GraphDatabaseService = new GraphDatabaseFactory().newEmbeddedDatabase("neo4j/matrix")
  	val engine: ExecutionEngine = new ExecutionEngine(db)
  	
  	val cypher = Array(
  	val cypher = Array(
  	"""
    |CREATE
    |      (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'}),
    |      (Keanu:Person {name:'Keanu Reeves', born:1964}),
    |      (Carrie:Person {name:'Carrie-Anne Moss', born:1967}),
    |      (Laurence:Person {name:'Laurence Fishburne', born:1961}),
    |      (Hugo:Person {name:'Hugo Weaving', born:1960}),
    |      (AndyW:Person {name:'Andy Wachowski', born:1967}),
    |      (LanaW:Person {name:'Lana Wachowski', born:1965}),
    |      (JoelS:Person {name:'Joel Silver', born:1952}),
    |      (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix),
    |      (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix),
    |      (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix),
    |      (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix),
    |      (AndyW)-[:DIRECTED]->(TheMatrix),
    |      (LanaW)-[:DIRECTED]->(TheMatrix),
    |      (JoelS)-[:PRODUCED]->(TheMatrix)
  """.stripMargin
  )
  	
  	val ns = Stream.from(1).iterator
  	cypher.foreach { c =>
      println(s"command${ns.next} :")
      println(engine.execute(c).dumpToString())
    }
    db.shutdown()
    Ok(<p>Inserted nodes and rels</p>).as(HTML)
  }

}
```

この処理のコードは[[Neo4J]　 ⑥ 組み込みサーバーモードでCypherを実行](http://qiita.com/kmry2045/items/bd7c7ac3b773a7308322)の記事を参考にさせていただきました．

著者さんがサンプルコードをgithubにあげていたのでリンクから飛んでみるといいと思います．

あとは`activator run`とか打って`/create`のURLを打てば`/neo4j/matrix`にdbが作成されていて，グラフが作成されているかと思います．

## restAPI
scalaからneo4jをrestAPIで扱うライブラリとして[AnormCypher](https://github.com/AnormCypher/AnormCypher)があります．

ここで注意して欲しいことが1つ．
先ほどの組み込みではneo4j2.3を使っていましたが，AnormCypherではサポートされていないのでバージョンを下げてください．
(組み込みでも2.3である必要はないので適宜バージョンを変更してください)

>Integration tests currently run against neo4j-community-2.1.3.


### build.sbt

```scala:build.sbt
name := """neo4j_play"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.6"

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test,
  //以下を追加
  "org.anormcypher" %% "anormcypher" % "0.7.1"
)

resolvers ++= Seq(
  "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases",
  //以下を追加
  "anormcypher" at "http://repo.anormcypher.org/",
  "Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases/"
)

// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator
```

### app/MatrixController.scala

```scala:app/MatrixController.scala
package controllers

import play.api._
import play.api.mvc._
import org.anormcypher.{Neo4jREST, Cypher}
import play.api.libs.ws.ning


class MatrixController extends Controller {

  def create  = Action{
    implicit val wsclient = ning.NingWSClient()
    implicit val connection = Neo4jREST()(wsclient)
    implicit val ec = scala.concurrent.ExecutionContext.global
    Cypher(
      """
      CREATE
      (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'}),
      (Keanu:Person {name:'Keanu Reeves', born:1964}),
      (Carrie:Person {name:'Carrie-Anne Moss', born:1967}),
      (Laurence:Person {name:'Laurence Fishburne', born:1961}),
      (Hugo:Person {name:'Hugo Weaving', born:1960}),
      (AndyW:Person {name:'Andy Wachowski', born:1967}),
      (LanaW:Person {name:'Lana Wachowski', born:1965}),
      (JoelS:Person {name:'Joel Silver', born:1952}),
      (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix),
      (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix),
      (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix),
      (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix),
      (AndyW)-[:DIRECTED]->(TheMatrix),
      (LanaW)-[:DIRECTED]->(TheMatrix),
      (JoelS)-[:PRODUCED]->(TheMatrix)
      """
    ).execute()
    wsclient.close()
    Ok(<p>Inserted nodes and rels</p>).as(HTML)
  }

}
```

### 実行
今回はすでに起動しているneo4jにクエリを投げるので，予めdbを作成し，起動しておいてください！

あとは先程と同様に実行してからurlを打てばグラフが作成されているはずです．

以上です！