当前位置:

首页 > 如何在Java中解析NebulaGraph数据库数据?

如何在Java中解析NebulaGraph数据库数据?

先用Docker镜像准备环境:dockerpullalbertlatacz/java-repldockerrun--rm-it\--network=nebula-net\-v~:/root\albertlatacz/java-repl\bashaptupdate-y&&aptinstallca-certificates-ywgethttps://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz--no-c

先用 Docker 镜像准备环境:

docker pull albertlatacz/java-repl
docker run --rm -it \
    --network=nebula-net \
    -v ~:/root \
    albertlatacz/java-repl \
    bash
apt update -y && apt install ca-certificates -y
wget https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz --no-check-certificate
tar xzvf apache-maven-3.8.6-bin.tar.gz
wget https://github.com/vesoft-inc/nebula-java/archive/refs/tags/v3.0.0.tar.gz
tar xzvf v3.0.0.tar.gz
cd nebula-java-3.0.0/
../apache-maven-3.8.6/bin/mvn dependency:copy-dependencies
../apache-maven-3.8.6/bin/mvn -B package -Dmaven.test.skip=true
java -jar ../javarepl/javarepl.jar

在执行完上面的 java -jar ../javarepl/javarepl.jar 之后,我们就进入了交互式的 Java Shell(REPL)。我们不用再做编译、执行、print 这样的慢反馈来调试和研究我们的代码了,是不是很方便?

root@a2e26ba62bb6:/javarepl/nebula-java-3.0.0# java -jar ../javarepl/javarepl.jar
Welcome to JavaREPL version 428 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111)
Type expression to evaluate, :help for more options or press tab to auto-complete.
Connected to local instance at http://localhost:43707
java> System.out.println("Hello, World!");
Hello, World!
java>

首先我们在 java> 提示符下,这些来把必须的类路径和导入:

:cp /javarepl/nebula-java-3.0.0/client/target/client-3.0.0.jar
:cp /javarepl/nebula-java-3.0.0/client/target/dependency/fastjson-1.2.78.jar
:cp /javarepl/nebula-java-3.0.0/client/target/dependency/slf4j-api-1.7.25.jar
:cp /javarepl/nebula-java-3.0.0/client/target/dependency/slf4j-log4j12-1.7.25.jar
:cp /javarepl/nebula-java-3.0.0/client/target/dependency/commons-pool2-2.2.jar
:cp /javarepl/nebula-java-3.0.0/client/target/dependency/log4j-1.2.17.jar
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vesoft.nebula.ErrorCode;
import com.vesoft.nebula.client.graph.NebulaPoolConfig;
import com.vesoft.nebula.client.graph.data.CASignedSSLParam;
import com.vesoft.nebula.client.graph.data.HostAddress;
import com.vesoft.nebula.client.graph.data.ResultSet;
import com.vesoft.nebula.client.graph.data.SelfSignedSSLParam;
import com.vesoft.nebula.client.graph.data.ValueWrapper;
import com.vesoft.nebula.client.graph.net.NebulaPool;
import com.vesoft.nebula.client.graph.net.Session;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.*;

我们可以从这 Java 环境连接到 NebulaGraph。在下面的例子中,我用了自己的 graphd 的 IP 和端口作为例子:

NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig();
nebulaPoolConfig.setMaxConnSize(10);
List addresses = Arrays.asList(new HostAddress("192.168.8.127", 9669));
NebulaPool pool = new NebulaPool();
pool.init(addresses, nebulaPoolConfig);
Session session = pool.getSession("root", "nebula", false);

通过调用 execute 方法获得不太容易懂的 ResultSet 对象

刚接触 NebulaGraph Java 客户端的大家一定对这个 ResultSet 对象有些愁。别担心,借助我们的环境,十分钟把它搞通。这里我们执行一个简单的返回 vertex 顶点的结果看看:

ResultSet resp = session.execute("USE basketballplayer;MATCH (n:player) WHERE n.name==\"Tim Duncan\" RETURN n");

我们可以参考 ResultSet 的代码:client/graph/data/ResultSet.java

其实可以先不看,跟着教程往下走。一般来说,查询结果都是二维表,ResultSet 针对行和列提供了常见的处理方法。通常,我们会获取每一行结果,再解析它,而关键的问题是每一个值要怎么处理。

java> resp.isSucceeded()
java.lang.Boolean res9 = true
java> resp.rowsSize()
java.lang.Integer res16 = 1
java> rows = resp.getRows()
java.util.ArrayList rows = [Row (
  values : [
    ,
        tags : [
          Tag (
              name : 70 6C 61 79 65 72,
              props : {
                [B@5264a468 : 
                [B@496b8e10 : 
              }
            )
        ]
      )>
  ]
)]
java> row0 = resp.rowValues(0)
java.lang.Iterable res10 = ColumnName: [n], Values: [("player100" :player {name: "Tim Duncan", age: 42})]

回到本次 query 语句,它其实是在返回一个 vertex 顶点:

(root@nebula) [basketballplayer]> match (n:player) WHERE n.name == "Tim Duncan" return n
+----------------------------------------------------+
| n                                                  |
+----------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------+
Got 1 rows (time spent 2116/44373 us)

通过上面的几个方法,我们其实能够获得这个顶点的值:

v = Class.forName("com.vesoft.nebula.Value")
v.getDeclaredMethods()

然而,这个 com.vesoft.nebula.Value 的值的类提供的方法特别原始,这也是让大家犯愁数据解析的原因。所以,在这个教程中最重要的一个带走的经验(除了利用 REPL 之外)就是:非必要不要去取这个原始的类,我们应该去取得 ValueWrapper 封装之后的值!!!

注意:其实我们有更轻松地方法,就是用 executeJson 直接获得 JSON string。别担心,会在后面提到,不过这个方法要 2.6 之后才支持。

那么问题来了,如何使用 ValueWrapper 封装呢?其实答案已经在上面了,大家可以回去看看,resp.rowValues(0) 的类型正是 ValueWrapper 的可迭代对象!

所以,正确打开方式是迭它!迭它!迭它!其实这个就是代码库里的 GraphClientExample 的一部分例子了,我们把它迭代取出来,放到 wrappedValueList 里慢慢把玩:

import java.util.ArrayList;
import java.util.List;
List wrappedValueList = new ArrayList<>();
for (int i = 0; i < resp.rowsSize(); i++) {
    ResultSet.Record record = resp.rowValues(i);
    for (ValueWrapper value : record.values()) {
        wrappedValueList.add(value);
        if (value.isLong()) {
            System.out.printf("%15s |", value.asLong());
        }
        if (value.isBoolean()) {
            System.out.printf("%15s |", value.asBoolean());
        }
        if (value.isDouble()) {
            System.out.printf("%15s |", value.asDouble());
        }
        if (value.isString()) {
            System.out.printf("%15s |", value.asString());
        }
        if (value.isTime()) {
            System.out.printf("%15s |", value.asTime());
        }
        if (value.isDate()) {
            System.out.printf("%15s |", value.asDate());
        }
        if (value.isDateTime()) {
            System.out.printf("%15s |", value.asDateTime());
        }
        if (value.isVertex()) {
            System.out.printf("%15s |", value.asNode());
        }
        if (value.isEdge()) {
            System.out.printf("%15s |", value.asRelationship());
        }
        if (value.isPath()) {
            System.out.printf("%15s |", value.asPath());
        }
        if (value.isList()) {
            System.out.printf("%15s |", value.asList());
        }
        if (value.isSet()) {
            System.out.printf("%15s |", value.asSet());
        }
        if (value.isMap()) {
            System.out.printf("%15s |", value.asMap());
        }
    }
    System.out.println();
}

上边这些很丑的 if 就是关键了,我们知道 query 的返回值可能是多种类型的,他们分为:

  • 图语义的:点、边、路径

  • 数据类型:String,日期,列表,集合…等等

这里的关键是,我们要使用 ValueWrapper 为我们准备好 asXxx 方法。如果这个值是一个顶点,那么这个 Xxx 就是 Node。同理如果是边的话,这个 Xxx 就是 Relationship。

所以,我给大家看看咱们这个返回点结果的情况下的 asNode() 方法:

java> v = wrappedValueList.get(0)
com.vesoft.nebula.client.graph.data.ValueWrapper v = ("player100" :player {name: "Tim Duncan", age: 42})
java> v.asNode()
com.vesoft.nebula.client.graph.data.Node res16 = ("player100" :player {name: "Tim Duncan", age: 42})
java> node = v.asNode()
com.vesoft.nebula.client.graph.data.Node node = ("player100" :player {name: "Tim Duncan", age: 42})

顺便说一下,借助于 Java 的反射 reflection,我们可以在这个交互程序里做类似于 Python 里 dir() 的事情:实时地去获取一个类支持的方法。像这样,省去了查代码的时间。

java> rClass=Class.forName("com.vesoft.nebula.client.graph.data.ResultSet")
java.lang.Class r = class com.vesoft.nebula.client.graph.data.ResultSet
java> rClass.getDeclaredMethods()
java.lang.reflect.Method[] res20 = [public java.util.List com.vesoft.nebula.client.graph.data.ResultSet.getColumnNames(), public int com.vesoft.nebula.client.graph.data.ResultSet.rowsSize(), public com.vesoft.nebula.client.graph.data.ResultSet$Record com.vesoft.nebula.client.graph.data.ResultSet.rowValues(int), public java.util.List com.vesoft.nebula.client.graph.data.ResultSet.colValues(java.lang.String), public java.lang.String com.vesoft.nebula.client.graph.data.ResultSet.getErrorMessage(), public boolean com.vesoft.nebula.client.graph.data.ResultSet.isSucceeded(), public int com.vesoft.nebula.client.graph.data.ResultSet.getErrorCode(), public java.lang.String com.vesoft.nebula.client.graph.data.ResultSet.getSpaceName(), public int com.vesoft.nebula.client.graph.data.ResultSet.getLatency(), public com.vesoft.nebula.graph.PlanDescription com.vesoft.nebula.client.graph.data.ResultSet.getPlanDesc(), public java.util.List com.vesoft.nebula.client.graph.data.ResultSet.getRows(), public java.lang.String com.vesoft.nebula.client.graph.data.ResultSet.getComment(), public java.lang.String com.vesoft.nebula.client.graph.data.ResultSet.toString(), public boolean com.vesoft.nebula.client.graph.data.ResultSet.isEmpty(), public java.util.List com.vesoft.nebula.client.graph.data.ResultSet.keys()]

这样:

java> nodeClass=Class.forName("com.vesoft.nebula.client.graph.data.Node")
java.lang.Class nodeClass = class com.vesoft.nebula.client.graph.data.Node
java> nodeClass.getDeclaredMethods()
java.lang.reflect.Method[] res20 = [public boolean com.vesoft.nebula.client.graph.data.Node.hasTagName(java.lang.String), public boolean com.vesoft.nebula.client.graph.data.Node.hasLabel(java.lang.String), public java.util.List com.vesoft.nebula.client.graph.data.Node.tagNames(), public java.util.HashMap com.vesoft.nebula.client.graph.data.Node.properties(java.lang.String) throws java.io.UnsupportedEncodingException, public java.util.List com.vesoft.nebula.client.graph.data.Node.labels(), public boolean com.vesoft.nebula.client.graph.data.Node.equals(java.lang.Object), public java.lang.String com.vesoft.nebula.client.graph.data.Node.toString(), public java.util.List com.vesoft.nebula.client.graph.data.Node.values(java.lang.String), public int com.vesoft.nebula.client.graph.data.Node.hashCode(), public com.vesoft.nebula.client.graph.data.ValueWrapper com.vesoft.nebula.client.graph.data.Node.getId(), public java.util.List com.vesoft.nebula.client.graph.data.Node.keys(java.lang.String) throws java.io.UnsupportedEncodingException]

看到这里,大家应该体会到封装了 ValueWrapper 的好处了吧?它提供了方便的符合直觉的方法,对于 Node 类型来说,它提供了 tagNames()properties()labels() 等等非常好用的方法:

java> node.properties("player")
java.util.HashMap res11 = {name="Tim Duncan", age=42}
java> node.tagNames()
java.util.ArrayList res12 = [player]
java> node.labels()
java.util.ArrayList res13 = [player]
java> node.values("player")
java.util.ArrayList res14 = [42, "Tim Duncan"]

我们这里只展示了顶点数据类型的处理、解析方式(RETURN n),像其他的数据类型比如边(edge)、路径(path)或者地理数据、时间数据,用这种方式(看有什么方法,再交互地去试试方法怎么用)也是一样的,对吧?

直接返回 JSON 的 executeJson 方法

最后,好消息是:从 v2.6 开始,NebulaGraph 可以直接返回 JSON 的 String 了,我们上面的纠结也都不是必要的了:

java> String resp_json = session.executeJson("USE basketballplayer;MATCH (n:player) WHERE n.name==\"Tim Duncan\" RETURN n");
java.lang.String resp_json = "
{
   "errors":[
      {
         "code":0
      }
   ],
   "results":[
      {
         "spaceName":"basketballplayer",
         "data":[
            {
               "meta":[
                  {
                     "type":"vertex",
                     "id":"player100"
                  }
               ],
               "row":[
                  {
                     "player.age":42,
                     "player.name":"Tim Duncan"
                  }
               ]
            }
         ],
         "columns":[
            "n"
         ],
         "errors":{
            "code":0
         },
         "latencyInUs":4761
      }
   ]
}
"
本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
相关文章 更多
从产业趋势到产品实践  GBASE技术云享会解码国产数据库发展新机遇
从产业趋势到产品实践 GBASE技术云享会解码国产数据库发展新机遇

2026GBASE技术云享会聚焦数据库技术演进与行业实践,探讨AI原生数据库能力、全栈产品迭代及开源生态共建。产业正从高速增长迈入高质量发展阶段,技术实力是国产数据库立足根本。

谷歌浏览器Mac版入口
谷歌浏览器Mac版入口

谷歌浏览器Mac版官方安装指南 谷歌浏览器Mac版官方安装入口是https://www.google.com/chrome/,需macOS 12+系统、500MB空间,下载.dmg后拖入应用程序安装,支持多设备同步、性能优化与隐私保护功能。 苹果电脑Chrome的安装入口究竟在哪里?这个问题最近可是

Chrome浏览器JS脚本不运行怎么办
Chrome浏览器JS脚本不运行怎么办

Chrome中JavaScript未执行需依次检查:一、移除站点级禁用并添加允许域名;二、开启全局JavaScript开关;三、禁用干扰扩展;四、在开发者工具中启用JavaScript;五、重置内容设置为默认。 有时在Chrome里打开网页,会发现交互按钮点了没反应,数据加载不出来,页面仿佛“静止”

IE浏览器怀旧版在线网址
IE浏览器怀旧版在线网址

IE浏览器怀旧版在线网址:一次精准的技术时光回溯 最近,不少老用户和怀旧爱好者在反复搜索一个问题:那个经典的Internet Explorer,如今还能在哪里原汁原味地体验到?答案指向一个特定的地址:https://ie.microsoft.com/legacy/。 这个网站远不止是一个简单的“皮肤

火狐浏览器有哪些设置功能
火狐浏览器有哪些设置功能

火狐浏览器五大核心设置功能:解锁高效、安全与个性化体验 火狐浏览器功能强大,但如果不仔细挖掘,很多能大幅提升效率和安全性的设置可能就“藏着掖着”了。这就好比拥有一台高性能设备,却只用了基础模式。那么,如何把它调整到最顺手、最安全的状态?接下来,我们就聚焦于当前版本(截至2025年末)最关键的五大设置

chrome搜索免验证入口
chrome搜索免验证入口

Chrome官方免验证入口为https://www.google.cn/chrome/,提供全平台安装包、免登录即用、本地化安全机制及引擎级性能优化。 到底该去哪里找正版、免费且无需繁琐验证的Chrome浏览器入口?这个问题困扰了不少网友。今天,我们就来直通核心,为大家详细拆解Chrome引擎的官方

java heap space 选型思路:使用场景与区别整理
java heap space 选型思路:使用场景与区别整理

Java堆是JVM存储对象的核心内存区域,配置需结合场景:单体应用适中设置;大数据处理需大堆并关注GC停顿;微服务强调快速启动;高并发需精细划分堆区域。关键参数-Xms和-Xmx建议等值以稳定性能。垃圾回收器选择影响效率,如G1适用于大堆,ZGC可实现低停顿。内存错误时需监控堆状态。

java heap space 使用中遇到的问题怎么解决
java heap space 使用中遇到的问题怎么解决

Java堆内存溢出错误通常因内存泄漏、数据处理需求过大或JVM参数配置不当引起。排查时可借助jmap、堆转储及MAT等工具定位问题。解决方案包括调整JVM内存参数(如-Xmx)、修复代码中的内存泄漏、优化大数据处理逻辑,并建立持续监控与预防机制,以保障应用稳定运行。

java xml 选型思路:使用场景与区别整理
java xml 选型思路:使用场景与区别整理

XML在Java开发中用于配置、数据交换等场景。解析方式主要有DOM、SAX、StAX及第三方库。DOM适合操作小文件,SAX/StAX适合处理大文件流,JAXB用于对象与XML映射。选型需结合数据大小、内存、性能及团队熟悉度,现代框架常封装底层解析。

using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。