
org.wowtools.neo4j.rtree.internal.edit.TxCell Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-rtree Show documentation
Show all versions of neo4j-rtree Show documentation
a spatial index for neo4j 4.x.
The newest version!
package org.wowtools.neo4j.rtree.internal.edit;
import org.neo4j.graphdb.*;
import org.wowtools.neo4j.rtree.internal.define.Labels;
import org.wowtools.neo4j.rtree.internal.define.Relationships;
import org.wowtools.neo4j.rtree.internal.edit.CacheNode;
import org.wowtools.neo4j.rtree.internal.edit.NodeOfAxialSplitLeaf;
import org.wowtools.neo4j.rtree.internal.edit.NodeOfBranch;
import org.wowtools.neo4j.rtree.internal.edit.RectBuilder;
import org.wowtools.neo4j.rtree.pojo.RectNd;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 事务外壳,用于在构建rtree时获取事务
* 注意,此对象非线程安全
*
* @author liuyu
* @date 2021/12/17
*/
public class TxCell {
private Transaction tx;
private final int limit;
private final int mMin;
private final int mMax;
private final GraphDatabaseService graphDb;
private int num;
private final RectBuilder builder = new RectNd.Builder();
private final Map cacheNodeMap = new HashMap<>();
private final Map nodeParentMap = new HashMap<>();
public CacheNode getNode(long nodeId) {
CacheNode cacheNode = cacheNodeMap.get(nodeId);
if (null != cacheNode) {
return cacheNode;
}
org.neo4j.graphdb.Node noeNode = getTx().getNodeById(nodeId);
String labelName = noeNode.getLabels().iterator().next().name();
if (labelName.equals(Labels.RTREE_BRANCH.name())) {
cacheNode = new CacheNode(nodeId, this, CacheNode.NodeType.Branch);
} else if (labelName.equals(Labels.RTREE_LEAF.name())) {
cacheNode = new CacheNode(nodeId, this, CacheNode.NodeType.Branch);
} else {
throw new RuntimeException("label错误: " + labelName + " id: " + noeNode);
}
cacheNodeMap.put(nodeId, cacheNode);
return cacheNode;
}
public CacheNode newNode(Label label) {
org.neo4j.graphdb.Node node = tx.createNode(label);
CacheNode.NodeType nodeType;
if (label == Labels.RTREE_BRANCH) {
nodeType = CacheNode.NodeType.Branch;
} else if (label == Labels.RTREE_LEAF) {
nodeType = CacheNode.NodeType.Leaf;
} else {
throw new RuntimeException("未知label " + label.name());
}
CacheNode cacheNode = new CacheNode(node.getId(), this, nodeType);
cacheNodeMap.put(node.getId(), cacheNode);
return cacheNode;
}
public void setNodeParent(Long nodeId, Long parentNodeId) {
nodeParentMap.put(nodeId, parentNodeId);
}
public org.wowtools.neo4j.rtree.internal.edit.Node getNodeFromNeo4j(long nid) {
org.neo4j.graphdb.Node node = getTx().getNodeById(nid);
String labelName = node.getLabels().iterator().next().name();
if (labelName.equals(Labels.RTREE_BRANCH.name())) {
return NodeOfBranch.getFromNeo(getBuilder(), nid, this);
} else if (labelName.equals(Labels.RTREE_LEAF.name())) {
return NodeOfAxialSplitLeaf.getFromNeo(getBuilder(), nid, this);
} else {
throw new RuntimeException("未知标签 " + labelName);
}
}
public TxCell(int limit,int mMin, int mMax, GraphDatabaseService graphDb) {
this.limit = limit;
this.mMin = mMin;
this.mMax = mMax;
this.graphDb = graphDb;
tx = newTx();
}
public RectBuilder getBuilder() {
return builder;
}
protected Transaction _newTx() {
return graphDb.beginTx();
}
public Transaction newTx() {
tx = _newTx();
return tx;
}
public Transaction getTx() {
return tx;
}
public void addChange() {
num++;
}
public void addChange(int n) {
num += n;
}
public boolean limitCommit() {
if (num >= limit) {
commit();
newTx();
return true;
}
return false;
}
public void commit() {
//各cacheNode属性提交
cacheNodeMap.forEach((nid, cacheNode) -> {
cacheNode.commit();
});
//RTREE_PARENT_TO_CHILD关系变更
nodeParentMap.forEach((nid, parentNid) -> {
if (null == parentNid) {//parentNid为空,删除旧关系
for (Relationship relationship : tx.getNodeById(nid).getRelationships(Direction.INCOMING, Relationships.RTREE_PARENT_TO_CHILD)) {
relationship.delete();
}
} else {//parentNid非空,修改关系
boolean hasRelationship = false;//新的关系是否已存在
for (Relationship relationship : tx.getNodeById(nid).getRelationships(Direction.INCOMING, Relationships.RTREE_PARENT_TO_CHILD)) {
if (hasRelationship) {
relationship.delete();
} else {
if (parentNid == relationship.getStartNodeId()) {
hasRelationship = true;
} else {
relationship.delete();
}
}
}
if (!hasRelationship) {
tx.getNodeById(parentNid).createRelationshipTo(tx.getNodeById(nid), Relationships.RTREE_PARENT_TO_CHILD);
}
}
});
neoGc();//gc
tx.commit();//提交neo4j事务
//清理内存中的对象
num = 0;
cacheNodeMap.forEach((nid, cacheNode) -> {
cacheNode.clearCache();
});
cacheNodeMap.clear();
nodeParentMap.clear();
}
/**
* 做一次“gc”操作,把cacheNodeMap中没有引用的node及其子节点从数据库删除掉
*/
private void neoGc() {
cacheNodeMap.forEach((id, n) -> {
org.neo4j.graphdb.Node node;
try {
node = tx.getNodeById(id);
} catch (NotFoundException e) {
//node已在前面的遍历中被删除,跳过
return;
}
org.neo4j.graphdb.Node thisRoot = node;
ArrayDeque stack = new ArrayDeque<>();
stack.push(node.getId());
boolean findRoot = false;
do {
try {
node = tx.getNodeById(stack.pop());
} catch (NotFoundException e) {
continue;
}
//检查是否有关系 RTREE_METADATA_TO_ROOT
Iterator iterator = node.getRelationships(Direction.INCOMING, Relationships.RTREE_METADATA_TO_ROOT).iterator();
if (iterator.hasNext()) {
findRoot = true;
break;
}
//将父节点丢进栈继续
for (Relationship relationship : node.getRelationships(Direction.INCOMING, Relationships.RTREE_PARENT_TO_CHILD)) {
org.neo4j.graphdb.Node parent = relationship.getStartNode();
thisRoot = parent;
stack.push(parent.getId());
}
} while (!stack.isEmpty());
//未找到根节点,则删除所有本次遍历过的设备
if (!findRoot) {
stack = new ArrayDeque<>();
stack.push(thisRoot.getId());
do {
try {
node = tx.getNodeById(stack.pop());
} catch (NotFoundException e) {
continue;
}
//遍历子节点
for (Relationship relationship : node.getRelationships(Direction.OUTGOING, Relationships.RTREE_PARENT_TO_CHILD)) {
org.neo4j.graphdb.Node parent = relationship.getStartNode();
thisRoot = parent;
stack.push(parent.getId());
}
//删除父节点及关系
for (Relationship r : node.getRelationships()) {
r.delete();
}
node.delete();
} while (!stack.isEmpty());
}
});
}
public void close() {
tx.close();
}
public int getmMin() {
return mMin;
}
public int getmMax() {
return mMax;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy