是否有任何示例Scala代码可用于在Neo4j-3.0.3中创建存储过程?
我一直在尝试创建一个基于Scala的简单存储过程。下面是我将scala-jar文件复制到neo4j-plugins目录并启动neo4j服务器时收到的错误消息:
================= Caused by: org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.kernel.impl.proc.Procedures@1ac0223' was successfully initialized, but failed to start. Please see attached cause exception. at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:444) at org.neo4j.kernel.lifecycle.LifeSupport.start(LifeSupport.java:107) at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:140) ... 10 more Caused by: org.neo4j.kernel.api.exceptions.ProcedureException: Unable to find a usable public no-argument constructor in the class `neoscala`. Please add a valid, public constructor, recompile the class and try again. =================
package neoproc import org.neo4j.graphdb.GraphDatabaseService import org.neo4j.procedure.Procedure; import javax.ws.rs.core.{Context, Response} class neoscala(@Context db: GraphDatabaseService) { @Procedure def alice():String = { String.valueOf(db.execute( "MATCH (n:User) return n" )); } }
答案 0 :(得分:1)
Your Scala class declares a constructor with a GraphDatabaseService
argument, and the exception tells you that it only wants a no-argument constructor.
It's documented in both
the user documentation:
Only static fields and @Context-annotated fields are allowed in Procedure classes.
the Javadoc:
The procedure method itself can contain arbitrary Java code - but in order to work with the underlying graph, it must have access to the graph API. This is done by declaring fields in the procedure class, and annotating them with the Context annotation. Fields declared this way are automatically injected with the requested resource. This is how procedures gain access to APIs to do work with.
All fields in the class containing the procedure declaration must either be static; or it must be public, non-final and annotated with Context.
Apparently it's not possible to create a class with a public field in Scala, so you'll have to create a parent Java class with the public field, and extend it with your Scala class:
// ProcedureAdapter.java
public abstract class ScalaProcedureAdapter {
@Context
public GraphDatabaseService db;
}
// neoscala.scala
class neoscala extends ScalaProcedureAdapter {
// ...
}
答案 1 :(得分:-1)
以下是解决方案:
我们将在scala中创建Class:
class FullTextIndex extends JavaHelper {
@Procedure("example.search")
@PerformsWrites
def search(@Name("label") label: String,
@Name("query") query: String): Stream[SearchHit] = {
//declare your method
}
val nodes: Stream[Node] = db.index.forNodes(index).query(query).stream
val newFunction: java.util.function.Function[Node, SearchHit] = (node: Node) => new SearchHit(node)
nodes.map {
newFunction
}
}
private def indexName(label: String): String = {
"label-" + label
}
}
Neo4j中的过程总是在Stream中返回结果,它是Java8中的最新特性,因此我们还将使用Java Class返回最终结果和定义公共变量。
我们将为结果创建Java类:
public class JavaHelper {
@Context
public GraphDatabaseService db;
@Context
public Log log;
public static class SearchHit {
//your result code here
}
您可以参考knoldus blog for Neo4j User Defined Procedure来创建和存储使用Scala的Neo4j过程。在这里,您还可以找到带有git hub存储库的示例代码。