一. 简介
关于Gremlin和neo4j的简介这里不做过多的介绍,目前两者主要是解决数据血缘的问题,本文主要讲解内嵌型Gremlin和neo4j的使用方式以及完整的实例。
二. 版本适配
Gremlin和neo4j都是用java开发的所以也都是依赖jvm的,这才能够完全内嵌到我们的java程序中,于我们的java程序共用一个jvm,但是当要存的数据量过大时,就会产生一些数据库于程序在jvm的平衡还有jvm的压力等各种问题,本文不深究于此,下面我们看两者的版本
// embedded graph of gremlin and driver
implementation 'org.apache.tinkerpop:gremlin-core:3.4.10'
implementation 'org.apache.tinkerpop:gremlin-driver:3.4.10'
// embedded neo4j and tinkerpop api impl
implementation 'org.apache.tinkerpop:neo4j-gremlin:3.4.10'
implementation 'org.neo4j:neo4j-tinkerpop-api-impl:0.9-3.4.0'
目前为止neo4j对gremlin兼容的最高版本为3.4.0(更高的版本不兼容难道是他想搞自己的标准?)
三.使用
1. 启动Gremlin
我们选择在springboot项目启动后,加载neo4jGraph的实例,当然也可以在用的时候加载,但是这个实例只能加载一次,不然会报错。
import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* Construct a graph instance by specifying the directory to create the database.
*/
@Component
@Order(1)
public class DataBaseApplicationRunner implements ApplicationRunner {
private String graphDataSource = "/tmp/neo4j";
private Neo4jGraph graph;
@Override
public void run(ApplicationArguments args) {
// 启动时可以注入neo4j数据保存的位置
log.info("Graph database loading.....");
String[] sourceArgs = args.getSourceArgs();
if (sourceArgs.length >= 1) {
graphDataSource = sourceArgs[0];
}
try {
graph = Neo4jGraph.open(graphDataSource);
} catch (Exception e) {
GraphLog.log.error("Graph database load happen Exception.", e);
}
log.info("Graph database load success.");
}
public Neo4jGraph getGraph() {
return graph;
}
}
2. Graph Access
我们设计与Gremlin交互的并自动释放资源的工具类
@Component
public final class GraphAccess {
private static DataBaseApplicationRunner dataBaseApplicationRunner;
@Autowired
public void setGraphApplication(DataBaseApplicationRunner dataBaseApplicationRunner) {
GraphAccess.dataBaseApplicationRunner = dataBaseApplicationRunner;
}
// 获取gremlin连接
public static GraphTraversalSource getGraphTraversalSource() {
GraphTraversalSource g = traversal().withEmbedded(dataBaseApplicationRunner.getGraph());
g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.AUTO);
return g;
}
// set节点并返回这个节点,自动释放连接
public static Vertex exec(GraphVertexSupplier graphVertexSupplier) {
try (GraphTraversalSource g = getGraphTraversalSource()) {
try {
return graphVertexSupplier.exec();
} catch (Exception e) {
GraphLog.log.error("graph database operation happen Exception.", e);
g.tx().rollback();
close(g);
throw e;
} finally {
g.tx().close();
}
}
}
/**
* graph database operation that return list and auto close
*
* @param graphGetOperation GraphSourceToList
* @return List<Object>
*/
@SneakyThrows
public static<T> List<T> use(GraphSourceToList<T> graphGetOperation) {
try (GraphTraversalSource g = getGraphTraversalSource()) {
try {
List<T> result = graphGetOperation.exec(g);
g.tx().commit();
return result;
} catch (Exception e) {
GraphLog.log.error("graph database operation happen Exception.", e);
g.tx().rollback();
throw e;
} finally {
g.tx().close();
}
}
}
/**
* graph database operation that no return value and auto close
*
* @param graphSourceConsumer GraphSourceConsumer
*/
@SneakyThrows
public static void use(GraphSourceConsumer graphSourceConsumer) {
try (GraphTraversalSource g = getGraphTraversalSource()) {
try {
graphSourceConsumer.exec(g);
g.tx().commit();
} catch (Exception e) {
GraphLog.log.error("graph database operation happen Exception.", e);
g.tx().rollback();
throw e;
} finally {
g.tx().close();
}
}
}
相关FunctionInterface:
@FunctionalInterface
public interface GraphSourceToList<T> {
List<T> exec(GraphTraversalSource graphTraversalSource);
}
@FunctionalInterface
public interface GraphSourceConsumer {
void exec(GraphTraversalSource graphTraversalSource);
}
@FunctionalInterface
public interface GraphVertexSupplier {
Vertex exec();
}
@FunctionalInterface
public interface GraphOperation {
void exec();
}
@FunctionalInterface
public interface GraphEdgeSupplier {
Edge exec();
}
@FunctionalInterface
public interface GraphTraversalSupplier<S, E> {
GraphTraversal<S, E> exec();
}
3. Dao层
3.1. put Dao
@Component
public class GraphPutDao {
// set vertex
public Vertex setVertex(String label, Map<String, String> property) {
return GraphAccess.use((GraphVertexSupplier) (g) -> {
GraphTraversal<Vertex, Vertex> traversal = g.addV(label);
addVertexProperty(traversal, property);
return traversal.next();
});
}
// set edge
public void setEdge( EachGraphDomain eachGraphDomain) {
GraphAccess.use((g) -> {
GraphTraversal<Edge, Edge> traversal = g
.addE(eachGraphDomain.getEdgeLabel())
.from(eachGraphDomain.getStartVertex());
addEdgeProperty(traversal, eachGraphDomain.getEdgeProperty());
traversal.to(eachGraphDomain.getEndVertex()).iterate();
});
}
private void addVertexProperty(GraphTraversal<Vertex, Vertex> graphTraversal, Map<String, String> properties) {
properties.forEach(graphTraversal::property);
}
private void addEdgeProperty(GraphTraversal<Edge, Edge> graphTraversal, Map<String, String> properties) {
properties.forEach(graphTraversal::property);
}
}
3.2. Get Dao
@Component
public class GraphGetDao {
/**
* @param label String
* @return List<Vertex>
*/
public List<Vertex> getVertexByLabel(String label) {
return GraphAccess.use((GraphSourceToList<Vertex>) g -> g.V().hasLabel(label).toList());
}
/**
* @param sId String
* @param eId String
* @return List<Object>
*/
public List<Object> getEdgeByStartAndEndVertexId(Object sId, Object eId) {
return GraphAccess.use((GraphSourceToList<Object>) g -> g.V(sId)
.outE()
.as("e")
.inV()
.hasId(eId)
.select("e").toList()
);
}
/**
* @param label String
* @return List<Vertex>
*/
public List<Vertex> getIndegreeVertex(String label) {
return GraphAccess.use((GraphSourceToList<Vertex>) g -> g.V().hasLabel(label).in().toList());
}
/**
* @param label String
* @return List<Vertex>
*/
public List<Vertex> getOutdegreeVertex(String label) {
return GraphAccess.use((GraphSourceToList<Vertex>) g -> g.V().hasLabel(label).out().toList());
}
}
4. 调用
public class Test {
GraphGetDao getDao = new GaraphGetDao();
GraphPutDao putDao = new GaraphPutDao();
Vertex startVertex = putDao.setVertex("startlable", Map.of("name", "zhangsan", "age", "23"));
Vertex endVertex = putDao.setVertex("endlable", Map.of("name", "lisi", "age", "24"));
putDao .setEdge(startVertex, endVertex, "edge", Map.of("relation", "brother");
getDao.getVertexByLabel("startlable");
getDao.getIndegreeVertex("endlable");
getDao.getOutdegreeVertex("startLable");
}
5. 其他工具类
@Getter
@AllArgsConstructor
public class EachGraphDomain {
private final Vertex startVertex;
private final Vertex endVertex;
private final String edgeLabel;
private final Map<String, String> edgeProperty;
}