使用 Java 的 Janusgraph 远程遍历

问题描述

我正在构建一个需要连接到远程 JanusGraph 服务器并动态创建图形的 Java 应用程序。

我已经安装/配置了一个带有 Berkeley 数据库后端和 ConfigurationManagementGraph 支持的单节点 JanusGraph 服务器,以便我可以在服务器上创建/管理多个图形。

Gremlin 控制台中,我可以连接到远程服务器、创建图形、创建顶点等。示例:

gremlin> :remote connect tinkerpop.server conf/remote.yaml session
gremlin> :remote console

gremlin> map = new HashMap<String,Object>();
gremlin> map.put("storage.backend","berkeleyje");
gremlin> map.put("storage.directory","db/test");
gremlin> ConfiguredGraphFactory.createTemplateConfiguration(new MapConfiguration(map));
gremlin> ConfiguredGraphFactory.create("test");

gremlin> graph = ConfiguredGraphFactory.open("test");
gremlin> g = graph.traversal();
gremlin> g.addV("person").property("name","peter");
gremlin> g.tx().commit();
gremlin> graph.vertices().size();
==>1
gremlin> g.V();
==>v[4288]
gremlin> g.V().count();
==>1
gremlin> g.close();

到目前为止一切顺利。在Java 端,我可以连接到远程服务器并通过 Client.submit() 方法发出命令。在以下示例中,我连接到远程服务器并创建一个名为“test2”的新图:

Cluster cluster = Cluster.build()
    .addContactPoint(host)
    .port(port)
    .serializer(Serializers.GRYO_V3D0)
    .create();

String name = "test2";

String sessionId = UUID.randomUUID().toString();
Client client = cluster.connect(sessionId);
client.submit("map = new HashMap<String,Object>();");
client.submit("map.put(\"storage.backend\",\"berkeleyje\");");
client.submit("map.put(\"storage.directory\",\"db/" + name + "\");");
client.submit("ConfiguredGraphFactory.createTemplateConfiguration(new MapConfiguration(map));");
client.submit("ConfiguredGraphFactory.create(\"" + name + "\");");

我可以使用 client.submit() 方法以编程方式确认图形已创建并查看其他图形:

ResultSet results = client.submit("ConfiguredGraphFactory.getGraphNames()");
Iterator<Result> it = results.iterator();
while (it.hasNext()){
    Result result = it.next();
    String graphName = result.getString();
    System.out.println(graphName);
}

接下来我想连接到一个图形并以编程方式遍历节点(在 Java 中)。但是,我似乎无法弄清楚如何做到这一点。从我读过的内容来看,它应该是这样简单的:

DriverRemoteConnection conn = DriverRemoteConnection.using(client,name); //"_traversal"
GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(conn);

这些命令不会引发任何错误,但 GraphTraversalSource 似乎为空:

System.out.println(g.getGraph()); //always returns emptygraph[empty]
System.out.prinltn(g.V()); //Appears to be empty [GraphStep(vertex,[])]
Iterator<Vertex> it = g.getGraph().vertices(); //empty

有关如何在 Java 中为远程 JanusGraph 服务器获取 GraphTraversalSource 的任何建议?我怀疑我的问题与 ConfigurationManagementGraph 有关,但我无法解决。再次,client.submit() 工作。如果我能做这样的事情会很酷:

GraphTraversalSource g = (GraphTraversalSource) client.submit("ConfiguredGraphFactory.open(\"" + name + "\");").iterator().next();

...当然,那是行不通的

更新

查看代码,似乎忽略了传递给 DriverRemoteConnection 的图形名称 (remoteTraversalSourceName)。

从 DriverRemoteConnection 开始:

DriverRemoteConnection conn = DriverRemoteConnection.using(client,name); 

在幕后,图形名称 (remoteTraversalSourceName) 仅用于设置别名(例如 client.alias(name);)

接下来,在 AnonymousTraversalSource.traversal().withRemote() 方法

GraphTraversalSource g = AnonymousTraversalSource.traversal().withRemote(conn);

在幕后,withRemote() 正在调用

traversalSourceClass.getConstructor(RemoteConnection.class).newInstance(remoteConnection);

其中 traversalSourceClass 是 GraphTraversalSource.class

与此相同:

g = GraphTraversalSource.class.getConstructor(RemoteConnection.class).newInstance(conn);

最后,GraphTraversalSource 的构造函数如下所示:

public GraphTraversalSource(final RemoteConnection connection) {
    this(EmptyGraph.instance(),TraversalStrategies.GlobalCache.getStrategies(EmptyGraph.class).clone());
    this.connection = connection;
    this.strategies.addStrategies(new RemoteStrategy(connection));
}

如您所见,GraphTraversalSource 中的图形变量从未设置。

我怀疑 (a) 我不应该使用 AnonymousTraversalSource 或 (b) 我需要以其他方式实例化 GraphTraversalSource,也许使用 Graph 对象。

解决方法

更新答案

您使用的通道化器很可能是 Tinkerpop 的通道化器 org.apache.tinkerpop.gremlin.server.channel.WsAndHttpChannelizer。将其替换为 Janus 的通道化器 org.janusgraph.channelizers.JanusGraphWsAndHttpChannelizer 可以正确地将图形绑定到连接。

旧答案

当通道化器为 org.apache.tinkerpop.gremlin.server.channel.WsAndHttpChannelizer 时使用的解决方法。

我遇到了同样的问题。目前,我找到的解决方法是在 Janus 启动期间绑定遍历。 除了 gremlin-server.yaml and janusgraph.properties,我还用内容覆盖了 empty-sample.groovy

def globals = [:]
ConfiguredGraphFactory.getGraphNames().each { name ->
  globals << [ (name + "_traversal") : ConfiguredGraphFactory.open(name).traversal()]
}

现在您创建的图表可在 yourgraphname_traversal 处获得:

import org.apache.tinkerpop.gremlin.driver.Cluster
import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
import org.apache.tinkerpop.gremlin.driver.ser.Serializers
import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource
...
  val cluster = Cluster.build()
    .addContactPoint("your_load_balancer_host")
    .port(8182)
    .serializer(Serializers.GRAPHBINARY_V1D0.simpleInstance())
    .create()
  val remoteConnection = DriverRemoteConnection.using(cluster,"yourgraphname_traversal")
  val g = AnonymousTraversalSource.traversal().withRemote(remoteConnection)

该解决方案并不理想,因为它需要重新启动所有 Janus 节点才能更新绑定。假设很少创建图,这个解决方案至少是一些东西。