(4)JanusGraph学习-----connect via JAVA

2022-03-21 00:00:00 版本 报错 配置 依赖 查看

1.通过内嵌方式访问JG

通过前文了解到JG本身就是一堆jar包,没有执行线程。所以两种访问方式,一种是通过现在服务器上启动一个gremlin-server (第三节中的内容) 。一种就是jar包内嵌的客户系统中,也就是要放到一个main函数或者spring web容器中去执行jg的jar包。

这里主要通过调用JG的相关java依赖包,结合配置文件,通过JanusGraphFactory.open()来访问对应的图库。首先演示通过main或者单元测试来跑通JG连接。

为了大家更好的理解内嵌的方式,大家可以:首先kill第三节中gremlin-server服务进程,再删除数据。(hbase和ES索引)

首先参考官方给出的example,构建出如下的目录结构:


相关核心代码:

1.1GraphDB类

主要封装一些统一的方法。这里我们通过GraphFactory.open(conf)方法来打开图库。注意通过查看源码可以得知:配置文件中必须定义key:gremlin.graph。GraphFactory会调用对应的指定工厂类的open代码。考虑后期扩展性,所以这里不直接写死JanusGraphFactory.open()。

public class GraphDB {
    private static final Logger LOGGER = LoggerFactory.getLogger(GraphDB.class);
    protected String propFileName;
    protected Configuration conf;
    protected Graph graph;
    protected GraphTraversalSource g;
    protected boolean supportsTransactions;
    protected boolean supportsSchema;
    protected boolean supportsGeoshape;
 
    public GraphDB(final String fileName) {
        this.propFileName = fileName;
    }
    
    public GraphTraversalSource openGraph() throws ConfigurationException {
        LOGGER.info("[andlinks]: opening graph");
        conf = new PropertiesConfiguration(propFileName);
        graph = GraphFactory.open(conf);
        g = graph.traversal();
        return g;
    }
    public GraphTraversalSource createGraph()  {
        return null;
    }

    public void closeGraph() throws Exception {
        LOGGER.info("[andlinks]:closing graph");
        try {
            if (g != null) {
                g.close();
            }
            if (graph != null) {
                graph.close();
            }
        } finally {
            g = null;
            graph = null;
        }
    }
    **
     * Drops the graph instance. The default implementation does nothing.
     */
    public void dropGraph() throws Exception {
    }
    **
     * Creates the graph schema. The default implementation does nothing.
     */
    public void createSchema() {
    }
}



1.2 JanusGraphDB类

    继承GraphDB类,提供一系列图操作接口。

public class JanusGraphDB extends GraphDB{
    private static final Logger LOGGER= LoggerFactory.getLogger(JanusGraph.class);
   
    public JanusGraphDB(final String fileName) {
        super(fileName);
        this.supportsSchema = true;
        this.supportsTransactions = true;
        this.supportsGeoshape = true;
    }
    @Override
    public GraphTraversalSource openGraph() throws ConfigurationException {
        super.openGraph();
        return g;
    }
    @Override
    public GraphTraversalSource createGraph() {
        return super.createGraph();
    }
    @Override
    public void dropGraph() throws Exception {
        if (graph != null) {
            JanusGraphFactory.drop(getJanusGraph());
        }
    }
    protected JanusGraph getJanusGraph() {
        return (JanusGraph) graph;
    }
    @Override
    public void createSchema() {
        final JanusGraphManagement management = this.getJanusGraph().openManagement();
        try {
             naive check if the schema was previously created
//            if (management.getRelation*(RelationType.class).iterator().hasNext()) {
//                management.rollback();
//                return;
//            }
            LOGGER.info("[andlinks]:creating schema");
//            createProperties(management);
            createVertexLabels(management);
//            createEdgeLabels(management);
//            createCompositeIndexes(management);
//            createMixedIndexes(management);
            management.commit();
        } catch (Exception e) {
            management.rollback();
        }
    }
    **
     * Creates the vertex labels.
     */
    protected void createVertexLabels(final JanusGraphManagement management) {
        management.makeVertexLabel("titan").make();
        management.makeVertexLabel("location").make();
        management.makeVertexLabel("god").make();
        management.makeVertexLabel("demigod").make();
        management.makeVertexLabel("human").make();
        management.makeVertexLabel("monster").make();
    }
}



1.3 janusgraph-hbase-es.properties配置文件

这里没有配置graph.graphname的话,默认是janusgraph图库。对应的hbase表名和图库名一致。后期如果要做多图配置的话,需要设置该key。


 

gremlin.graph=org.janusgraph.core.JanusGraphFactory
#graph.graphname=cc
#graph.graphname=ConfigurationManagementGraph
# 存储后端配置
storage.backend=hbase
# your zookper hostname
storage.hostname=192.168.1.22
# mac os中:如果你想远程连接 还需要做的是 把hbase的host文件copy过来放到你的本机的hosts文件中
# 缓存配置
# cache.db-cache = true
# cache.db-cache-clean-wait = 20åå
# cache.db-cache-time = 180000
# cache.db-cache-size = 0.5
# es 配置
index.search.backend=elasticsearch
index.search.hostname=192.168.1.22



1.4 pom文件

一开始直接使用了janusgraph-all依赖包,内部包含了所有的JG依赖。类似于springboot。但是实际启动过程中会报各种class not found错误。查看依赖树发现是多个版本冲突导致。考虑多个jar冲突报错和后期第三方jar包的增加,这里单独引用需要用到的小依赖。需要注意下hbase-shaded-client和elasticsearch-rest-client的版本,试过几次才找到对应的可用版本。具体的报错信息见末尾的报错总结。


    <dependencies>
        <!--<dependency>-->
            <!--<groupId>org.janusgraph</groupId>-->
            <!--<artifactId>janusgraph-all</artifactId>-->
            <!--<version>${jg.version}</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-core</artifactId>
            <version>${jg.version}</version>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>com.fasterxml.jackson.core</groupId>-->
            <!--<artifactId>jackson-core</artifactId>-->
            <!--<version>2.6.2</version>-->
        <!--</dependency>-->
        <!--<dependency>-->
            <!--<groupId>org.apache.httpcomponents</groupId>-->
            <!--<artifactId>httpcore</artifactId>-->
            <!--<version>4.2.3</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.apache.tinkerpop</groupId>
            <artifactId>gremlin-server</artifactId>
            <version>${tinkerpop.version}</version>
        </dependency>
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-hbase</artifactId>
            <version>${jg.version}</version>
            <!--<scope>runtime</scope>-->
        </dependency>
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-es</artifactId>
            <version>${jg.version}</version>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>org.apache.hbase</groupId>-->
            <!--<artifactId>hbase-common</artifactId>-->
            <!--<version>1.2.0-cdh5.12.1</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-shaded-client</artifactId>
            <version>1.2.6</version>
            <!--<scope>runtime</scope>-->
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>6.2.2</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>maven-hadoop</id>
            <name>Hadoop Releases</name>
            <url>https://repository.cloudera.com/content/repositories/releases/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
   
</project>



1.5 JanusGraphDBTest类

这里直接先使用单元测试,初步判断下是否能够成功。

public class JanusGraphDBTest{

    protected static final String CONF_FILE = "src/main/resources/conf/janusgraph-hbase-es.properties";
    private static JanusGraphDB janusGraphDB;
    private static GraphTraversalSource g;
    private static JanusGraphManager gm;
    static {
        janusGraphDB = new JanusGraphDB(CONF_FILE);
        if(JanusGraphManagerUtility.getInstance()==null){
            gm = new JanusGraphManager(new Settings());
        }
        try {
            g = janusGraphDB.openGraph();
        } catch (ConfigurationException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void createSchema(){
        janusGraphDB.createSchema();
        final JanusGraph janusGraph = (JanusGraph) g.getGraph();
        final JanusGraphManagement management = janusGraph.openManagement();
        final List<String> vertexLabels = StreamSupport.stream(management.getVertexLabels().spliterator(), false)
                .map(Namifiable::name).collect(Collectors.toList());
        final List<String> expectedVertexLabels = Stream.of("titan", "location", "god", "demigod", "human", "monster")
                .collect(Collectors.toList());
        assertTrue(vertexLabels.containsAll(expectedVertexLabels));
    }
    @Test
    public void selectCount(){
        Long count = g.V().count().next();
        System.out.println("CC+++++++:"+count.toString());
    }
    @Test
    public void dropGraph() throws Exception {
        janusGraphDB.dropGraph();
    }
}



单元测试成功的话,会在hbase中查看到对应创建的table。es索引创建可能不成功。这个我们后面章节再介绍进一步配置,先保证连接,建图成功。

2.踩坑过程中碰到的问题记录:    

2.1     Caused by:  java.lang.NoSuchMethodError:org.apache.hadoop.hbase.HTableDescriptor.addFamily(Lorg/apache/hadoop/hbase/HColumnDescriptor;)Lorg/apache/hadoop/hbase/HTableDescriptor;

 at org.janusgraph.diskstorage.hbase.HBaseCompat1_0.addColumnFamilyToTableDescriptor(HBaseCompat1_0.java:49)

 at org.janusgraph.diskstorage.hbase.HBaseStoreManager.createTable(HBaseStoreManager.java:761)

 at org.janusgraph.diskstorage.hbase.HBaseStoreManager.ensureTableExists(HBaseStoreManager.java:744)

 at org.janusgraph.diskstorage.hbase.HBaseStoreManager.getLocalKeyPartition(HBaseStoreManager.java:536)

 at org.janusgraph.diskstorage.hbase.HBaseStoreManager.getDeployment(HBaseStoreManager.java:375)

【解决方案】:hbase-shaded-client依赖包版本不对,这里使用hbase对应的版本版反而会报错,查看源码,需要和janusgraph-core对应的依赖包版本一致才行。可以在janusgraph-all中查看对应的版本号,然后单独引入对应的依赖即可。

2.2 

Caused by: java.lang.IllegalArgumentException: Could not instantiate implementation: org.janusgraph.diskstorage.es.ElasticSearchIndex

 at org.janusgraph.util.system.ConfigurationUtil.instantiate(ConfigurationUtil.java:64)

 at org.janusgraph.diskstorage.Backend.getImplementationClass(Backend.java:476)

 at org.janusgraph.diskstorage.Backend.getIndexes(Backend.java:463)

 at org.janusgraph.diskstorage.Backend.<init>(Backend.java:148)

 at org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.getBackend(GraphDatabaseConfiguration.java:1840)

 at org.janusgraph.graphdb.database.StandardJanusGraph.<init>(StandardJanusGraph.java:138)

 at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:160)

 at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:131)

 at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:111)

 ... 30 more

Caused by: java.lang.reflect.InvocationTargetException

 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)

 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

 at java.lang.reflect.Constructor.newInstance(Constructor.java:423)

 at org.janusgraph.util.system.ConfigurationUtil.instantiate(ConfigurationUtil.java:58)

 ... 38 more

Caused by: org.janusgraph.diskstorage.PermanentBackendException: listener timeout after waiting for [30000] ms

【解决方案】:这里通过进一步查看debug日志,发现次连接es是成功的,说明es服务本身没有问题,所以初步定位问题出现在jar包上,通过尝试,更新elasticsearch-rest-client 的6.2.2版本jar包后解决。(查看日志发现应该是路由ip解析的问题,6.2.2版本jar包能够解析到本机的内网ip,而6.0.1版本解析不到。这里暂时不花时间深究。)

2.3

Caused by: java.lang.IllegalStateException: Gremlin Server must be configured to use the JanusGraphManager.

 at com.google.common.base.Preconditions.checkState(Preconditions.java:173)

 at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:148)

 at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:131)

 at org.janusgraph.core.JanusGraphFactory.open(JanusGraphFactory.java:111)

【解决方案】:这里需要初始化JanusGraphManager才能够创建graph实例。这个是在配置文件中配置了key:graph.graphname之后才会报错,需要在代码中手动初始化一下,因为JanusGraphManager是一个单例,所以直接初始化一下就行了。

相关文章