0

0

Nebula Graph和SpringBoot环境连接和查询怎么实现

PHPz

PHPz

发布时间:2023-05-15 22:01:04

|

1521人浏览过

|

来源于亿速云

转载

说明

nebula graph 是一款开源的、分布式的、易扩展的原生图数据库,能够承载包含数千亿个点和数万亿条边的超大规模数据集,并且提供毫秒级查询。

当前Nebula Graph的最新版本是3.2.1, 根据官方的文档进行配置

  • 支持分布式. 相对于Neo4j, TigerGraph这些图数据库, Nebula 是面向分布式设计的, 因此对集群的支持比较完备, 在规模上上限要高很多. 在实际项目中存储了180亿的点边, 这个数量对于Neo4j和TigerGraph是比较困难的.

  • 支持图空间. 各个图空间的ID是互不干扰的, 但是在同一个图空间里ID的类型和长度必须一致. 注意这个一致约束的是所有的点和边. Nebula 可以使用int64作为ID, 也可以用字符串, 但是字符串需要指定一个长度, 例如64个字节. 相对于只能用长整数的Neo4j, ID设计上更自由灵活.

  • 点对应的类型叫TAG, 边对应的类型叫EDGE

    TAG和EDGE都会对应一组的属性(map, 或者说dict)

    一个点可以对多个TAG, 每个TAG一组属性, 多组属性. 项目中建议一开始不要用多TAG, 在整个图结构稳定后, 再做合并

    一个边只对应一个EDGE, 一组属性

  • Nebula 用的是自定义的查询语法 GQL, 和 cypher 语法基本一样

  • 除了点边的ID和关联关系外, 只有带索引的属性可以查询. 这点和其它图数据库不一样, 其它数据库即使没有索引, 慢是慢点但是不报错, Nebula直接给你返回错误.

  • 对于返回数量较大的查询, Nebula会强制查询必须带limit

  • Nebula 单节点稳定性是有问题的, 在3.2.1版本中观察到偶尔会出现服务自行退出, 如果在生产环境使用, 需要有后台监控进行心跳检测和自动启动

GQL 常用查询

下面列出一些常用的查询

-- 列出图空间
SHOW SPACES;
-- 列出tag(点类型)和edge(边类型), 需要先 USE 一个图空间
SHOW TAGS;
SHOW EDGES;

列出某一类型的点和边

MATCH ()-[e:follow]-() RETURN e
MATCH (v:player) RETURN v

带条件的查询, 在结果数量较多时必须带limit, 否则Nebula会报错

match (v:ADDRESS)-[e]-() where id(v)=="ADD:82388116" return v,e limit 100

基础配置和使用

在上面的链接中, 提供了最小的配置和测试代码

pom.xml 增加包依赖

对于Nebula Graph 3.2.1, 需要使用3.0.0的版本. client的每个版本只能对应特定的一两个服务端版本

<dependency>
	<groupId>com.vesoft</groupId>
	<artifactId>client</artifactId>
	<version>3.0.0</version>
</dependency>

Java调用

Java调用主要是三部分, 创建连接池, 创建会话, 执行查询

创建 NebulaPool 连接池

连接到地址127.0.0.1, 端口9669, 连接池大小100. 注意地址和端口是一个列表, Nebula是支持集群的. 连接时不需要用户和密码

百宝箱
百宝箱

百宝箱是支付宝推出的一站式AI原生应用开发平台,无需任何代码基础,只需三步即可完成AI应用的创建与发布。

下载
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 ()
//...

创建 Session 会话

创建会话时需要用户名和密码

Session session = pool.getSession("root", "nebula", false);

执行查询

创建一个SPACE, 然后使用这个SPACE, 创建一个TAG person, 创建一个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);

在 SpringBoot 项目中使用 Nebula Graph

pom.xml 增加包依赖

<dependency>
	<groupId>com.vesoft</groupId>
	<artifactId>client</artifactId>
	<version>3.0.0</version>
</dependency>

Session工厂: NebulaSessionFactory.java

配合@Bean(destroyMethod = "close"), 创建一个工厂类, 接收pool并实现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 每次创建时需要带用户名密码, 将密码作为config注入到每个Service中肯定是大家都不愿意看到的.

配置修改: application.yml

  • 这里的值如果不打算使用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@

Spring启动配置: NebulaGraphConfig.java

应用启动时读取配置, 创建 NebulaPool, 并实例化 NebulaSessionFactory, destroyMethod = "close", 这个表示在项目shutdown时会调用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调用

在 Service 中进行调用

@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<>() {});
    }
}

辅助类 NebulaResult.java 等

外层结构

这里定义了 json 格式响应的外层结构

@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;
    }
}

内层因为区分Edge和Vertex, 结构不一样. 如果是混合返回的结果, 可以用 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();

对于边, 需要使用结构化的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;
}

用这个结构进行查询

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");

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

38

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

83

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

97

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

223

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

458

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

169

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

246

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

34

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Redis6入门到精通超详细教程
Redis6入门到精通超详细教程

共47课时 | 5.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号