該文的實(shí)現(xiàn)有更簡(jiǎn)單的方式,詳見我的另一篇博客springboot整合neo4j–采用Neo4jClient和Neo4jTemplate方式
1.背景
Neo4j 提供 JAVA API 以編程方式執(zhí)行所有數(shù)據(jù)庫(kù)操作。它支持三種類型的API:
1、Neo4j 原生的 Java API
原生 Java API 是一種低級(jí)別的純 JAVA API,用于執(zhí)行數(shù)據(jù)庫(kù)操作。
2、Neo4j Cypher Java API
Cypher Java API 是簡(jiǎn)單而強(qiáng)大的 JAVA API,用于執(zhí)行所有CQL命令以執(zhí)行數(shù)據(jù)庫(kù)操作。
3、Neo4j OGM JAVA API
OGM Java API和Mybatis、JPA類似可以直接和SpringData整合
2.分析
目前很多項(xiàng)目針對(duì)neo4j的操作采用Neo4j OGM JAVA API,該方案與springboot整合之后可以使用@Query注解很方便的編寫查詢接口,比如這篇SpringBoot集成neo4j實(shí)戰(zhàn)。
但是這種方式對(duì)圖數(shù)據(jù)庫(kù)的增刪改查均依賴業(yè)務(wù)數(shù)據(jù)對(duì)象(就是你的Java bean對(duì)象,比如People、Company),如果我們數(shù)據(jù)類型很多且不斷變化,那這種方式就不再適合。
而Neo4j Cypher Java API對(duì)neo4j的操作是業(yè)務(wù)數(shù)據(jù)對(duì)象無(wú)關(guān)的,不管是什么樣的節(jié)點(diǎn)數(shù)據(jù)或關(guān)系數(shù)據(jù)均可以操作。因?yàn)樗侵苯邮褂胹ession執(zhí)行cyhper語(yǔ)句。具體區(qū)別可自行查看下方代碼。
3.代碼實(shí)戰(zhàn)
1.依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>chaos</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.0</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
<!--<exclusions>
<exclusion>
<artifactId>neo4j-java-driver</artifactId>
<groupId>org.neo4j.driver</groupId>
</exclusion>
</exclusions>-->
</dependency>
<!-- <dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>4.2.0</version>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<excludes>
<!--<exclude>**/*</exclude>-->
</excludes>
</resource>
</resources>
</build>
</project>
1.Neo4jClientConfig
package com.dbs.neo4j.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "com.dbs.neo4j")
public class Neo4jClientConfig {
private String uri;
private String username;
private String password;
}
**2.Neo4jClientService **
package com.win.chaos.service;
import com.win.chaos.config.Neo4jConfig;
import com.win.chaos.exception.Neo4jException;
import lombok.extern.slf4j.Slf4j;
import org.neo4j.driver.*;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class Neo4jClientService {
private final Driver driver;
public Neo4jClientService(Neo4jConfig neo4jConfig) {
this.driver = GraphDatabase.driver(neo4jConfig.getUri(), AuthTokens.basic(neo4jConfig.getUsername(), neo4jConfig.getPassword()));
}
/**
* 適用執(zhí)行寫邏輯
* @param cypher cypher
* @return Result 由于return之前session已經(jīng)被關(guān)閉,該result不能被消費(fèi)
* @throws Neo4jException 執(zhí)行cypher出現(xiàn)異常
*/
public Result run(String cypher) throws Neo4jException {
Session session = driver.session();
Transaction ts = session.beginTransaction();
try {
Result result = ts.run(cypher);
ts.commit();
return result;
} catch (Exception e) {
ts.rollback();
log.error("run neo4j cypher error with ", e);
throw new Neo4jException("run " + cypher + " error with" + e.getMessage());
}finally {
ts.close();
session.close();
}
}
/**
* 用于執(zhí)行讀或?qū)慶ypher語(yǔ)句
* @param gql cypher
* @return Result
* @throws Neo4jException 執(zhí)行cypher出現(xiàn)異常
*/
public Result exec(String gql) throws Neo4jException {
try {
Session session = driver.session();
log.info("exec {}", gql);
return session.run(gql);
} catch (Exception e) {
log.error("execute gql {} error ", gql, e);
throw new Neo4jException("execute " + gql + " error with" + e.getMessage());
}
}
}
3.Controller
@Resource
private Neo4jClientService neo4jClient;
//查詢節(jié)點(diǎn)
@GetMapping("/getNode")
public Neo4jGraph getNode() throws Neo4jException {
String ql = "MATCH (n:`公司`) RETURN n LIMIT 25";
Result result = neo4jClient.run(ql);
return Neo4jGraph.parse(result);
}
//查詢路徑
@GetMapping("/matchPath")
public Neo4jGraph matchPath() throws Neo4jException {
String ql = "MATCH p=()-[r:`持股`]->() RETURN p LIMIT 25";
Result result = neo4jClient.run(ql);
return Neo4jGraph.parse(result);
}
//測(cè)試創(chuàng)建和刪除
@GetMapping("/test")
public void add() throws Neo4jException {
String addQL = "CREATE (o:people {name:\"里斯\",id:32435})";
Result addResult = neo4jClient.run(addQL);
String delQL = "match (n:people) delete n";
Result delResult = neo4jClient.run(delQL);
}
以上代碼實(shí)現(xiàn)了springboot整合neo4j原生cypher,可以進(jìn)行業(yè)務(wù)數(shù)據(jù)對(duì)象無(wú)關(guān)的操作。
代碼中的Neo4jGraph.parse為解析查詢對(duì)象接口。如有需要請(qǐng)看下面代碼。
4.Neo4jGraph
package com.win.chaos.model.neo4j;
import cn.hutool.core.collection.ConcurrentHashSet;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.neo4j.driver.Record;
import org.neo4j.driver.Result;
import org.neo4j.driver.Value;
import org.neo4j.driver.internal.types.TypeConstructor;
import org.neo4j.driver.types.Node;
import org.neo4j.driver.types.Path;
import org.neo4j.driver.types.Relationship;
import org.neo4j.driver.types.Type;
import java.util.List;
import java.util.Set;
@Data
@Slf4j
public class Neo4jGraph {
private Set<Neo4jNode> nodes = new ConcurrentHashSet<>();
private Set<Neo4jEdge> edges = new ConcurrentHashSet<>();
/**
* 解析查詢結(jié)果,目前僅解析節(jié)點(diǎn)(Node)、關(guān)系(Relationship)、路徑(Path)三種查詢結(jié)果類型
* @param result 查詢結(jié)果集
* @return Neo4jGraph
*/
public static Neo4jGraph parse(Result result) {
if (result == null) return null;
Neo4jGraph graph = new Neo4jGraph();
List<Record> records = result.list();
for (Record record:records){
List<Value> values = record.values();
for (Value value : values) {
Type type = value.type();
if (type.name().equals(TypeConstructor.NODE.name())) {
Node node = value.asNode();
graph.addNeo4jNode(new Neo4jNode(node));
}else if (type.name().equals(TypeConstructor.PATH.name())) {
Path path = value.asPath();
path.nodes().forEach(node -> graph.addNeo4jNode(new Neo4jNode(node)));
path.relationships().forEach(relationship -> graph.addNeo4jEdge(new Neo4jEdge(relationship)));
}else if (type.name().equals(TypeConstructor.RELATIONSHIP.name())) {
Relationship relationship = value.asRelationship();
graph.addNeo4jEdge(new Neo4jEdge(relationship));
}else {
log.error("目前不支持{}類型的查詢數(shù)據(jù)解析。", type.name());
}
}
}
return graph;
}
public void addNeo4jNode(Neo4jNode neo4jNode) {
nodes.add(neo4jNode);
}
public void addNeo4jEdge(Neo4jEdge neo4jEdge) {
edges.add(neo4jEdge);
}
}
5.Neo4jNode
package com.win.chaos.model.neo4j;
import lombok.Data;
import org.neo4j.driver.types.Node;
import java.util.*;
@Data
public class Neo4jNode {
private Object id;
private List<String> labels = new ArrayList<>();
private Map<String, Object> props = new HashMap<>();
public Neo4jNode(Node node) {
id = node.id();
parseLabels(node);
parseProp(node);
}
public void parseLabels(Node node){
if (node.labels() != null){
node.labels().forEach(labels::add);
}
}
public void parseProp(Node node) {
Map<String, Object> propsMap = node.asMap();
Set<String> keys = propsMap.keySet();
for (String key : keys){
props.put(key, propsMap.get(key));
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Neo4jNode vertex = (Neo4jNode) o;
return id.equals(vertex.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
}
6.Neo4jEdge
package com.win.chaos.model.neo4j;
import lombok.Data;
import org.neo4j.driver.types.Relationship;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Data
public class Neo4jEdge {
private long edgeId;
private Object srcId;
private Object dstId;
private String label;
private Map<String, Object> props = new HashMap<>();
public Neo4jEdge(Relationship relationship) {
srcId = relationship.startNodeId();
dstId = relationship.endNodeId();
edgeId = relationship.id();
label = relationship.type();
parseProps(relationship);
}
private void parseProps(Relationship relationship) {
Map<String, Object> data = relationship.asMap();
Set<String> keys = data.keySet();
for (String key : keys) {
props.put(key, data.get(key));
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Neo4jEdge that = (Neo4jEdge) o;
//if (!edgeId.equals(that.edgeId)) return false;
if (!srcId.equals(that.srcId)) return false;
if (!dstId.equals(that.dstId)) return false;
return label.equals(that.label);
}
@Override
public int hashCode() {
int result = srcId.hashCode();
result = 31 * result + dstId.hashCode();
result = 31 * result + label.hashCode();
result = 31 * result + (int) (edgeId ^ (edgeId >>> 32));
return result;
}
}
完整代碼:springboot_neo4j_hanlp文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-702472.html
參考
圖數(shù)據(jù)庫(kù) Neo4j Java Api 的使用文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-702472.html
到了這里,關(guān)于springboot整合neo4j-使用原生cypher Java API的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!