0
votes

Is there any sample Scala code available for creating stored procedures in Neo4j-3.0.3 ?

I have been trying to create one simple Scala based stored procedure. Below is the Error message I get when I copy my scala-jar file to the neo4j-plugins directory and start the neo4j server :

=================
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.
=================

The scala class that I have used is :

    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" ));
     }
    }
2

2 Answers

1
votes

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
votes

Here is the solution for this :

We will create Class in scala :

  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
   }
 }

Procedure in Neo4j always return result in Stream and it is a latest feature in Java8 so we will also used Java Class for return the final result and For defining the public variable.

We will create Java class for result :

public class JavaHelper {

@Context
public GraphDatabaseService db;

@Context
public Log log;

 public static class SearchHit {
    //your result code here
}

You can refer knoldus blog for Neo4j User Defined Procedure for creating and storing Neo4j Procedure with Scala. Here you will also find sample code with git hub repository.