问题描述
我正在构建一个需要连接到远程 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 节点才能更新绑定。假设很少创建图,这个解决方案至少是一些东西。