scalaのプログラムからneo4jを扱ってみます.
今回はサンプルとしてscalaからneo4jでノードをcreateするところをやりたいと思います.
そして,扱う方法としては,neo4jを組み込む方法かrestAPIで操作する方法がありますのでどちらも書きます.
今回はPlay!2.4
を使ってやってみました.
(Playを使う必然性は全然ありません..)
いくつかコードがでてきますが,前提としてはすでにactivator
でプロジェクトを作っていることとします.
コードについて詳しくは書いていないのでHow Toみたいな感じになってしまいました.
build.sbt
の追加部分はplayを使っても使わなくても同じだし,app/MatrixContorller
のcreate
関数の中の処理もさほど変わらない思います!
雛形
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
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
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
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を実行の記事を参考にさせていただきました.
著者さんがサンプルコードをgithubにあげていたのでリンクから飛んでみるといいと思います.
あとはactivator run
とか打って/create
のURLを打てば/neo4j/matrix
にdbが作成されていて,グラフが作成されているかと思います.
restAPI
scalaからneo4jをrestAPIで扱うライブラリとしてAnormCypherがあります.
ここで注意して欲しいことが1つ.
先ほどの組み込みではneo4j2.3を使っていましたが,AnormCypherではサポートされていないのでバージョンを下げてください.
(組み込みでも2.3である必要はないので適宜バージョンを変更してください)
Integration tests currently run against neo4j-community-2.1.3.
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
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を打てばグラフが作成されているはずです.
以上です!