How to configure Neo4j embedded to run apoc procedures?

2.2k Views Asked by At

I have setup Neo4j using the latest spring 1.5 release, spring-data-neo4j 4.2, with ogm drivers. The configuration is using embedded driver without URI (so impermanent database store)

Here is the spring @Configuration bean content:

@Bean
public org.neo4j.ogm.config.Configuration neo4jConfiguration() {
    org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration();
    configuration.driverConfiguration().setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver");
    // don't set the URI for embedded so we get an impermanent database
    return configuration;
}

@Bean
public SessionFactory getSessionFactory() {
    return new SessionFactory(
            neo4jConfiguration(),
            "xxx.yyy.springboot.neo4j.domain");
}

@Bean
public Neo4jTransactionManager transactionManager() {
    return new Neo4jTransactionManager(getSessionFactory());
}

Trying to run built in procedure works fine:

/**
 * Test we can call out to standard built-in procedures using cypher
 */
@Test
public void testNeo4jProcedureCalls() {

    Session session = sessionFactory.openSession();
    Result result = session.query("CALL dbms.procedures()", ImmutableMap.of());

    assertThat(result).isNotNull();
    List<Map<String, Object>> dataList = StreamSupport.stream(result.spliterator(), false)
            .collect(Collectors.toList());
    assertThat(dataList).isNotNull();
    assertThat(dataList.size()).isGreaterThan(0);
}

Now I'd like to install and run apoc procedures, which I've added to the classpath:

/**
 * Test we can call out to https://neo4j-contrib.github.io/neo4j-apoc-procedures
 */
@Test
public void testNeo4jApocProcedureCalls() {

    Session session = sessionFactory.openSession();
    Result result = session.query("CALL apoc.help(\"apoc\")", ImmutableMap.of());

    assertThat(result).isNotNull();
    List<Map<String, Object>> dataList = StreamSupport.stream(result.spliterator(), false)
            .collect(Collectors.toList());
    assertThat(dataList).isNotNull();
    assertThat(dataList.size()).isGreaterThan(0);
}

However, the above fails with error Description: There is no procedure with the name 'apoc.help' registered for this database instance

I couldn't find any documentation for registering apoc procedures to run in embedded mode. Couldn't find any reference to registering procedures in the OGM documentation. Any tips or snippets would be appreciated.

3

There are 3 best solutions below

2
On

Thanks for the pointer Michael. Your example is good for direct access, and this answer gave me the details needed to access through the neo4j-ogm layer:

Deploy a Procedure to Neo4J when using the embedded driver

so here's what I ended up with to register procedures through spring-data-neo4j

Note: isEmbedded() checks the neo4j driver property value contains 'embedded', and the Components.driver() call is static method provided by the ogm layer.

public void registerProcedures(List<Class<?>> toRegister) {
    if(isEmbedded()) {
        EmbeddedDriver embeddedDriver = (EmbeddedDriver) Components.driver();
        GraphDatabaseService databaseService = embeddedDriver.getGraphDatabaseService();
        Procedures procedures = ((GraphDatabaseAPI) databaseService).getDependencyResolver().resolveDependency(Procedures.class);
        toRegister.forEach((proc) -> {
            try {
                procedures.registerProcedure(proc);
            } catch (KernelException e) {
                throw new RuntimeException("Error registering " + proc, e);
            }
        });
    }
}

and add the call to register the procedures in the test when running with embedded:

@Test
public void testNeo4jApocProcedureCalls() {

    registerProcedures(asList(
            Help.class,
            Json.class,
            LoadJson.class,
            Xml.class,
            PathExplorer.class,
            Meta.class)
    );
    Session session = sessionFactory.openSession();
    Result result = session.query("CALL apoc.help('apoc')", ImmutableMap.of());
0
On

You have to register them manually with your GraphDatabaseService.

See here for an example: https://github.com/neo4j-contrib/rabbithole/blob/3.0/src/main/java/org/neo4j/community/console/Neo4jService.java#L55

0
On

With the release of neo4j 4.0 some things have changed (noticeably Procedures vs GlobalProcedures), and that's why I want to share my solution.

I wanted to setup embedded neo4j along with neo4j for test purposes and here are the results:

  1. For some reason when including apoc from maven repository there were missing classes (e.g. apoc.util package contained only one class instead of ~20, also there were missing apoc.coll.Coll functions).

In order to fix that I had to use this answer: Compile Jar from Url in Gradle

and then in my dependencies block I've included

    testImplementation(urlFile("https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/4.1.0.0/apoc-4.1.0.0-all.jar", "neo4j-apoc"))
  1. Once you have all the classes register whatever you need, in my case I'm registering only Coll functions:

EmbeddedNeo4jDriver.kt

val managementService = org.neo4j.dbms.api.DatabaseManagementServiceBuilder(TestConfiguration.Neo4j.directory)
       .setConfig(BoltConnector.enabled, true)
       .setConfig(BoltConnector.listen_address, SocketAddress(TestConfiguration.Neo4j.hostname, TestConfiguration.Neo4j.port))
       .build()
   

managementService.listDatabases().first()
       .let(managementService::database)
       .let { it as org.neo4j.kernel.internal.GraphDatabaseAPI }
       .dependencyResolver
       .resolveDependency(org.neo4j.kernel.api.procedure.GlobalProcedures::class.java)
       .registerFunction(apoc.coll.Coll::class.java)