当前位置: 首页 > 工具软件 > Gremlin > 使用案例 >

Gremlin+neo4j+完整实例

左丘曦
2023-12-01

一. 简介

关于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;
}

 类似资料: