J'ai créé 1 million de nœuds Neo4j par lots de 10000, chaque batch dans sa propre transaction. Ce qui est étrange, c'est que paralléliser ce processus avec une exécution multithread n'a eu aucun effet positif sur les performances. C'est comme si les transactions de différents threads se bloquaient les unes les autres.Création de nœuds multithread dans Neo4j
Voici un morceau de code Scala qui teste avec l'aide des collections parallèles:
import org.neo4j.kernel.EmbeddedGraphDatabase
object Main extends App {
val total = 1000000
val batchSize = 10000
val db = new EmbeddedGraphDatabase("neo4yay")
Runtime.getRuntime().addShutdownHook(
new Thread(){override def run() = db.shutdown()}
)
(1 to total).grouped(batchSize).toSeq.par.foreach(batch => {
println("thread %s, nodes from %d to %d"
.format(Thread.currentThread().getId, batch.head, batch.last))
val transaction = db.beginTx()
try{
batch.foreach(db.createNode().setProperty("Number", _))
}finally{
transaction.finish()
}
})
}
et voici les build.sbt
lignes nécessaires pour la construction et l'exécuter:
scalaVersion := "2.9.2"
libraryDependencies += "org.neo4j" % "neo4j-kernel" % "1.8.M07"
fork in run := true
On peut basculer entre les modes parallèle et séquentiel en supprimant et en ajoutant .par
appel avant le foreach
externe. La sortie de la console montre clairement que l'exécution .par
est en effet multithread. Pour exclure d'éventuels problèmes de concurrence dans ce code, j'ai également essayé une implémentation basée sur l'acteur, avec à peu près le même résultat (6 et 7 secondes pour les versions séquentielles et parallèles, respectivement). Donc, la question est: ai-je fait quelque chose de mal ou est-ce une limitation de Neo4j? Merci!
L'outil d'insertion par lots n'est pas ce qu'Oleg a utilisé mais l'API transactionnelle normale :) –
Je suppose que je lis beaucoup de "batch" es dans le texte ;-) Mais écrire avec plusieurs threads dans un fichier sera goulot par la vitesse io (comme vous avez répondu). – Jan