這篇文章主要講解了“Nebula Graph和SpringBoot環(huán)境連接及查詢?nèi)绾螌崿F(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Nebula Graph和SpringBoot環(huán)境連接及查詢?nèi)绾螌崿F(xiàn)”吧!
在濱江等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計制作、成都網(wǎng)站設(shè)計 網(wǎng)站設(shè)計制作按需求定制制作,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),網(wǎng)絡(luò)營銷推廣,成都外貿(mào)網(wǎng)站制作,濱江網(wǎng)站建設(shè)費用合理。
Nebula Graph 是一款開源的、分布式的、易擴展的原生圖數(shù)據(jù)庫,能夠承載包含數(shù)千億個點和數(shù)萬億條邊的超大規(guī)模數(shù)據(jù)集,并且提供毫秒級查詢。
當(dāng)前Nebula Graph的最新版本是3.2.1, 根據(jù)官方的文檔進行配置
支持分布式. 相對于Neo4j, TigerGraph這些圖數(shù)據(jù)庫, Nebula 是面向分布式設(shè)計的, 因此對集群的支持比較完備, 在規(guī)模上上限要高很多. 在實際項目中存儲了180億的點邊, 這個數(shù)量對于Neo4j和TigerGraph是比較困難的.
支持圖空間. 各個圖空間的ID是互不干擾的, 但是在同一個圖空間里ID的類型和長度必須一致. 注意這個一致約束的是所有的點和邊. Nebula 可以使用int64作為ID, 也可以用字符串, 但是字符串需要指定一個長度, 例如64個字節(jié). 相對于只能用長整數(shù)的Neo4j, ID設(shè)計上更自由靈活.
點對應(yīng)的類型叫TAG, 邊對應(yīng)的類型叫EDGE
TAG和EDGE都會對應(yīng)一組的屬性(map, 或者說dict)
一個點可以對多個TAG, 每個TAG一組屬性, 多組屬性. 項目中建議一開始不要用多TAG, 在整個圖結(jié)構(gòu)穩(wěn)定后, 再做合并
一個邊只對應(yīng)一個EDGE, 一組屬性
Nebula 用的是自定義的查詢語法 GQL, 和 cypher 語法基本一樣
除了點邊的ID和關(guān)聯(lián)關(guān)系外, 只有帶索引的屬性可以查詢. 這點和其它圖數(shù)據(jù)庫不一樣, 其它數(shù)據(jù)庫即使沒有索引, 慢是慢點但是不報錯, Nebula直接給你返回錯誤.
對于返回數(shù)量較大的查詢, Nebula會強制查詢必須帶limit
Nebula 單節(jié)點穩(wěn)定性是有問題的, 在3.2.1版本中觀察到偶爾會出現(xiàn)服務(wù)自行退出, 如果在生產(chǎn)環(huán)境使用, 需要有后臺監(jiān)控進行心跳檢測和自動啟動
下面列出一些常用的查詢
-- 列出圖空間 SHOW SPACES; -- 列出tag(點類型)和edge(邊類型), 需要先 USE 一個圖空間 SHOW TAGS; SHOW EDGES;
列出某一類型的點和邊
MATCH ()-[e:follow]-() RETURN e MATCH (v:player) RETURN v
帶條件的查詢, 在結(jié)果數(shù)量較多時必須帶limit, 否則Nebula會報錯
match (v:ADDRESS)-[e]-() where id(v)==\"ADD:82388116\" return v,e limit 100
在上面的鏈接中, 提供了最小的配置和測試代碼
對于Nebula Graph 3.2.1, 需要使用3.0.0的版本. client的每個版本只能對應(yīng)特定的一兩個服務(wù)端版本
<dependency> <groupId>com.vesoft</groupId> <artifactId>client</artifactId> <version>3.0.0</version> </dependency>
Java調(diào)用主要是三部分, 創(chuàng)建連接池, 創(chuàng)建會話, 執(zhí)行查詢
連接到地址127.0.0.1, 端口9669, 連接池大小100. 注意地址和端口是一個列表, Nebula是支持集群的. 連接時不需要用戶和密碼
NebulaPool pool = new NebulaPool(); try { NebulaPoolConfig nebulaPoolConfig = new NebulaPoolConfig(); nebulaPoolConfig.setMaxConnSize(100); List<HostAddress> addresses = Arrays.asList(new HostAddress("127.0.0.1", 9669)); Boolean initResult = pool.init(addresses, nebulaPoolConfig); if (!initResult) { log.error("pool init failed."); return; } } catch () //...
創(chuàng)建會話時需要用戶名和密碼
Session session = pool.getSession("root", "nebula", false);
創(chuàng)建一個SPACE, 然后使用這個SPACE, 創(chuàng)建一個TAG person, 創(chuàng)建一個EDGE like
String createSchema = "CREATE SPACE IF NOT EXISTS test(vid_type=fixed_string(20)); " + "USE test;" + "CREATE TAG IF NOT EXISTS person(name string, age int);" + "CREATE EDGE IF NOT EXISTS like(likeness double)"; ResultSet resp = session.execute(createSchema); if (!resp.isSucceeded()) { log.error(String.format("Execute: `%s', failed: %s", createSchema, resp.getErrorMessage())); System.exit(1); }
添加一個點記錄
String insertVertexes = "INSERT VERTEX person(name, age) VALUES " + "'Bob':('Bob', 10), " + "'Lily':('Lily', 9), " + "'Tom':('Tom', 10), " + "'Jerry':('Jerry', 13), " + "'John':('John', 11);"; ResultSet resp = session.execute(insertVertexes); if (!resp.isSucceeded()) { log.error(String.format("Execute: `%s', failed: %s", insertVertexes, resp.getErrorMessage())); System.exit(1); }
查詢
String query = "GO FROM \"Bob\" OVER like " + "YIELD $^.person.name, $^.person.age, like.likeness"; ResultSet resp = session.execute(query); if (!resp.isSucceeded()) { log.error(String.format("Execute: `%s', failed: %s", query, resp.getErrorMessage())); System.exit(1); } printResult(resp);
<dependency> <groupId>com.vesoft</groupId> <artifactId>client</artifactId> <version>3.0.0</version> </dependency>
配合@Bean(destroyMethod = "close")
, 創(chuàng)建一個工廠類, 接收pool并實現(xiàn)close()方法
public class NebulaSessionFactory { private final NebulaPool pool; private final String username; private final String password; public NebulaSessionFactory(NebulaPool pool, String username, String password) { this.pool = pool; this.username = username; this.password = password; } public Session getSession() { try { return pool.getSession(username, password, false); } catch (NotValidConnectionException|IOErrorException|AuthFailedException|ClientServerIncompatibleException e) { throw new RuntimeException("Nebula session exception", e); } } public void close() { pool.close(); } }
為什么不直接將 NebulaPool 配置為Bean? 因為 Session 每次創(chuàng)建時需要帶用戶名密碼, 將密碼作為config注入到每個Service中肯定是大家都不愿意看到的.
這里的值如果不打算使用profile配置, 可以直接寫入
hosts是逗號分隔的地址端口列表, 例如 10.22.33.33:9669,10.22.33.34:9669
myapp: nebula: hosts: @nebula.hosts@ username: @nebula.username@ password: @nebula.password@ max-conn: @nebula.max-conn@
應(yīng)用啟動時讀取配置, 創(chuàng)建 NebulaPool, 并實例化 NebulaSessionFactory, destroyMethod = "close"
, 這個表示在項目shutdown時會調(diào)用Bean的close方法釋放資源.
@Configuration public class NebulaGraphConfig { @Value("${myapp.nebula.hosts}") private String hosts; @Value("${myapp.nebula.max-conn}") private int maxConn; @Value("${myapp.nebula.username}") private String username; @Value("${myapp.nebula.password}") private String password; @Bean(destroyMethod = "close") public NebulaSessionFactory nebulaSessionFactory() { List<HostAddress> hostAddresses = new ArrayList<>(); String[] hostList = hosts.split(",[ ]*"); for (String host : hostList) { String[] hostParts = host.split(":"); if (hostParts.length != 2 || !hostParts[1].matches("\\d+")) { throw new RuntimeException("Invalid host name set for Nebula: " + host); } hostAddresses.add(new HostAddress(hostParts[0], Integer.parseInt(hostParts[1]))); } NebulaPoolConfig poolConfig = new NebulaPoolConfig(); poolConfig.setMaxConnSize(maxConn); NebulaPool pool = new NebulaPool(); try { pool.init(hostAddresses, poolConfig); } catch (UnknownHostException e) { throw new RuntimeException("Unknown Nebula hosts"); } return new NebulaSessionFactory(pool, username, password); } }
在 Service 中進行調(diào)用
@Service @Slf4j public class GraphServiceImpl implements GraphService { @Autowired private NebulaSessionFactory sessionFactory; @Override public <T> NebulaResult<T> query(String graphSpace, String gql) { Session session = null; try { log.info("GQL: {}", gql); session = sessionFactory.getSession(); NebulaResult<Void> res = query(session, "USE " + graphSpace); if (!res.isSuccess() || res.getResults() == null || res.getResults().size() == 0) { log.error("Failed to use space:{}", graphSpace); return null; } if (!graphSpace.equals(res.getResults().get(0).getSpaceName())) { log.error("Failed to use space:{}, result:{}", graphSpace, res.getResults().get(0).getSpaceName()); return null; } return query(session, gql); } catch (IOErrorException e) { log.error(e.getMessage(), e); return null; } finally { if (session != null) { session.release(); } } } private <T> NebulaResult<T> query(Session session, String gql) throws IOErrorException { String json = session.executeJson(gql); return JacksonUtil.extractByType(json, new TypeReference<>() {}); } }
這里定義了 json 格式響應(yīng)的外層結(jié)構(gòu)
@Data public class NebulaResult<T> implements Serializable { private List<Error> errors; private List<Result<T>> results; @JsonIgnore public boolean isSuccess() { return (errors != null && errors.size() == 1 && errors.get(0).getCode() == 0); } @Data public static class Error implements Serializable { private int code; } @Data @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public static class Result<T> implements Serializable { private String spaceName; private List<Element<T>> data; private List<String> columns; private Error errors; private long latencyInUs; } @Data public static class Element<T> implements Serializable { private List<Meta<T>> meta; private List<Serializable> row; } @Data public static class Meta<T> implements Serializable { private String type; private T id; } }
內(nèi)層因為區(qū)分Edge和Vertex, 結(jié)構(gòu)不一樣. 如果是混合返回的結(jié)果, 可以用 Serializable
String gql = "match (v:ADDR)-[e]-() where id(v)==\"ADD:123123\" return v,e limit 100"; NebulaResult<Serializable> res = graphService.query("insurance", gql); log.info(JacksonUtil.compress(res)); Assertions.assertThat(res).isNotNull();
對于邊, 需要使用結(jié)構(gòu)化的ID
@Data @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class EdgeId implements Serializable { private int ranking; private int type; private String dst; private String src; private String name; }
用這個結(jié)構(gòu)進行查詢
NebulaResult<EdgeId> res3 = graphService.query("t_test1", "MATCH ()-[e:follow]-() RETURN e");
對于點, ID就是String
NebulaResult<String> res2 = graphService.query("t_test1", "MATCH (v:player) RETURN v");
感謝各位的閱讀,以上就是“Nebula Graph和SpringBoot環(huán)境連接及查詢?nèi)绾螌崿F(xiàn)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Nebula Graph和SpringBoot環(huán)境連接及查詢?nèi)绾螌崿F(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
網(wǎng)站題目:Nebula?Graph和SpringBoot環(huán)境連接及查詢?nèi)绾螌崿F(xiàn)
URL網(wǎng)址:http://www.2m8n56k.cn/article24/ggdgje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、建站公司、定制網(wǎng)站、軟件開發(fā)、小程序開發(fā)、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:[email protected]。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)