Over a million developers have joined DZone.

Neo4j With Scala: User Defined Procedures and APOC

See how you can use APOC to make your own procedures in Scala — with a relational database bent.

· Database Zone

Build fast, scale big with MongoDB Atlas, a hosted service for the leading NoSQL database. Try it now! Brought to you in partnership with MongoDB.

In the last blog, Getting Started Neo4j with Scala: An Introduction, which got the overwhelming response from Neo4j and DZone. We discussed how to use Neo4j with Scala. For a recap, here's the blog and the code. Now we are going to take one step further.

As we know that in the Relational Database, Procedure provides advantages of better performance, scalability, productivity, ease of use and security.

In the Neo4j we also used APOC and User Defined Procedure which provide same advantages which we get in the Relational Database.

User Defined Function

We used a user defined procedure in the Relational Database which we store in the database and call from there whenever needed. In Neo4j, we also do the same thing. Here, we create procedure method with the @Procedure annotation.

When we annotated with @Procedure, it takes any Cypher Type as parameters and returns Stream of Data Transfer Objects (DTO).

When the procedure writes to the database, at that time we also use the @PerformWrites annotation.

We should use the procedure for common tasks, or for those tasks that you use more frequently.

When we complete creation of Procedure, then we have to make its .jar and put that .jar into $Neo4j_Home/plugins/ and restart Neo4j. While making the .jar please be careful that all dependencies also become part of the .jar. Otherwise, the dependencies will not be found when Procedure is loaded.

After putting the .jar in and restarting server, run this Cypher to check your listed procedure.

CALL dbms.procedures();


You can also check the log: $Neo4j_Home/logs/debug.log the listed procedure in logs.

You can also check the log: $Neo4j_Home/logs/neo4j.log if the server is not starting. It will provide you with a clear picture of mistakes.

When we try to create a procedure, we have to use Java 1.8. Any version below that will not work. There is a reason for that — that's when Java introduced 'Stream,' which we use to return results. We're also using Scala 2.12.0-M5 for using a Java lambda in Scala.

Another thing — when we use Scala create procedures, we have to use a Java also file because only static fields and @Context-annotated fields are allowed in Procedure classes. We also define that class, which contains the result and sends them as an object in Stream, which we define here. It contains a public variable because when we define public variables in Scala, the Neo4j compiler is unable to access it.

Now we start creating files in Java:

@Context public GraphDatabaseService db;
@Context public Log log;


Now we define Procedure as a method in the Scala file, which will return Stream<Output>. Here, we are trying to create a procedure that will search ‘NodeId’ with the help of “Label” and “Query” and will return it as a Stream[SearchHit], where SearchHit is a static class that we define in the Java file. Here is the code:

@Procedure("example.search")
@PerformsWrites
def search(@Name("label") label: String, @Name("query") query: String): Stream[SearchHit] = {
    val index: String = indexName(label)
    if (!db.index.existsForNodes(index)) {
        log.debug("Skipping index query since index does not exist: `%s`", index)
        Stream.empty
    }
    val nodes: Stream[Node] = db.index.forNodes(index).query(query).stream

    val javaFunction: java.util.function.Function[Node, SearchHit] = (node: Node) => new SearchHit(node)
    nodes.map {
        javaFunction
    }
}


And in the Java, file we create a result class:

public static class SearchHit {
    public long nodeId;
    public SearchHit(Node node) {
        this.nodeId = node.getId();
    }
}


Now we create the .jar file for the procedure, put it in $Neo4j_Home/plugins/ and restart the Neo4j Server.

For checking whether the procedure is listed there, we can use this Cypher:

CALL dbms.procedures() YIELD name
RETURN head(split(name,".")) as package, count(*), collect(name) as procedures;


Here we find :

udf


Now as we can see, here is a new package name “example,” which contains “example.search.”

Now we can call this procedure with its parameter :

CALL example.search('User', 'name:Brook*')


callproc.png


Awesome Procedure on Cypher (APOC)

What Is APOC?

When we hear APOC, most of the people start thinking of “Apoc,” which is a character in ‘The Matrix’ movie. And they're. The name comes from there and ‘A Package Of Components’ for Neo4j.

APOC stands for Awesome Procedure On Cypher. APOC is a library of procedures. It was introduced with Neo4j 3.0, and it currently contains 206 libraries — and it's still growing. We can see this with using:

CALL dbms.procedures() YIELD name
RETURN head(split(name,".")) as package, count(*), collect(name) as procedures;


dbms.procedure.count.jpg


Some areas that have procedures designed for them are:

  • Graph Algorithm.
  • Metadata.
  • Manual indexes and relationship indexes.
  • Full-text search.
  • Integration with other databases like MongoDB, ElasticSearch, Cassandra and relational databases.
  • Path expansion.
  • Import and export.
  • Date and time function.
  • Loading of XML and JSON from APIs and files.
  • String and text function.
  • Concurrent and batched Cypher Execution.
  • Spatial Function and Lock.
  • Collection and map utilities.

How Can We Use APOC With the Llatest Release?

We have two ways to use the APOC with Neo4j.

First Way

  • Download binary .jar from the latest release [Click here]
  • Put that into your $Neo4j_Home/plugins/ folder.
  • Restart your Neo4j.

Second Way

  • Clone neo4j-apoc-procedure from here.
  • Go to the folder with ‘cd neo4j-apoc-procedures’.
  • Now create a .jar with the help of command ‘mvn clean compile install’.
  • Now copy your .jar file from the target to $Neo4j_Home/plugins/ folder.[cp target/apoc-1.0.0-SNAPSHOT.jar $Neo4j_Home/plugins/]
  • Restart your Neo4j.

Now configure your plugins in ‘conf/neo4j.conf’ with “dbms.plugin.directory=plugin’s path”, if you want to use it in embedded mode.

Now after restarting your Neo4j, you can check the procedure list. We used ‘ CALL ‘ for calling the procedure along with procedure_name.

CALL dbms.procedures();


dbms.procedure.jpg


Now we can call for help for the help function, which is built into the library.

CALL apoc.help("apoc")


apoc-help.jpg


We can use APOC for the various statements directly in Cypher. Here, you can find the full usage of the APOC Library.

This is a start for user-defined procedures in Neo4j with Scala.

I hope it will help for creating procedures with Scala. Please, provide your suggestions to make it better.

You can get the above working example for Scala from the GitHub repo.

Now it's easier than ever to get started with MongoDB, the database that allows startups and enterprises alike to rapidly build planet-scale apps. Introducing MongoDB Atlas, the official hosted service for the database on AWS. Try it now! Brought to you in partnership with MongoDB.

Topics:
annotation ,user ,method ,neo4j ,database ,relational database ,list

Published at DZone with permission of Anurag Srivastava, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}