我使用具有近 50 万个节点的 Neo4J 数据库。当我启动我的 Spring 应用程序并执行第一个查询时,大约需要 4-5 秒。这只发生在第一个查询中,所以我想我可以在 spring 初始化后进行预热,以使所有后续查询更快。
这是我的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">
<!-- neo4j database -->
<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>
我看到等待 Spring bean 初始化的一种方法是实现 ApplicationListener
,而使用 Neo 预热数据库的常规方法是调用 apoc.runtime.warmup( )
函数,所以我做了如下操作:
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.");
}
}
这个没有用,一切都被正确记录,但第一个 neo4j 查询仍然很慢。
由于这种方法不起作用,我编辑了 executeTestSelect
方法来运行一个真正的查询并像这样处理结果:
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.");
}
这次启动需要 4-5 秒来执行查询,但随后会打印
Neo4j cache done. Processed 0 nodes.
这很奇怪,因为在应用程序完全初始化时运行的完全相同的查询返回 450k 个节点。
我错过了什么?是否有可能在到达 onApplicationEvent
时 Neo4j DB 尚未初始化并且无法执行查询?
如何在完成 spring 应用程序初始化后立即正确预热 neo4j 数据库?
最佳答案
好吧,我发现这个纯粹是运气。
我删除了 ApplicationListener
并在执行预热的方法上创建了一个带有 @Autowired
注释的 @Service
类,它似乎正在工作。
我通过删除一个类字段而没有看到留在此处的 @Autowired
注释发现了这一点,并且它起作用了。我试了几次,热身现在开始起作用了。我不知道它是否记录在 Spring 文档的某处。
这是我的最后一个类:
package com.app.components;
@Component
public class Neo4jWarmup {
private static final Logger LOG = LogManager.getLogger(StartupTasks.class);
@Autowired
GraphDatabaseService db;
/*
* this did the trick - the method gets called
* after Spring initialization and the DB works as expected
*/
@Autowired
public void neo4jWarmup() {
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.");
}
}
关于java - spring 初始化后预热 Neo4j 数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44347483/