You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fu-hsi-service/src/main/java/com/supervision/neo4j/service/impl/Neo4jServiceImpl.java

632 lines
27 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.supervision.neo4j.service.impl;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.supervision.common.domain.R;
import com.supervision.neo4j.domain.CaseNode;
import com.supervision.neo4j.domain.Rel;
import com.supervision.neo4j.dto.WebRelDTO;
import com.supervision.neo4j.service.Neo4jService;
import com.supervision.neo4j.utils.Neo4jUtils;
import com.supervision.police.vo.GraphReqVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.neo4j.driver.Record;
import org.neo4j.driver.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author qmy
* @since 2023-10-26
*/
@Slf4j
@Service
public class Neo4jServiceImpl implements Neo4jService {
private final Driver driver;
@Autowired
private Neo4jServiceImpl(Driver driver) {
this.driver = driver;
}
@Override
public CaseNode save(CaseNode caseNode) {
if (StringUtils.isEmpty(caseNode.getName()) || StringUtils.isEmpty(caseNode.getNodeType())) {
throw new RuntimeException("未传节点名称或节点类型或图谱类型!");
}
List<CaseNode> byName = findByName(caseNode.getCaseId(), caseNode.getRecordId(), caseNode.getNodeType(), caseNode.getName(), caseNode.getPicType());
if (byName != null && !byName.isEmpty()) {
throw new RuntimeException("名称已存在!");
}
CaseNode res = null;
try {
Session session = driver.session();
StringBuilder cql = new StringBuilder();
Map<String, Object> params = new HashMap<>();
cql.append("CREATE (n:").append(caseNode.getNodeType()).append("{name:$name");
params.put("name", caseNode.getName());
if (StringUtils.isNotEmpty(caseNode.getRecordId())) {
cql.append(", recordSplitId:$recordSplitId");
params.put("recordSplitId", caseNode.getRecordSplitId());
}
if (StringUtils.isNotEmpty(caseNode.getRecordId())) {
cql.append(", recordId:$recordId");
params.put("recordId", caseNode.getRecordId());
}
if (StringUtils.isNotEmpty(caseNode.getCaseId())) {
cql.append(", caseId:$caseId");
params.put("caseId", caseNode.getCaseId());
}
if (StringUtils.isNotEmpty(caseNode.getPicType())) {
cql.append(", picType:$picType");
params.put("picType", caseNode.getPicType());
}
cql.append("})").append(Neo4jUtils.NODE_RETURN);
Result run = session.run(cql.toString(), params);
res = Neo4jUtils.getOneNode(run);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return res;
}
/**
* 删除节点,注意,删除节点的时候,要先把边删除掉,不然会报错
*
* @param id 点的ID
*/
@Override
public void delNode(Long id) {
try {
Session session = driver.session();
StringBuilder cql = new StringBuilder();
cql.append("MATCH (n) where id(n) = ").append(id).append(" DELETE n");
log.info(cql.toString());
Result run = session.run(cql.toString());
while (run.hasNext()) {
run.next();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
@Override
public void deleteNoRelationNode(Long id) {
try {
Session session = driver.session();
StringBuilder cql = new StringBuilder();
cql.append("MATCH (n) WHERE n.id = ").append(id).append(" AND NOT (n)--() DELETE n");
log.info(cql.toString());
Result run = session.run(cql.toString());
while (run.hasNext()) {
run.next();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 删除边
*
* @param relId 边ID
*/
public void deleteRel(Long relId) {
try {
Session session = driver.session();
StringBuilder cql = new StringBuilder();
cql.append("MATCH ()-[r]->() WHERE id(r) = ").append(relId).append(" DELETE r");
log.info(cql.toString());
Result run = session.run(cql.toString());
while (run.hasNext()) {
run.next();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
@Override
public CaseNode findById(Long id) {
CaseNode node = null;
try {
Session session = driver.session();
Result run = session.run("MATCH (n) where id(n) = " + id + Neo4jUtils.NODE_RETURN);
node = Neo4jUtils.getOneNode(run);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return node;
}
@Override
public List<CaseNode> findByName(String caseId, String recordId, String nodeType, String name, String picType) {
List<CaseNode> list = new ArrayList<>();
try {
Session session = driver.session();
StringBuilder cql = new StringBuilder();
cql.append("MATCH (n");
if (StringUtils.isNotEmpty(nodeType)) {
cql.append(":");
cql.append(nodeType);
}
cql.append(") where 1 = 1");
if (StringUtils.isNotEmpty(caseId)) {
cql.append(" and n.caseId = ");
cql.append(caseId);
}
if (StringUtils.isNotEmpty(recordId)) {
cql.append(" and n.recordId = ");
cql.append(recordId);
}
if (StringUtils.isNotEmpty(name)) {
cql.append(" and n.name = '");
cql.append(name);
cql.append("'");
}
if (StringUtils.isNotEmpty(picType)) {
cql.append(" and n.picType = ");
cql.append(picType);
}
cql.append(Neo4jUtils.NODE_RETURN);
Result run = session.run(cql.toString());
list = Neo4jUtils.getNodeList(run);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return list;
}
@Override
public CaseNode findOneByName(String caseId, String recordId, String nodeType, String name, String picType) {
CaseNode node = null;
try {
Session session = driver.session();
StringBuilder cql = new StringBuilder();
Map<String, Object> params = new HashMap<>();
cql.append("MATCH (n");
if (StringUtils.isNotEmpty(nodeType)) {
cql.append(":");
cql.append(nodeType);
}
cql.append(") where 1 = 1");
if (StringUtils.isNotEmpty(caseId)) {
cql.append(" and n.caseId = $caseId");
params.put("caseId", caseId);
}
if (StringUtils.isNotEmpty(recordId)) {
cql.append(" and n.recordId = $recordId");
params.put("recordId", recordId);
}
if (StringUtils.isNotEmpty(name)) {
cql.append(" and n.name = $name");
params.put("name", name);
}
if (StringUtils.isNotEmpty(picType)) {
cql.append(" and n.picType = $picType");
params.put("picType", picType);
}
cql.append(Neo4jUtils.NODE_RETURN);
Result run = session.run(cql.toString(), params);
node = Neo4jUtils.getOneNode(run);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return node;
}
@Override
public Rel findRelation(Rel rel) {
try {
Session session = driver.session();
Map<String, Object> params = new HashMap<>();
String cql = "MATCH (a)-[rel:" + rel.getName() + "]->(b) where id(a) = $sourceId and id(b) = $targetId" +
Neo4jUtils.REL_RETURN;
params.put("sourceId", rel.getSourceId());
params.put("targetId", rel.getTargetId());
Result run = session.run(cql, params);
rel = Neo4jUtils.getOneRel(run);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
if (rel != null && rel.getId() != null) {
return rel;
} else {
return null;
}
}
@Override
public Rel saveRelation(Rel rel) {
try {
Session session = driver.session();
Map<String, Object> params = new HashMap<>();
String cql = "MATCH (a), (b) where id(a) = $sourceId and id(b) = $targetId CREATE(a)-[rel:" + rel.getName() +
"]->(b) " + Neo4jUtils.REL_RETURN;
params.put("sourceId", rel.getSourceId());
params.put("targetId", rel.getTargetId());
Result run = session.run(cql, params);
rel = Neo4jUtils.getOneRel(run);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return rel;
}
@Override
public R<?> getCaseGraph(GraphReqVO graphReqVO) {
Map<String, Object> map = new HashMap<>();
List<WebRelDTO> list = new ArrayList<>();
List<Map<String, String>> nodes = new ArrayList<>();
List<Map<String, String>> labelColorMap = graphReqVO.getNodeLabelColorMap();
try {
Session session = driver.session();
StringBuilder relQuery = new StringBuilder("MATCH (n)-[rel]->(m) " +
"WHERE n.picType = $picType " +
"AND n.caseId = $caseId ");
Map<String, Object> params = new HashMap<>();
params.put("picType", graphReqVO.getPicType());
params.put("caseId", graphReqVO.getCaseId());
if (StringUtils.isNotEmpty(graphReqVO.getQueryStr())) {
params.put("queryStr", graphReqVO.getQueryStr());
relQuery.append("AND (n.name CONTAINS $queryStr OR type(rel) CONTAINS $queryStr OR m.name CONTAINS $queryStr) ");
}
if (graphReqVO.getNodeLabels() != null && !graphReqVO.getNodeLabels().isEmpty()) {
params.put("nodeLabels", graphReqVO.getNodeLabels());
relQuery.append("AND (ANY(label IN $nodeLabels WHERE label IN labels(n)) " +
"OR ANY(label IN $nodeLabels WHERE label IN labels(m))) ");
}
if (graphReqVO.getRelTypes() != null && !graphReqVO.getRelTypes().isEmpty()) {
params.put("relTypes", graphReqVO.getRelTypes());
relQuery.append("AND ANY(type IN $relTypes WHERE type = type(rel)) ");
}
relQuery.append("RETURN id(rel) as id, n.name as source, id(n) as sourceId, n.name as sourceName, type(rel) as relName, m.name as target, id(m) as targetId, m.name as targetName, labels(n) as sourceLabels, labels(m) as targetLabels");
log.info("relQuery:{}", relQuery);
Result run = session.run(relQuery.toString(), params);
while (run.hasNext()) {
Record record = run.next();
List<String> sourceLabels = record.get("sourceLabels").asList(Value::asString);
List<String> targetLabels = record.get("targetLabels").asList(Value::asString);
if (sourceLabels == null || sourceLabels.isEmpty() || targetLabels == null || targetLabels.isEmpty()) {
log.info("节点标签为空,跳过");
continue;
}
// 组织边
long sourceId = record.get("sourceId").asLong();
String relName = record.get("relName").asString();
long targetId = record.get("targetId").asLong();
list.add(new WebRelDTO(sourceId, targetId, relName));
// 组织节点
Map<String, String> sourceNodeMap = new HashMap<>();
sourceNodeMap.put("name", record.get("sourceName").asString());
setNodeIdAndColor(nodes, labelColorMap, sourceLabels, sourceId, sourceNodeMap);
Map<String, String> targetNodeMap = new HashMap<>();
targetNodeMap.put("name", record.get("targetName").asString());
setNodeIdAndColor(nodes, labelColorMap, targetLabels, targetId, targetNodeMap);
}
} catch (Exception e) {
log.error("查询失败", e);
}
// 根据节点ID去重
List<Map<String, String>> distinctNodes = new ArrayList<>(nodes.stream()
.collect(Collectors.toMap(
node -> node.get("id"), // 以 ID 为唯一键
node -> node, // 保留整个 Map 作为值
(existing, replacement) -> existing)) // 如果有重复 ID保留第一个
.values());
// 节点和关系合并
Pair<List<WebRelDTO>, List<Map<String, String>>> pair = mergeRecord(distinctNodes, list);
// 将返回结果List<Map<String, String>>转为Map<String, Object>并将其中key为color的键值对包一层itemStyle将键值对放在里面
List<Map<String, Object>> nodesList = new ArrayList<>();
for (Map<String, String> node : pair.getValue()) {
Map<String, String> itemStyle = new HashMap<>();
itemStyle.put("color", node.get("color"));
Map<String, Object> nodeMap = new HashMap<>();
nodeMap.put("name", node.get("name"));
nodeMap.put("id", node.get("id"));
nodeMap.put("itemStyle", itemStyle);
nodesList.add(nodeMap);
}
map.put("list", pair.getKey());
map.put("nodes", nodesList);
return R.ok(map);
}
private void setNodeIdAndColor(List<Map<String, String>> nodes, List<Map<String, String>> labelColorMap, List<String> labels, long id, Map<String, String> nodeMap) {
nodeMap.put("id", String.valueOf(id));
for (Map<String, String> labelColor : labelColorMap) {
if (labels.contains(labelColor.get("name"))) {
nodeMap.put("color", labelColor.get("color"));
break;
}
}
if (!nodeMap.containsKey("color")) {
log.error("节点【{}】没有颜色,随机生成", nodeMap.get("name"));
nodeMap.put("color", Neo4jUtils.getRandomColorPair()[0]);
}
nodes.add(nodeMap);
}
public Pair<List<WebRelDTO>, List<Map<String, String>>> mergeRecord(List<Map<String, String>> nodes, List<WebRelDTO> relDTOS) {
Map<String, NodeMapRecord> nodeRecordMap = electNodeRecord(nodes);
return Pair.of(mergerWebRel(relDTOS, nodeRecordMap), mergeNode(nodes, nodeRecordMap));
}
@Override
public R<?> getNodeAndRelationListByCaseId(String picType, String caseId) {
Map<String, Object> map = new HashMap<>();
Set<String> nodeLabels = new HashSet<>();
Set<String> relTypes = new HashSet<>();
try (Session session = driver.session()) {
// 查询所有匹配caseId的节点及其关联关系
String query = "MATCH (n)-[r]->(m) WHERE n.caseId = $caseId AND m.caseId = $caseId RETURN labels(n) as sourceLabels, type(r) as relName, labels(m) as targetLabels";
session.executeRead(tx -> {
Result result = tx.run(query, Values.parameters("caseId", caseId));
while (result.hasNext()) {
Record record = result.next();
List<String> sourceLabels = record.get("sourceLabels").asList(Value::asString);
List<String> targetLabels = record.get("targetLabels").asList(Value::asString);
if (!sourceLabels.isEmpty()) {
nodeLabels.add(sourceLabels.get(0));
}
if (!targetLabels.isEmpty()) {
nodeLabels.add(targetLabels.get(0));
}
relTypes.add(record.get("relName").asString());
}
return null;
});
} catch (Exception e) {
log.error("查询失败", e);
}
log.info("查询到的节点类型{}个:{}", nodeLabels.size(), nodeLabels);
log.info("查询到的关系类型{}个:{}", relTypes.size(), relTypes);
// 将nodeLabels重新组装成List<Map<String, Object>>nodeLabels中的值作为key:name的值另外创建一个key:itemStyle值是Map<String, String>一个键值对是color+随机颜色另一个是lightColor+随机颜色
List<Map<String, Object>> nodeLabelsList = nodeLabels.stream().map(label -> {
Map<String, Object> nodeLabelMap = new HashMap<>();
Map<String, String> itemStyle = new HashMap<>();
itemStyle.put("color", Neo4jUtils.getRandomColorPair()[0]);
itemStyle.put("lightColor", Neo4jUtils.getRandomColorPair()[1]);
nodeLabelMap.put("name", label);
nodeLabelMap.put("itemStyle", itemStyle);
return nodeLabelMap;
}).toList();
map.put("nodeLabels", nodeLabelsList);
map.put("relTypes", relTypes);
return R.ok(map);
}
record NodeMapRecord(String name, String id, Set<String> idSet) {
}
/**
* 推选出代表节点信息
*
* @param nodes key: name ,entityName,id 节点信息
* @return key: name ,value: NodeMapRecord
*/
private Map<String, NodeMapRecord> electNodeRecord(List<Map<String, String>> nodes) {
Map<String, NodeMapRecord> nodeRecordMap = new HashMap<>();
for (Map<String, String> node : nodes) {
String name = node.get("name");
String id = node.get("id");
NodeMapRecord nodeMapRecord = nodeRecordMap.get(name);
if (nodeMapRecord == null) {
Set<String> idSet = new HashSet<>();
idSet.add(id);
nodeRecordMap.put(name, new NodeMapRecord(name, id, idSet));
} else {
nodeMapRecord.idSet.add(id);
}
}
return nodeRecordMap;
}
/**
* 合并节点信息
* 合并依据:
* name为唯一标识
*
* @param nodes key: name ,entityName,id
* @param nodeRecordMap 代表节点信息
* @return 合并后的节点信息
*/
private List<Map<String, String>> mergeNode(List<Map<String, String>> nodes, Map<String, NodeMapRecord> nodeRecordMap) {
return nodes.stream().map(map -> {
Map<String, String> nodeMap = new HashMap<>();
nodeMap.put("name", map.get("name"));
nodeMap.put("color", map.get("color"));
NodeMapRecord nodeMapRecord = nodeRecordMap.get(map.get("name"));
if (null == nodeMapRecord) {
log.warn("mergeNode:节点信息异常nodeRecordMap中不存在节点名称为{}的NodeMapRecord", map.get("name"));
return nodeMap;
}
if (!nodeMapRecord.idSet.contains(map.get("id"))) {
log.warn("mergeNode:节点信息异常nodeMapRecord.idSet中不包含节点id:{},节点名称为:{}", map.get("id"), map.get("name"));
return nodeMap;
}
nodeMap.put("id", nodeMapRecord.id);
return nodeMap;
}).filter(map -> StrUtil.isNotEmpty(map.get("id")))
.filter(distinctPredicate(m -> m.get("id"))).collect(Collectors.toList());
}
/**
* 合并关系信息
*
* @param webRelDTOList 关系信息
* @param nodeRecordMap 代表节点信息
* @return 合并后的关系信息
*/
private List<WebRelDTO> mergerWebRel(List<WebRelDTO> webRelDTOList, Map<String, NodeMapRecord> nodeRecordMap) {
Map<String, NodeMapRecord> idNodeRecordMap = nodeRecordMap.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getValue().id, Map.Entry::getValue));
return webRelDTOList.stream().map(webRelDTO -> {
String target = webRelDTO.getTarget();
String source = webRelDTO.getSource();
String name = webRelDTO.getName();
String sourceNew = idNodeRecordMap.entrySet().stream()
.filter(entry -> entry.getValue().idSet.contains(source))
.findAny().map(Map.Entry::getKey).orElse("");
String targetNew = idNodeRecordMap.entrySet().stream()
.filter(entry -> entry.getValue().idSet.contains(target))
.findAny().map(Map.Entry::getKey).orElse("");
if (StrUtil.isEmpty(sourceNew) || StrUtil.isEmpty(targetNew)) {
log.warn("mergerWebRel:关系信息异常nodeRecordMap中不存在节点id:{}或节点id:{}信息,节点名称为:{}", source, target, name);
}
return new WebRelDTO(sourceNew, targetNew, name);
}).filter(webRelDTO -> StrUtil.isNotEmpty(webRelDTO.getSource()) && StrUtil.isNotEmpty(webRelDTO.getTarget()))
.filter(distinctPredicate(rel -> rel.getSource() + rel.getTarget())).toList();
}
private <K> Predicate<K> distinctPredicate(Function<K, Object> function) {
ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>();
return (t) -> null == map.putIfAbsent(function.apply(t), true);
}
@Override
public void createAbstractGraph(String path, String sheetName) {
// 首先从数据库中读到数据
ExcelReader reader = ExcelUtil.getReader(path, sheetName);
List<AbstractGraphExcelHeader> abstractGraphExcelHeaders = reader.readAll(AbstractGraphExcelHeader.class);
Map<String, CaseNode> nodeMap = new HashMap<>();
Map<String, Rel> relMap = new HashMap<>();
for (AbstractGraphExcelHeader abstractGraphExcelHeader : abstractGraphExcelHeaders) {
// from
if (!nodeMap.containsKey(abstractGraphExcelHeader.getFrom())) {
CaseNode caseNode = new CaseNode(abstractGraphExcelHeader.getFrom(), abstractGraphExcelHeader.getFrom(), "0");
log.info("点:{}插入成功", abstractGraphExcelHeader.getFrom());
CaseNode save = save(caseNode);
nodeMap.put(abstractGraphExcelHeader.getFrom(), save);
}
// to
if (!nodeMap.containsKey(abstractGraphExcelHeader.getTo())) {
CaseNode caseNode = new CaseNode(abstractGraphExcelHeader.getTo(), abstractGraphExcelHeader.getTo(), "0");
CaseNode save = save(caseNode);
log.info("点:{}插入成功", abstractGraphExcelHeader.getTo());
nodeMap.put(abstractGraphExcelHeader.getTo(), save);
}
// relation
if (!relMap.containsKey(abstractGraphExcelHeader.getFrom() + "->" + abstractGraphExcelHeader.getRelation() + "->" + abstractGraphExcelHeader.getTo())) {
Rel rel = new Rel(nodeMap.get(abstractGraphExcelHeader.getFrom()).getId(), abstractGraphExcelHeader.getRelation(), nodeMap.get(abstractGraphExcelHeader.getTo()).getId(), "0");
saveRelation(rel);
log.info("关系:{}插入成功", (abstractGraphExcelHeader.getFrom() + "->" + abstractGraphExcelHeader.getRelation() + "->" + abstractGraphExcelHeader.getTo()));
relMap.put(abstractGraphExcelHeader.getFrom() + "->" + abstractGraphExcelHeader.getRelation() + "->" + abstractGraphExcelHeader.getTo(), rel);
}
}
}
public void deleteAbstractGraph() {
Session session = driver.session();
// 首先查出来所有的抽象节点
Result run = session.run("MATCH (n) WHERE n.picType = '0' OPTIONAL MATCH (n)-[r]-() RETURN id(n) as nodeId, id(r) as relId");
Set<String> nodeIdSet = new HashSet<>();
HashSet<String> relIdSet = new HashSet<>();
while (run.hasNext()) {
Record record = run.next();
String nodeId = Neo4jUtils.valueTransportString(record.get("nodeId"));
nodeIdSet.add(nodeId);
String relId = Neo4jUtils.valueTransportString(record.get("relId"));
relIdSet.add(relId);
}
// 删除边
for (String s : relIdSet) {
long relId = Long.parseLong(s);
deleteRel(relId);
log.info("删除边:{} 成功", relId);
}
// 删除节点
for (String s : nodeIdSet) {
long nodeId = Long.parseLong(s);
delNode(nodeId);
log.info("删除节点:{} 成功", nodeId);
}
}
@Data
private static class AbstractGraphExcelHeader {
private String from;
private String relation;
private String to;
}
@Data
private static class MockDataGraphExcelHeader {
private String fromType;
private String from;
private String relation;
private String to;
private String toType;
}
@Override
public void mockTestGraph(String path, String sheetName, String recordId, String recordSplitId, String caseId) {
// 首先从数据库中读到数据
ExcelReader reader = ExcelUtil.getReader(path, sheetName);
List<MockDataGraphExcelHeader> mockDataGraphExcelList = reader.readAll(MockDataGraphExcelHeader.class);
Map<String, CaseNode> nodeMap = new HashMap<>();
Map<String, Rel> relMap = new HashMap<>();
for (MockDataGraphExcelHeader mockData : mockDataGraphExcelList) {
// from
if (!nodeMap.containsKey(mockData.getFrom())) {
CaseNode caseNode = new CaseNode(mockData.getFrom(), mockData.getFromType(), recordSplitId, recordId, caseId, "1");
log.info("点:{}插入成功", mockData.getFrom());
CaseNode save = save(caseNode);
nodeMap.put(mockData.getFrom(), save);
}
// to
if (!nodeMap.containsKey(mockData.getTo())) {
CaseNode caseNode = new CaseNode(mockData.getTo(), mockData.getToType(), recordSplitId, recordId, caseId, "1");
CaseNode save = save(caseNode);
log.info("点:{}插入成功", mockData.getTo());
nodeMap.put(mockData.getTo(), save);
}
// relation
if (!relMap.containsKey(mockData.getFrom() + "->" + mockData.getRelation() + "->" + mockData.getTo())) {
Rel rel = new Rel(nodeMap.get(mockData.getFrom()).getId(), mockData.getRelation(), nodeMap.get(mockData.getTo()).getId(), "1");
saveRelation(rel);
log.info("关系:{}插入成功", (mockData.getFrom() + "->" + mockData.getRelation() + "->" + mockData.getTo()));
relMap.put(mockData.getFrom() + "->" + mockData.getRelation() + "->" + mockData.getTo(), rel);
}
}
}
@Override
public List<Record> executeCypher(String cypher, Map<String, Object> parameters) {
return this.driver.session().run(cypher, parameters).list();
}
}