I am using a Neo4J database with nearly 500k nodes. When I launch the Spring application and execute the first request, it takes about 4-5 seconds. This only happens for the first request, so I thought I could do a warm-up after initializing Spring to make all subsequent requests faster.
This is my applicationContext.xml :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <util:map id="config"> <entry key="enable_remote_shell" value="false" /> </util:map> <bean id="graphDbFactory" class="org.neo4j.graphdb.factory.GraphDatabaseFactory" /> <bean id="graphDbBuilder" factory-bean="graphDbFactory" factory-method="newEmbeddedDatabaseBuilder"> <constructor-arg value="/path/to/db" /> </bean> <bean id="graphDbBuilderFinal" factory-bean="graphDbBuilder" factory-method="setConfig"> <constructor-arg ref="config" /> </bean> <bean id="graphDatabaseService" factory-bean="graphDbBuilderFinal" factory-method="newGraphDatabase" destroy-method="shutdown" class="org.neo4j.graphdb.GraphDatabaseService"/> <context:component-scan base-package="com.app.components" /> </beans>
I saw that one of the ways to wait for Spring beans to initialize was to implement ApplicationListener , and the regular way to defrost a database using Neo was to call apoc.runtime.warmup() , so I did the following
package com.app.components; @Component public class StartupTasks implements ApplicationListener<ContextRefreshedEvent> { private static final Logger LOG = LogManager.getLogger(StartupTasks.class); @Autowired GraphDatabaseService db; @Override public void onApplicationEvent(ContextRefreshedEvent event) { executeTestSelect(); } private void executeTestSelect() { LOG.info("Warming up Neo4j..."); Transaction tx = db.beginTx(); db.execute("CALL apoc.warmup.run()"); tx.close(); LOG.info("Warmup complete."); } }
This does not work, everything is logged correctly, but the first neo4j request is still slow.
Since this approach did not work, I edited the executeTestSelect to run the real query and process the results as follows:
private void executeTestSelect() { String textToSearch = "a"; // returns almost all nodes, should make neo4j cache them all Transaction tx = db.beginTx(); Map<String, Object> params = new HashMap<String, Object>(); params.put("textToSearch", textToSearch ); Result resultSet = db.execute("MATCH (n:PROD) WHERE n.description CONTAINS {textToSearch} RETURN n", params); Iterator<Node> results = resultSet.columnAs("n"); int count = 0; while (results.hasNext()) { results.next(); count++: } tx.close(); LOG.info("Neo4j cache done. Processed " + count + " nodes."); }
This time, the launch takes 4-5 seconds to complete the request, but then it prints
Completed Neo4j cache. Processed 0 nodes.
This is strange, because the same request is launched when the application is fully initialized, it returns 450 thousand nodes.
What am I missing? Is it possible that upon reaching onApplicationEvent , the Neo4j database is not yet initialized and cannot complete queries?
How to warm up the neo4j database right after the Spring application is fully initialized?