这篇文章将主要记录通过java来链接Neo4j数据库进行简单,复杂查询的api编写
查询指定标签的节点,以及指定属性
MATCH (n:label {property: $propertyValue}) RETURN n;按照这个CQL来组装动态参数,实现如下:
/**
* 功能描述:查询指定标签的节点,以及指定属性
*
* @param label 标签
* @param properties 属性
* @return {@link List }<{@link Object }>
* @author zhongzy
* @date 2024/05/17
*/
public List<Object> searchNode(String label, Map<String, Object> properties) {
try (Session session = driver.session()) {
StringBuilder sb = new StringBuilder("MATCH (n:" + label);
appendProperties(sb,"n",properties);
sb.append(") RETURN n");
return session.run(sb.toString(), Values.value(properties)).list().stream().map(record -> record.get("n").asMap()).collect(toList());
}
}
查询所有节点,限制个数
MATCH (n) RETURN n LIMIT $limit;按照这个CQL来组装动态参数,实现如下:
/**
* 功能描述:查询所有节点,限制个数
*
* @param limit 限制
* @return {@link List }<{@link Object }>
* @author zhongzy
* @date 2024/05/17
*/
public List<Object> searchNode(int limit){
try(Session session = driver.session()){
return session.run("MATCH (n) RETURN n LIMIT $limit",parameters("limit",limit)).list().stream().map(record -> record.get("n").asMap()).collect(toList());
}
}
查询所有关系
MATCH ()-[r]->() RETURN r;按照这个CQL来组装动态参数,实现如下:
/**
* 功能描述:查询所有关系
*
* @return {@link List }<{@link Object }>
* @author zhongzy
* @date 2024/05/17
*/
public List<Object> searchRelationShip(){
try(Session session = driver.session()){
return session.run("MATCH ()-[r]->() RETURN r").list().stream().map(record -> record.get("r").asMap()).collect(toList());
}
}
查询指定关系
MATCH (a:person {name: "沙僧"})-[r]-(b:person {name: "猪八戒"}) RETURN r;按照这个CQL来组装动态参数,实现如下:
/**
* 功能描述:查询指定关系
*
* @param fromLabel 起始节点
* @param fromProperties 起始节点属性
* @param toLabel 目标节点
* @param toProperties 目标节点属性
* @param relationshipType 关系类型
* @param relationshipProperties 关系属性
* @return {@link List }<{@link Object }>
* @author zhongzy
* @date 2024/05/17
*/
public List<Object> searchRelationShip(String fromLabel, Map<String, Object> fromProperties, String toLabel, Map<String, Object> toProperties, String relationshipType, Map<String, Object> relationshipProperties){
try(Session session = driver.session()){
StringBuilder sb = new StringBuilder("MATCH (a:" + fromLabel);
appendProperties(sb, "a", fromProperties);
sb.append(") MATCH (b:" + toLabel);
appendProperties(sb, "b", toProperties);
sb.append(") MATCH (a)-[r:" + relationshipType);
appendProperties(sb, "r", relationshipProperties);
sb.append("]->(b) RETURN r");
Map<String, Object> parameters = new HashMap<>();
addPropertiesToParameters(parameters, addPrefixToProperties(fromProperties, "a_"));
addPropertiesToParameters(parameters, addPrefixToProperties(toProperties, "b_"));
addPropertiesToParameters(parameters, addPrefixToProperties(relationshipProperties, "r_"));
return session.run(sb.toString(), Values.value(parameters)).list().stream().map(record -> record.get("r").asMap()).collect(toList());
}
}
查询指定节点的属性已经关系还有对应节点值
MATCH (a:person {name: "沙僧"})-[r]-(b:person {name: "猪八戒"}) RETURN a,r,b;按照这个CQL来组装动态参数,这里的查询我将给出自己封装的响应类和封装方法,实现如下:
NodeResult实体类,接收节点数据封装
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.neo4j.driver.types.Node;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Zhongzy
* @description
* @since 2024-05-17 15:52
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NodeResult {
private List<String> labels;
private Map<String, Object> properties;
private String elementId;
public void copyNode(Node a){ //复制响应中的元素,封装为想要的响应结果
this.setLabels((List<String>) a.labels());
this.setElementId(a.elementId());
Map<String, Object> nodeAMap = new HashMap<>();
a.keys().forEach(k -> {
nodeAMap.put(k, a.get(k));
});
this.setProperties(nodeAMap);
}
}
RelationshipResult关系实体类,返回关系响应体
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.neo4j.driver.types.Relationship;
import java.util.HashMap;
import java.util.Map;
/**
* @author Zhongzy
* @description
* @since 2024-05-17 15:59
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RelationshipResult {
private String type;
private Map<String, Object> properties;
private String elementId;
private String startElementId;
private String endElementId;
public void copyFromRelationship(Relationship r) { //封装响应体
Map<String, Object> relationMap = new HashMap<>();
r.keys().forEach(k -> {
relationMap.put(k, r.get(k));
});
this.properties = relationMap;
this.elementId = r.elementId();
this.type = r.type();
this.endElementId = r.endNodeElementId();
this.startElementId = r.startNodeElementId();
}
}
ResponseResult节点关系响应体
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* @author Zhongzy
* @description
* @since 2024-05-17 15:27
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResponseResult {
private Map<String, Object> nodeA;
private Map<String, Object> relationship;
private Map<String, Object> nodeB;
}
searchNodeAndRelationship实现方法
查询指定的节点和关系 MATCH (a:person {name: "沙僧"})-[r]-(b:person {name: "猪八戒"}) RETURN a,r,b
/**
* 功能描述:查询指定的节点和关系 MATCH (a:person {name: "沙僧"})-[r]-(b:person {name: "猪八戒"}) RETURN a,r,b
*
* @param fromLabel 从标签
* @param fromNodeProperty From Node 属性
* @param toLabel 到标签
* @param toNodeProperty To Node 属性
* @param type 类型
* @param proNodeProperty Pro Node 属性
* @return {@link List }<{@link ResponseResult }>
* @author zhongzy
* @date 2024/05/20
*/
public List<ResponseResult> searchNodeAndRelationship(String fromLabel, Map<String, Object> fromNodeProperty, String toLabel, Map<String, Object> toNodeProperty, String type, Map<String, Object> proNodeProperty) {
try (Session session = driver.session()) {
StringBuilder sb = new StringBuilder("MATCH (a:" + fromLabel);
appendProperties(sb, "a", fromNodeProperty);
sb.append(") MATCH (b:" + toLabel);
appendProperties(sb, "b", toNodeProperty);
sb.append(") MATCH (a)-[r:" + type);
appendProperties(sb, "r", proNodeProperty);
sb.append("]->(b) RETURN a,b,r");
Map<String, Object> parameters = new HashMap<>();
addPropertiesToParameters(parameters, addPrefixToProperties(fromNodeProperty, "a_"));
addPropertiesToParameters(parameters, addPrefixToProperties(toNodeProperty, "b_"));
addPropertiesToParameters(parameters, addPrefixToProperties(proNodeProperty, "r_"));
Result result = session.run(sb.toString(), Values.value(parameters));
List<ResponseResult> responseResult = new ArrayList<>();
while (result.hasNext()) {
//启动node
NodeResult fromNode = new NodeResult();
//目标node
RelationshipResult relation = new RelationshipResult();
//关系
NodeResult toNode = new NodeResult();
//获取关系
Record record = result.next();
encapsulation(fromNode, relation, toNode, record, responseResult);
}
return responseResult;
}
}
/**
* 功能描述:封装
*
* @param fromNode 从节点
* @param relation 关系
* @param toNode 到节点
* @param record 记录
* @param responseResult
* @author zhongzy
* @date 2024/05/20
*/
private void encapsulation(NodeResult fromNode, RelationshipResult relation, NodeResult toNode, Record record, List<ResponseResult> responseResult) {
ResponseResult result = new ResponseResult();
Node a = record.get("a").asNode();
//设置节点值
fromNode.copyNode(a);
//设置属性
Relationship r = record.get("r").asRelationship();
relation.copyFromRelationship(r);
Node b = record.get("b").asNode();
toNode.copyNode(b);
Map<String, Object> nodeA = new HashMap<>();
nodeA.put("a", fromNode);
Map<String, Object> relationR = new HashMap<>();
relationR.put("r", relation);
Map<String, Object> nodeB = new HashMap<>();
nodeB.put("b", toNode);
result.setNodeA(nodeA);
result.setNodeB(nodeB);
result.setRelationship(relationR);
responseResult.add(result);
}
这里给出返回的响应体结构是这样的,返回了在neo4j-desktop中展示出来的同款响应体,效果达成。
[ResponseResult(nodeA = {
a = NodeResult(labels = [person], properties = {
name = "唐僧"
},
elementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 2)
},
relationship = {
r = RelationshipResult(type = 徒弟, properties = {
year = "2024"
},
elementId = 5 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 6, startElementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 2, endElementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 3)
},
nodeB = {
b = NodeResult(labels = [person], properties = {
name = "孙悟空"
},
elementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 3)
}), ResponseResult(nodeA = {
a = NodeResult(labels = [person], properties = {
name = "唐僧"
},
elementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 2)
},
relationship = {
r = RelationshipResult(type = 徒弟, properties = {
year = "2024"
},
elementId = 5 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 7, startElementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 2, endElementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 4)
},
nodeB = {
b = NodeResult(labels = [person], properties = {
name = "猪八戒"
},
elementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 4)
}), ResponseResult(nodeA = {
a = NodeResult(labels = [person], properties = {
name = "唐僧"
},
elementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 2)
},
relationship = {
r = RelationshipResult(type = 徒弟, properties = {
year = "2024"
},
elementId = 5 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 8, startElementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 2, endElementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 5)
},
nodeB = {
b = NodeResult(labels = [person], properties = {
name = "沙僧"
},
elementId = 4 : 58f2796d - d800 - 4bc7 - a466 - 6f556f36fa3b: 5)
})]
通过深度查询相关节点以及关系
/**
* 功能描述:MATCH path = (n)-[*..depth]->(m)
* WHERE elementId(n) = {startNodeId}
* RETURN path 深度遍历,查询指定节点的深度关系
* TODO 可以添加其他参数,暂定最暴力版本
*
* @return
* @author zhongzy
* @date 2024/05/21
*/
public List<DepthResult> searchNodeAndRelationByDepth(String elementId, int depth) {
try (Session session = driver.session()) {
StringBuilder sb = new StringBuilder("MATCH path = (" + N.getValue() + ")-[*..");
sb.append(depth).append("]->(").append(M.getValue()).append(") where elementId(").append(N.getValue()).append(") = '").append(elementId).append("' return path");
Result run = session.run(sb.toString());
return getDepthResult(run);
}
}
完整代码有兴趣的可以私聊博主~持续更新中