如何使用Gremlin和Java查询远程Apache Tinkerpop图形数据库?

3

我找不到一个全面的示例,介绍如何使用Gremlin和Java连接远程Apache Tinkerpop图形数据库并进行查询。我也无法使其正常工作。有没有之前做过类似事情的人可以提供任何建议?

我已经设置了Azure Cosmos数据库,以Graph-DB模式运行,需要使用Gremlin查询来修改和访问其数据。我拥有数据库主机名、端口、用户名和密码,并且能够执行查询,但只有在传递一个非常复杂的查询字符串时才能这样做。我希望能够利用org.apache.tinkerpop.gremlin.structure.Graph遍历方法,但我还没有搞清楚怎么做。

import java.util.List;
import java.util.concurrent.CompletableFuture;

import org.apache.tinkerpop.gremlin.driver.Result;
import org.apache.tinkerpop.gremlin.driver.ResultSet;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

//More imports...

@Service
public class SearchService {
    private final static Logger log = LoggerFactory.getLogger(SearchService.class);

    @Autowired
    private GraphDbConnection graphDbConnection;

    @Autowired
    private Graph graph;

    public Object workingQuery() {
        try {
            String query = "g.V('1234').outE('related').inV().both().as('v').project('vertex').by(select('v')).by(bothE().fold())";
            log.info("Submitting this Gremlin query: {}", query);
            ResultSet results = graphDbConnection.executeQuery(query);
            CompletableFuture<List<Result>> completableFutureResults = results.all();
            List<Result> resultList = completableFutureResults.get();
            Result result = resultList.get(0);
            log.info("Query result: {}", result.toString());
            return result.toString();
        } catch (Exception e) {
            log.error("Error fetching data.", e);
        }
        return null;
    }

    public Object failingQuery() {
        return graph.traversal().V(1234).outE("related").inV()
            .both().as("v").project("vertex").by("v").bothE().fold()
            .next();
/* I get an Exception:
"org.apache.tinkerpop.gremlin.process.remote.RemoteConnectionException: 
 java.lang.RuntimeException: java.lang.RuntimeException: 
 java.util.concurrent.TimeoutException: Timed out while waiting for an 
 available host - check the client configuration and connectivity to the 
 server if this message persists" */

    }

}

这是我的配置类:
import java.util.HashMap;
import java.util.Map;

import org.apache.tinkerpop.gremlin.driver.Cluster;
import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GraphDbConfig {
    private final static Logger log = LoggerFactory.getLogger(GraphDbConfig.class);

    @Value("${item.graph.hostName}")
    private String hostName;
    @Value("${item.graph.port}")
    private int port;
    @Value("${item.graph.username}")
    private String username;
    @Value("${item.graph.password}")
    private String password;
    @Value("${item.graph.enableSsl}")
    private boolean enableSsl;

    @Bean
    public Graph graph() {
        Map<String, String> graphConfig = new HashMap<>();
        graphConfig.put("gremlin.graph",
                "org.apache.tinkerpop.gremlin.process.remote.RemoteGraph");
        graphConfig.put("gremlin.remoteGraph.remoteConnectionClass",
                "org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection");
        Graph g = GraphFactory.open(graphConfig);
        g.traversal().withRemote(DriverRemoteConnection.using(cluster()));
        return g;
    }

    @Bean
    public Cluster cluster() {
        Cluster cluster = null;
        try {
            MessageSerializer serializer = new GraphSONMessageSerializerGremlinV2d0();

            Cluster.Builder clusterBuilder = Cluster.build().addContactPoint(hostName)
                    .serializer(serializer)
                    .port(port).enableSsl(enableSsl)
                    .credentials(username, password);
            cluster = clusterBuilder.create();
        } catch (Exception e) {
            log.error("Error in connecting to host address.", e);
        }
        return cluster;
    }

}

我需要定义这个连接组件,才能向数据库发送查询:

import org.apache.tinkerpop.gremlin.driver.Client;
import org.apache.tinkerpop.gremlin.driver.Cluster;
import org.apache.tinkerpop.gremlin.driver.ResultSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class GraphDbConnection {
    private final static Logger log = LoggerFactory.getLogger(GraphDbConnection.class);

    @Autowired
    private Cluster cluster;

    public ResultSet executeQuery(String query) {
        Client client = connect();
        ResultSet results = client.submit(query);
        closeConnection(client);
        return results;
    }

    private Client connect() {
        Client client = null;
        try {
            client = cluster.connect();
        } catch (Exception e) {
            log.error("Error in connecting to host address.", e);
        }
        return client;
    }

    private void closeConnection(Client client) {
        client.close();
    }
}
1个回答

3
您目前无法利用CosmosDB的远程API,因为它尚不支持Gremlin Bytecode。以下是相关链接:https://github.com/Azure/azure-documentdb-dotnet/issues/439https://feedback.azure.com/forums/263030-azure-cosmos-db/suggestions/33632779-support-gremlin-bytecode-to-enable-the-fluent-api。在此之前,您必须继续使用字符串。如果您正在使用Java,则可以尝试一种不太广为人知的功能:GroovyTranslator
gremlin> g = EmptyGraph.instance().traversal()
==>graphtraversalsource[emptygraph[empty], standard]
gremlin> translator = GroovyTranslator.of('g')
==>translator[g:gremlin-groovy]
gremlin> translator.translate(g.V().out('knows').has('person','name','marko').asAdmin().getBytecode())
==>g.V().out("knows").has("person","name","marko")

正如您所看到的,它将 Gremlin 的 Bytecode 转换为一个字符串的 Gremlin,您可以将其提交给 CosmosDB。稍后,当 CosmosDB 支持 Bytecode 时,您可以放弃 GroovyTranslator 并从构造您的 GraphTraversalSourceEmptyGraph 转变,然后一切都应该开始工作了。为了使这个过程真正无缝,您可以采取额外的步骤,并编写一个类似于 TinkerPop 的 RemoteStrategyTraversalStrategy,执行类似的操作。与该策略提交 Bytecode 不同,您只需使用 GroovyTranslator 并提交 Gremlin 字符串即可。这种方法会使转换更加容易,因为当 CosmosDB 支持 Bytecode 时,您只需要删除自定义的 TraversalStrategy 并按标准方式重新配置远程的 GraphTraversalSource 即可。

非常感谢!GroovyTranslator 对我来说现在完全可以使用。 - SnoopDougg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接