Java Neo4j写入性能下降
我在我的应用程序中试用了一段时间neo4j-2.1.2企业评估版本。我听说neo4j具有在几秒钟内插入100万个节点的巨大能力。被这样的吹捧迷住了,我决定把它付诸行动。最初,插入10000个节点需要4秒钟。随着图形数据库中节点数量的增加,我开始看到写入性能有所下降。插入60000个节点需要60秒,时间呈指数级增长。我无法找出这种退化背后的原因。我试着用谷歌搜索,但找不到多少信息 规格如下:Java Neo4j写入性能下降,java,neo4j,Java,Neo4j,我在我的应用程序中试用了一段时间neo4j-2.1.2企业评估版本。我听说neo4j具有在几秒钟内插入100万个节点的巨大能力。被这样的吹捧迷住了,我决定把它付诸行动。最初,插入10000个节点需要4秒钟。随着图形数据库中节点数量的增加,我开始看到写入性能有所下降。插入60000个节点需要60秒,时间呈指数级增长。我无法找出这种退化背后的原因。我试着用谷歌搜索,但找不到多少信息 规格如下: * Application heap = 10 GB * ConcurrentMaxSweep
* Application heap = 10 GB
* ConcurrentMaxSweep GC
* Neo4J cache type = hpc
* Each node will have at most 4 properties
* uniqueKey property on the node is indexed.
* Everything else in neo4j properties left to default
* 8 core processor machine.
有人能指导我解决这个性能问题吗??我正在使用java核心API创建节点
更新请在下面找到我的代码
public class GraphDatabaseManager
{
private static final Logger logger = Logger.getLogger(GraphDatabaseManager.class);
private GraphDatabaseService graphDb;
private Index<org.neo4j.graphdb.Node> nodeIndex;
private UniqueFactory<org.neo4j.graphdb.Node> factory;
private Index<org.neo4j.graphdb.Relationship> relationShipIndex;
private static final String PROPERTY_FILE = "conf" + File.separator + "graphDB" + File.separator + "Neo4j.properties";
private static final String UNIQUE_KEY = GraphEntity.UNIQUE_KEY;
private static final String NODES = "nodes";
private static final String RELATIONSHIPS = "relationships";
private void init(Map<String, String> props)
{
graphDb = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(props.remove(GraphDBManager.DB_PATH))
.loadPropertiesFromFile(PROPERTY_FILE)
.setConfig(ShellSettings.remote_shell_enabled, props.get(GraphDBManager.REMOTE_SHELL_ENABLED))
.setConfig(ShellSettings.remote_shell_host, props.get(GraphDBManager.REMOTE_SHELL_HOST))
.setConfig(ShellSettings.remote_shell_port, props.get(GraphDBManager.REMOTE_SHELL_PORT))
.setConfig(ShellSettings.remote_shell_read_only, props.get(GraphDBManager.REMOTE_SHELL_READ_ONLY)).newGraphDatabase();
Transaction transaction = graphDb.beginTx();
nodeIndex = graphDb.index().forNodes(NODES);
factory = new UniqueNodeFactory(graphDb, NODES)
{
@Override
protected void initialize(org.neo4j.graphdb.Node node, Map<String, Object> props)
{
}
};
relationShipIndex = graphDb.index().forRelationships(RELATIONSHIPS);
transaction.success();
transaction.close();
}
public <T extends Node> void createNodes(List<T> nodes) throws Exception
{
if (CommonUtils.isCollectionNullOrEmpty(nodes))
throw new IllegalArgumentException("Nodes cannot be Empty while Creating");
List<List<T>> nodeLists = CommonUtils.split(nodes, getNodeBatchSize());
for (List<T> list : nodeLists)
{
try
{
createOrUpdateNodes0(list, true);
}
catch (Exception e)
{
throw e;
}
}
}
private Integer getNodeBatchSize()
{
return Integer.getInteger("NODES_BATCH_SIZE", 1000);
}
private void createOrUpdateNodes0(List<? extends Node> nodes, boolean isCreate) throws Exception
{
org.neo4j.graphdb.Transaction transaction = graphDb.beginTx();
try
{
for (Node node : nodes)
{
if (node == null)
continue;
saveOrUpdateNode(node, isCreate);
}
transaction.success();
}
catch (Exception e)
{
transaction.failure();
throw new Exception("Exception while storing nodes for ", e);
}
finally
{
transaction.close();
}
}
protected void saveOrUpdateNode(Node node, boolean isCreate) throws Exception
{
String uniqueKey = node.getUniqueKey();
try
{
org.neo4j.graphdb.Node neoNode = null;
boolean isNodeExist = isNodeExist(uniqueKey);
if (isCreate)
{
if (isNodeExist)
{
if (logger.isTraceEnabled())
logger.trace(" Node already Exists.....Returning the same..." + node);
return;
}
neoNode = factory.getOrCreate(UNIQUE_KEY, uniqueKey);
nodeIndex.add(neoNode, UNIQUE_KEY, uniqueKey);
if (logger.isTraceEnabled())
logger.trace(" NeoNode created Successfully..." + uniqueKey);
}
else
{
if (!isNodeExist)
return;
neoNode = getNeoNode(uniqueKey);
}
for (Entry<String, Object> neoProps : node.getProperties().entrySet())
{
if (neoProps.getValue() != null)
neoNode.setProperty(neoProps.getKey(), neoProps.getValue());
}
}
catch (Exception e)
{
throw new Exception("Exception while creating NeoNode with Unique key " + uniqueKey, e);
}
}
protected boolean isNodeExist(String uniqueKey)
{
return nodeIndex.get(UNIQUE_KEY, uniqueKey).hasNext();
}
protected void addNodeIndex(Node node, String column, Object value)
{
org.neo4j.graphdb.Node neoNode = getNeoNode(node.getUniqueKey());
nodeIndex.add(neoNode, column, value);
}
private org.neo4j.graphdb.Node getNeoNode(String uniqueKey)
{
return (uniqueKey != null) ? nodeIndex.get(UNIQUE_KEY, uniqueKey).getSingle() : null;
}
public <T extends Relationship> void createRelationships(List<T> relationships) throws Exception
{
if (CommonUtils.isCollectionNullOrEmpty(relationships))
throw new IllegalArgumentException("Relationships cannot be Empty while Creating");
List<List<T>> relationshipLists = CommonUtils.split(relationships, getRelationBatchSize());
for (List<T> relationshiplist : relationshipLists)
{
try
{
createOrUpdateRelationships0(relationshiplist, true);
}
catch (Exception e)
{
throw e;
}
}
}
private Integer getRelationBatchSize()
{
return Integer.getInteger("RELATIONSHIP_BATCH_SIZE", 1000);
}
private void createOrUpdateRelationships0(List<? extends Relationship> relationShips, boolean isCreate) throws Exception
{
org.neo4j.graphdb.Transaction transaction = graphDb.beginTx();
try
{
for (Relationship relationship : relationShips)
{
if (relationship == null)
continue;
saveOrUpdateRelationship(relationship, isCreate);
Entity relationshipEntity = GraphObjectManager.getRelationshipClz(relationship.getType());
if (relationshipEntity == null)
throw new Exception(" Could not find Entity for relationShip :: " + relationship.getType());
Indexedcolumns indexedcolumns = relationshipEntity.getIndexedcolumns();
if (indexedcolumns != null)
{
for (String index : indexedcolumns.getIndex())
{
Object value = relationship.getProperty(index);
addRelationshipIndex(relationship, index, value);
}
}
}
transaction.success();
}
catch (Exception e)
{
transaction.failure();
throw e;
}
finally
{
transaction.close();
}
}
protected void saveOrUpdateRelationship(Relationship relationShip, boolean isCreate) throws Exception
{
String uniqueKey = relationShip.getUniqueKey();
try
{
org.neo4j.graphdb.Relationship neoRelationShip = null;
boolean isRelationshipExist = isRelationshipExist(uniqueKey);
if (isCreate)
{
if (isRelationshipExist)
{
if (logger.isTraceEnabled())
logger.trace(" RelationShip already Exists.....Returning the same..." + relationShip);
return;
}
org.neo4j.graphdb.Node neoStartNode = getNeoNode(relationShip.getStartNodeUniqueKey());
org.neo4j.graphdb.Node neoEndNode = getNeoNode(relationShip.getEndNodeUniqueKey());
validateRelationshipNodes(relationShip, neoStartNode, neoEndNode);
neoRelationShip = neoStartNode.createRelationshipTo(neoEndNode, new Neo4jRelationshipType(relationShip.getType()));
relationShipIndex.add(neoRelationShip, UNIQUE_KEY, uniqueKey);
if (logger.isTraceEnabled())
logger.trace(" NeoRelationship created Successfully..." + uniqueKey);
}
else
{
if (!isRelationshipExist)
return;
neoRelationShip = getNeoRelationship(uniqueKey);
}
for (Entry<String, Object> relProps : relationShip.getProperties().entrySet())
{
if (relProps.getValue() == null)
continue;
neoRelationShip.setProperty(relProps.getKey(), relProps.getValue());
}
}
catch (Exception e)
{
throw new Exception("Exception while creating NeoRelationShip with Unique key " + relationShip.getUniqueKey(), e);
}
}
protected boolean isRelationshipExist(String uniqueKey)
{
return relationShipIndex.get(UNIQUE_KEY, uniqueKey).hasNext();
}
private org.neo4j.graphdb.Relationship getNeoRelationship(String uniqueKey)
{
return (uniqueKey != null) ? relationShipIndex.get(UNIQUE_KEY, uniqueKey).getSingle() : null;
}
private void validateRelationshipNodes(Relationship relationShip, org.neo4j.graphdb.Node neoStartNode, org.neo4j.graphdb.Node neoEndNode)
throws Exception
{
if (neoStartNode == null && neoEndNode == null)
{
throw new Exception("Start Node and End Node is not present in DB " + "for relationship " + relationShip);
}
else if (neoStartNode == null)
{
throw new Exception("Start Node is not present in DB " + "for relationship " + relationShip);
}
else if (neoEndNode == null)
{
throw new Exception("End Node is not present in DB " + "for relationship " + relationShip);
}
}
protected void addRelationshipIndex(Relationship relationship, String column, Object value)
{
org.neo4j.graphdb.Relationship neoRelationship = getNeoRelationship(relationship.getUniqueKey());
relationShipIndex.add(neoRelationship, column, value);
}
}
公共类GraphDatabaseManager
{
私有静态最终记录器Logger=Logger.getLogger(GraphDatabaseManager.class);
专用GraphDatabaseService graphDb;
私有索引节点索引;
私人专用工厂;
私有索引关系索引;
私有静态最终字符串属性_FILE=“conf”+FILE.separator+“graphDB”+FILE.separator+“Neo4j.properties”;
私有静态最终字符串UNIQUE\u KEY=GraphEntity.UNIQUE\u KEY;
私有静态最终字符串NODES=“NODES”;
私有静态最终字符串关系=“关系”;
私有void init(地图道具)
{
graphDb=new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(props.remove(GraphDBManager.DB_PATH))
.loadPropertiesFromFile(属性文件)
.setConfig(ShellSettings.remote_shell_启用,props.get(GraphDBManager.remote_shell_启用))
.setConfig(ShellSettings.remote_shell_host,props.get(GraphDBManager.remote_shell_host))
.setConfig(ShellSettings.remote_shell_端口,props.get(GraphDBManager.remote_shell_端口))
.setConfig(ShellSettings.remote_shell_read_only,props.get(GraphDBManager.remote_shell_read_only)).newGraphDatabase();
事务事务=graphDb.beginTx();
nodeIndex=graphDb.index().forNodes(节点);
工厂=新的UniqueNodeFactory(graphDb,节点)
{
@凌驾
受保护的void初始化(org.neo4j.graphdb.Node节点,地图道具)
{
}
};
relationShipIndex=graphDb.index()。用于关系(RELATIONSHIPS);
transaction.success();
transaction.close();
}
公共void createNodes(列表节点)引发异常
{
if(CommonUtils.isCollectionNullOrEmpty(节点))
抛出新的IllegalArgumentException(“创建时节点不能为空”);
List nodeLists=CommonUtils.split(节点,getNodeBatchSize());
用于(列表:节点列表)
{
尝试
{
createOrUpdateNodes0(列表,true);
}
捕获(例外e)
{
投掷e;
}
}
}
私有整数getNodeBatchSize()
{
返回Integer.getInteger(“NODES\u BATCH\u SIZE”,1000);
}
私有void createOrUpdateNodes0(列表请共享导入代码查看:共享导入代码。基本上,我认为您不只是创建新节点,而是在创建之前执行一些未优化的逻辑,如与其他节点的匹配关系。因此,您已经创建的节点越多,创建新节点所需的时间就越长,因为它必须首先计算所有以前节点上的逻辑除了同意需要共享导入代码之外,还有许多其他考虑因素。您是否使用标签?传统索引?是否设置了唯一性约束?如何接收插入的原始数据(大批量或逐个)?您是使用Neo API创建这些节点还是使用Cypher创建/合并?这里给我们一个提示!Neo4j可以在非事务批插入模式下每秒导入1M个节点。请查看批插入器API,您可能希望在前期过程中注意唯一性。