1. Dependency

<properties>
	<janus.version>1.0.0</janus.version>
	<tinkerpop.version>3.7.0</tinkerpop.version>
</properties>

<dependency>
    <groupId>org.janusgraph</groupId>
    <artifactId>janusgraph-driver</artifactId>
    <version>${janus.version}</version>
</dependency>

<dependency>
    <groupId>org.apache.tinkerpop</groupId>
    <artifactId>tinkerpop</artifactId>
    <version>${tinkerpop.version}</version>
    <scope>import</scope>
    <type>pom</type>
</dependency>

<!-- optional -->
<build>
	<resources>
		<resource>
	    	<directory>src/main/resources</directory>
	     	<filtering>true</filtering>
	     	<includes>
	        	<include>**/*.yaml</include>
	     	</includes>
		</resource>
	</resources>
</build>

2. Structure

📒 src/main/resources
  📂 conf
    📄 remote-objects.yaml
  📂 META-INF/spring/
	# content:io.os.tinkerpop.autoconfigure.GremlinClusterAutoConfiguration
    📄 org.springframework.boot.autoconfigure.AutoConfiguration.imports

3. Starter

3.1. TinkerpopProperties

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "io.os.tinkerpop")
public class TinkerpopProperties{

	private String traversalName = "g";
	private String configFile = "src/main/resources/conf/remote-objects.yaml";

	public String getTraversalName() {
		return traversalName;
	}
	public void setTraversalName(String traversalName) {
		this.traversalName = traversalName;
	}
	public String getConfigFile() {
		return configFile;
	}
	public void setConfigFile(String configFile) {
		this.configFile = configFile;
	}

}

3.2. TinkerpopRepository

import org.apache.tinkerpop.gremlin.driver.Client;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.springframework.stereotype.Repository;

@Repository
public class TinkerpopRepository {

	protected Client client;
	protected GraphTraversalSource g;

	public TinkerpopRepository(GraphTraversalSource g,Client client) {
		this.g = g;
		this.client = client;
	}

}

3.3. GremlinClusterAutoConfiguration

  • src/main/resources/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.elf.dp.tinkerpop.config.GremlinClusterAutoConfiguration
import org.apache.tinkerpop.gremlin.driver.Client;
import org.apache.tinkerpop.gremlin.driver.Cluster;
import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GremlinClusterAutoConfiguration {

	@Autowired
	private TinkerpopProperties tp;

    @Bean
    @ConditionalOnMissingBean
    Cluster cluster() throws Exception {
        return Cluster.open(tp.getConfigFile());
    }

    @Bean
    @ConditionalOnMissingBean
    Client client() throws Exception {
        return cluster().connect();
    }

    @Bean
    @ConditionalOnMissingBean
    RemoteConnection remoteConnection(final Cluster cluster) {
    	String traversalName = tp.getTraversalName();
        return DriverRemoteConnection.using(cluster,traversalName);
    }

    @Bean
    @ConditionalOnMissingBean
    GraphTraversalSource graphTraversalSource(
        final RemoteConnection remoteConnection) throws Exception {
       return AnonymousTraversalSource.traversal()
		   .withRemote(remoteConnection);
    }

}

3.4. 注意事项

  • 连接使用GraphBinary和janusgraph-driver,
    它不允许访问内部JanusGraph组件,如ManagementSystem,
    要访问ManagementSystem,必须更新包和序列化.

  • janusgraph-driver包替换为janusgraph-core包

  • conf/remote-objects.yaml替换className序列化类,
    GraphBinaryMessageSerializerV1替换为GryoMessageSerializerV1d0,
    最新版Gremlin序列化类是GryoMessageSerializerV3d0,
    org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1
    org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0

4. Application

4.1. 引入starter

<dependency>
	<groupId>io.os.starter</groupId>
	<artifactId>starter-tinkerpop</artifactId>
</dependency>

4.2. remote-objects.yaml

hosts: [192.168.9.111]
port: 8182
serializer: {
    className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0,
    config: {
        ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry]
    }
}
# 推荐4K
connectionPool: {maxContentLength: 6553600}

4.3. application.yaml

server:
  port: 8080
  servlet:
    context-path: /tinkerpop
logging:
  level:
    root: warn
    '[org.apache.tinkerpop.gremlin.driver]': warn
    '[io.os.gremlin]': debug
io:
  os:
    tinkerpop:
      traversalName: g
      configFile: src/main/resources/conf/remote-objects.yaml

4.4. Repository

import java.util.List;
import java.util.Map;

import org.apache.tinkerpop.gremlin.driver.Client;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.springframework.stereotype.Repository;

@Repository
public class LineageRepository extends TinkerpopRepository{

	public LineageRepository(GraphTraversalSource g,Client client) {
		super(g, client);
	}

	public List<Map<Object,Object>> getLineageByGuid() {
		return g.V().elementMap().toList();
	}

}

4.5. Connector

import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.Map;
import org.apache.tinkerpop.gremlin.driver.Cluster;
import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

public class TinkerpopConnector {

	private static final Logger logger = LoggerFactory
		.getLogger(MethodHandles.lookup().lookupClass());

	//connect("192.168.9.111",8182);
	public static void connect(final String host,final int port) {
		if (StringUtils.hasText(host)) {
			String msg = String.format("%s can not be blank!",host);
			throw new IllegalArgumentException(msg);
		}
		if (port < 1) {
			throw new IllegalArgumentException("invalid port!");
		}
		Cluster.Builder builder = Cluster.build();
		builder.addContactPoint(host);
		builder.port(port);
		builder.serializer(new GraphBinaryMessageSerializerV1());

		Cluster cluster = builder.create();
		GraphTraversalSource g = AnonymousTraversalSource.traversal()
			.withRemote(DriverRemoteConnection.using(cluster));

		Long count = g.V().count().next();
		List<Map<Object, Object>> resultMapList = g.V().elementMap().toList();
		logger.info("janus record count:{}",count);

		resultMapList.forEach(resultMap -> {
			logger.info(resultMap.toString());
		});
		cluster.close();
	}

}

4.6. Entry

@SpringBootApplication
@EnableConfigurationProperties(value = {
	TinkerpopProperties.class
})
public class Entry {

	public static void main(String[] sa) {
		Class<?> cls = MethodHandles.lookup().lookupClass();
		SpringApplication.run(cls,sa);
	}

}

5. Python Collector

一些gremlin步骤(step)和谓词(predicate)名称在python中是关键字,
在Gremlin-Python中只能以_为后缀,如in()变为in_(),not()变为not_()等,
受影响的其它名称如all,and,as,from,global,is,list,or和set.

5.1. 安装Gremlin-Python

pip install gremlinpython==3.5.3

5.2. 导入相关包

from gremlin_python import statics
from gremlin_python.structure.graph import Graph
from gremlin_python.process.graph_traversal import __
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection

5.3. GraphTraversalSource

from gremlin_python.process.anonymous_traversal_source import traversal
connection = DriverRemoteConnection('ws://localhost:8182/gremlin','g')
g = traversal().withRemote(connection)

5.4. 执行遍历

age = g.V().has('name','elf').values('age').next()
print('elf is {} years old.'.format(age))