圖數(shù)據(jù)庫NebulaGraph的Java 數(shù)據(jù)解析實(shí)踐與指導(dǎo)詳解
愉快、干凈的 Java 交互環(huán)境
如何快速、即時(shí)、符合直覺地去處理 Nebula Java Client 中的數(shù)據(jù)解析?讀這一篇就夠了。
圖數(shù)據(jù)庫 NebulaGraph 的論壇和微信群里,有不少用戶問及了 Java 客戶端數(shù)據(jù)解析的問題。在本文教你一種簡(jiǎn)單的方式同返回結(jié)果交互,快速、即時(shí)地拿到解析數(shù)據(jù)。
本文最為關(guān)鍵步驟之一,便是用幾行代碼,準(zhǔn)備一個(gè)干凈的交互式 NebulaGraph Java REPL 環(huán)境。
多虧了 Java-REPL,我們可以很方便地(像 iPython 那樣)去實(shí)時(shí)交互地調(diào)試、分析 NebulaGraph Java 客戶端。
下面,開始實(shí)操。
先用 Docker 鏡像準(zhǔn)備環(huán)境:
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
在執(zhí)行完上面的 java -jar ../javarepl/javarepl.jar
之后,我們就進(jìn)入了交互式的 Java Shell(REPL)。我們不用再做編譯、執(zhí)行、print 這樣的慢反饋來調(diào)試和研究我們的代碼了,是不是很方便?
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>
首先我們?cè)?java>
提示符下,這些來把必須的類路徑和導(dǎo)入:
: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 環(huán)境連接到 NebulaGraph。在下面的例子中,我用了自己的 graphd 的 IP 和端口作為例子:
NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); nebulaPoolConfig.setMaxConnSize(10); List<HostAddress> 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);
通過調(diào)用 execute 方法獲得不太容易懂的 ResultSet 對(duì)象
剛接觸 NebulaGraph Java 客戶端的大家一定對(duì)這個(gè) ResultSet 對(duì)象有些愁。別擔(dān)心,借助我們的環(huán)境,十分鐘把它搞通。這里我們執(zhí)行一個(gè)簡(jiǎn)單的返回 vertex 頂點(diǎn)的結(jié)果看看:
ResultSet resp = session.execute("USE basketballplayer;MATCH (n:player) WHERE n.name==\"Tim Duncan\" RETURN n");
我們可以參考 ResultSet 的代碼:client/graph/data/ResultSet.java
其實(shí)可以先不看,跟著教程往下走。一般來說,查詢結(jié)果都是二維表,ResultSet 針對(duì)行和列提供了常見的處理方法。通常,我們會(huì)獲取每一行結(jié)果,再解析它,而關(guān)鍵的問題是每一個(gè)值要怎么處理。
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 : [ <Value vVal:Vertex ( vid : <Value sVal:70 6c 61 79 65 72 31 30 30>, tags : [ Tag ( name : 70 6C 61 79 65 72, props : { [B@5264a468 : <Value iVal:42> [B@496b8e10 : <Value sVal:54 69 6d 20 44 75 6e 63 61 6e> } ) ] )> ] )] java> row0 = resp.rowValues(0) java.lang.Iterable<com.vesoft.nebula.client.graph.data.ValueWrapper> res10 = ColumnName: [n], Values: [("player100" :player {name: "Tim Duncan", age: 42})]
回到本次 query 語句,它其實(shí)是在返回一個(gè) vertex 頂點(diǎn):
(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)
通過上面的幾個(gè)方法,我們其實(shí)能夠獲得這個(gè)頂點(diǎn)的值:
v = Class.forName("com.vesoft.nebula.Value") v.getDeclaredMethods()
然而,這個(gè) com.vesoft.nebula.Value
的值的類提供的方法特別原始,這也是讓大家犯愁數(shù)據(jù)解析的原因。所以,在這個(gè)教程中最重要的一個(gè)帶走的經(jīng)驗(yàn)(除了利用 REPL 之外)就是:非必要不要去取這個(gè)原始的類,我們應(yīng)該去取得 ValueWrapper
封裝之后的值!??!
注意:其實(shí)我們有更輕松地方法,就是用 executeJson 直接獲得 JSON string。別擔(dān)心,會(huì)在后面提到,不過這個(gè)方法要 2.6 之后才支持。
那么問題來了,如何使用 ValueWrapper
封裝呢?其實(shí)答案已經(jīng)在上面了,大家可以回去看看,resp.rowValues(0)
的類型正是 ValueWrapper
的可迭代對(duì)象!
所以,正確打開方式是迭它!迭它!迭它!其實(shí)這個(gè)就是代碼庫里的 GraphClientExample 的一部分例子了,我們把它迭代取出來,放到 wrappedValueList
里慢慢把玩:
import java.util.ArrayList; import java.util.List; List<ValueWrapper> 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 就是關(guān)鍵了,我們知道 query 的返回值可能是多種類型的,他們分為:
- 圖語義的:點(diǎn)、邊、路徑
- 數(shù)據(jù)類型:String,日期,列表,集合…等等
這里的關(guān)鍵是,我們要使用 ValueWrapper
為我們準(zhǔn)備好 asXxx
方法。如果這個(gè)值是一個(gè)頂點(diǎn),那么這個(gè) Xxx 就是 Node。同理如果是邊的話,這個(gè) Xxx 就是 Relationship。
所以,我給大家看看咱們這個(gè)返回點(diǎn)結(jié)果的情況下的 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,我們可以在這個(gè)交互程序里做類似于 Python 里 dir()
的事情:實(shí)時(shí)地去獲取一個(gè)類支持的方法。像這樣,省去了查代碼的時(shí)間。
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]
看到這里,大家應(yīng)該體會(huì)到封裝了 ValueWrapper
的好處了吧?它提供了方便的符合直覺的方法,對(duì)于 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"]
我們這里只展示了頂點(diǎn)數(shù)據(jù)類型的處理、解析方式(RETURN n
),像其他的數(shù)據(jù)類型比如邊(edge)、路徑(path)或者地理數(shù)據(jù)、時(shí)間數(shù)據(jù),用這種方式(看有什么方法,再交互地去試試方法怎么用)也是一樣的,對(duì)吧?
直接返回 JSON 的 executeJson 方法
最后,好消息是:從 v2.6 開始,NebulaGraph 可以直接返回 JSON 的 String 了,我們上面的糾結(jié)也都不是必要的了:
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 } ] } "
我相信大家肯定比我更擅長處理 JSON 的結(jié)果了哈~~
結(jié)論
- 如果你有條件(v2.6 及其以上版本)用 JSON,情況會(huì)很容易,甚至你都不太需要本文的方法,不過本文可能會(huì)讓你的交互環(huán)境更容易;
- 如果你不得不和 ResultSet 打交道,記得用 ValueWrapper。因?yàn)槲覀兛梢杂?
asNode()
,asRelationship()
和asPath()
,封裝之后的值比原始的值可愛太多了!- 通過 REPL 工具,結(jié)合 Java 的 reflection 加上源代碼本身,分析數(shù)據(jù)的處理將變得異常順滑。
Happy Graphing!
謝謝你讀完本文 (///▽///)
NebulaGraph Desktop,Windows 和 macOS 用戶安裝圖數(shù)據(jù)庫的綠色通道,10s 拉起搞定海量數(shù)據(jù)的圖服務(wù)。通道傳送門:c.nxw.so/9ShUq
GitHub 閱讀 使用 http://c.nxw.so/8yTlk
以上就是圖數(shù)據(jù)庫NebulaGraph的Java 數(shù)據(jù)解析實(shí)踐與指導(dǎo)詳解的詳細(xì)內(nèi)容,更多關(guān)于 Java解析圖數(shù)據(jù)庫NebulaGraph的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java微信二次開發(fā)(三) Java微信各類型消息封裝
這篇文章主要為大家詳細(xì)介紹了Java微信二次開發(fā)第三篇,Java微信各類型消息封裝,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04java實(shí)現(xiàn)滑動(dòng)驗(yàn)證解鎖
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)滑動(dòng)驗(yàn)證解鎖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07SpringBoot日志文件的實(shí)現(xiàn)示例
日志是程序中的重要組成部分,使用日志可以快速的發(fā)現(xiàn)和定位問題,本文主要介紹了SpringBoot日志文件的實(shí)現(xiàn)示例,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08Spring?Boot項(xiàng)目Jar包加密實(shí)戰(zhàn)教程
本文詳細(xì)介紹了如何在Spring?Boot項(xiàng)目中實(shí)現(xiàn)Jar包加密,我們首先了解了Jar包加密的基本概念和作用,然后學(xué)習(xí)了如何使用Spring?Boot的Jar工具和第三方庫來實(shí)現(xiàn)Jar包的加密和解密,感興趣的朋友一起看看吧2024-02-02java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):循環(huán)鏈表和棧
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)鏈表、棧的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Java數(shù)據(jù)結(jié)構(gòu)中循環(huán)鏈表、棧、的功能、定義及使用方法,需要的朋友可以參考下2021-08-08java連接mysql數(shù)據(jù)庫亂碼的解決方法
這篇文章主要介紹通過java連接mysql數(shù)據(jù)庫的時(shí)候,頁面出現(xiàn)亂碼,這里簡(jiǎn)單分享下解決方法, 需要的朋友可以參考下2013-05-05java 中JDBC連接數(shù)據(jù)庫代碼和步驟詳解及實(shí)例代碼
這篇文章主要介紹了java 中JDBC連接數(shù)據(jù)庫代碼和步驟詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02SpringMVC中@ModelAttribute與@RequestBody的區(qū)別及說明
這篇文章主要介紹了SpringMVC中@ModelAttribute與@RequestBody的區(qū)別及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Java實(shí)現(xiàn)紀(jì)元秒和本地日期時(shí)間互換的方法【經(jīng)典實(shí)例】
這篇文章主要介紹了Java實(shí)現(xiàn)紀(jì)元秒和本地日期時(shí)間互換的方法,結(jié)合具體實(shí)例形式分析了Java日期時(shí)間相關(guān)操作技巧,需要的朋友可以參考下2017-04-04