图数据库Neo4j学习五渲染图数据库neo4jd3

文章目录

  • 1.现成的工具
  • 2.Neo4j JavaScript Driver
  • 3.neovis
  • 4.neo4jd3
    • 4.1neo4jd3和neovis对比
    • 4.2获取neo4jd3
    • 4.3neo4jd3的数据结构
    • 4.4Spring data neo
      • 4.4.1 定义返回数据格式
        • 4.4.1.1NeoResults
        • 4.4.1.2GraphVO
        • 4.4.1.3NodeVO
        • 4.4.1.4ShipVO
      • 4.4.2 SDN查询解析
        • 4.4.2.1 Repo查询语句
        • 4.4.2.2 解析Repo查询
        • 4.4.2.3返回解析结果
      • 4.4.3前端处理渲染
    • 4.5实现效果

本文最终技术架构:neo4jd3 + Spring boot + Spring Data Neo + neo4j

当我们刚开是接触图数据库的时候,我们进行各种关系查询,最终会得到一个拓扑图。和我们以前使用的数据库不一样的是,我们的数据库查询出来是一系列的表。
在这里插入图片描述
事实上,我们的图数据返回的的数据是类似于下面这样的格式的,然后通过前端(Neo4j Browser )来帮我们将返回的数据绘制成网络拓扑图。在我们之前的文章中介绍的Spring Data Neo中,返回的也都是java对象的数据
在这里插入图片描述
接下来本文就是介绍使用一些前端技术来帮我们将图数据库的数据返回给前端进行旋绕

1.现成的工具

比如Neo4j Browser 、Neo4j Bloom、这些官方提供的工具,免费或者有商业版权,这些工具特点都是人家已经开发好的工具,你安装上使用就行了。
例如Neo4j Browser,这些工具就好比,我们Navicat 、Sql Log、PL SQL这些客户端连接工具连接关系型数据库(mysql、oracle、post gre)等。本文就不在详细介绍。
在这里插入图片描述

2.Neo4j JavaScript Driver

Neo4j JavaScript Driver 是一个用于在 JavaScript 应用程序中与 Neo4j 图数据库进行通信的官方驱动程序。它提供了与 Neo4j 服务器进行连接、执行 Cypher 查询和处理查询结果等功能。我们可以在Jquery、React、Angular、Vue等前端框架中使用该驱动。
驱动安装

npm install neo4j-driver

代码示例

const neo4j = require('neo4j-driver')
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password))
const session = driver.session()
const personName = 'Alice'try {const result = await session.run('CREATE (a:Person {name: $name}) RETURN a',{ name: personName })const singleRecord = result.records[0]const node = singleRecord.get(0)console.log(node.properties.name)
} finally {await session.close()
}// on application exit:
await driver.close()

官方地址:neo4j-javascript

适用于:前端直接和Neo4J直接连接

3.neovis

Neovis.js 是一个纯 JavaScript 库,使用 JavaScript 语言编写和开发开源框架。它可以在浏览器环境中直接使用,也可以与其他 JavaScript 框架和库集成,如 React、Angular 或 Vue.js

  1. Neovis.js 使用 Neo4j JavaScript Driver 与 Neo4j 图数据库进行通信。
  2. Neovis.js 在 Vis.js 的基础上构建了对 Neo4j 数据库的特定集成和功能

github地址:github-neovis.js
下面这是一个官方的示例:
在这里插入图片描述
Neovis.js可以通过npm安装

npm install --save neovis.js

Neovis.js可以从Neo4jLabs CDN获得

<script src="https://unpkg.com/neovis.js@2.0.2"></script>
<script src="https://unpkg.com/neovis.js@2.0.2/dist/neovis-without-dependencies.js"></script>

代码示例
需要在代码中定义每个节点,边,例如下乳,查询用户和角色

<script type="text/javascript">let neoViz;function draw() {const config = {containerId: "viz",neo4j: {serverUrl: "bolt://localhost:7687",//neo4j的用户名和密码serverUser: "neo4j",serverPassword: "neo4j",},labels: {//节点的标签1(节点类型:用户)User: {//在User类型的节点上,使用userName作为节点的显示label: "userName"},//节点的标签2(节点类型:角色)Role: {//在Role类型的节点上,使用roleName作为节点的显示label: "roleName",}//节点的标签3.......},relationships: {//关系1(边)PLAY_THE_ROLE: {value: "name"}},//Cypher语句initialCypher: "MATCH (n)-[r:PLAY_THE_ROLE]->(m) RETURN *"};neoViz = new NeoVis.default(config);neoViz.render();}
</script>

4.neo4jd3

neo4jd3使用D3.js实现Neo4j图形可视化。
github地址:githug-neo4jd3,表现效果如下:
在这里插入图片描述

4.1neo4jd3和neovis对比

neo4jd3和neovis是两个完全不同的组件,使用方式也不一样。

  1. 在底层依赖上:
    neovis.js 是基于 Vis.js、neo4j JavaScript Driver 构建的,而 neo4jd3.js 基于 D3.js。

  2. 在功能上:
    neovis.js 能够直接和neo4j 数据库相连,将数据库查询结果直接进行渲染,而neo4jd3则不和数据库相连,而是通过数据进行渲染。所以对于neo4jd3来说,只要能提供数据,就能渲染,因此我们可以使用任何技术为neo4jd3来进行获取数据,最后将数据给neo4jd3。

  3. 在渲染上:
    neovis.js侧重于将数据库的查询语句发送给数据,然后渲染数据库返回的结果值,因此在渲染效果上存在很多的不友好一面。而neo4jd3并不关心查询语句如何编写,数据库如何查询,只对最后的数据进行渲染,因此在渲染效果上就体现的非常友好

以下是对同一个数据的查询结果进行的渲染对比,左图是neovis,右图neo4jd3,单从拓扑图上来说,左边的效果就很差
在这里插入图片描述

4.2获取neo4jd3

从仓库中下载代码,在dist目录下,有css和js
在这里插入图片描述

git clone https://github.com/eisman/neo4jd3.git

在这里插入图片描述

4.3neo4jd3的数据结构

我们先看官网给的两组Json,也就是需要我们的数据组织者按照如下格式进行数据格式组织
返回节点和关系的json

{"nodes": [{"id": "1","labels": ["User"],"properties": {"userId": "eisman"}},{"id": "8","labels": ["Project"],"properties": {"name": "neo4jd3","title": "neo4jd3.js","description": "Neo4j graph visualization using D3.js.","url": "https://eisman.github.io/neo4jd3"}}],"relationships": [{"id": "7","type": "DEVELOPES","startNode": "1","endNode": "8","properties": {"from": 1470002400000},"source": "1","target": "8","linknum": 1}]
}

返回绘制图的Json

{"results": [{"columns": ["user", "entity"],"data": [{"graph": {"nodes": [{"id": "1","labels": ["User"],"properties": {"userId": "eisman"}},{"id": "8","labels": ["Project"],"properties": {"name": "neo4jd3","title": "neo4jd3.js","description": "Neo4j graph visualization using D3.js.","url": "https://eisman.github.io/neo4jd3"}}],"relationships": [{"id": "7","type": "DEVELOPES","startNode": "1","endNode": "8","properties": {"from": 1470002400000}}]}}]}],"errors": []
}

4.4Spring data neo

我们现在已经知道了neo4jd3绘制图的Json格式了,现在就需要我们后台查询数据,然后返回

4.4.1 定义返回数据格式

在这里插入图片描述
我们当然也能通过数据格式发现,嵌套有点深,这里推荐按照这个格式来,因为不这样的话,你就得要求修改前端组建的源代码了。下面这个是前端渲染数据的一部分代码,如果后端返回的数据不按照这个格式来的话,前端这里就需要你修改代码了。
在这里插入图片描述
这里我避免创建很多单一属性的类,因此采用了内部类的方式,这里你不一定才用内部类,只要能返回和上面的Json格式就行

4.4.1.1NeoResults

@lombok.Data
public class NeoResults {private List<Data> results = new ArrayList<>();public NeoResults() {super();results.add(new NeoResults.Data());}@lombok.Datapublic class Data{private List<Graph> data = new ArrayList<>();public Data() {super();data.add(new Data.Graph());}@lombok.Datapublic class Graph{private GraphVO graph = new GraphVO();}}public void setNodes(List<NodeVO> nodes) {results.get(0).getData().get(0).getGraph().setNodes(nodes);} public void setRelationships(List<ShipVO> relationships) {results.get(0).getData().get(0).getGraph().setRelationships(relationships);} 
}

4.4.1.2GraphVO

@Data
public class GraphVO {private List<NodeVO> nodes = new ArrayList<>();private List<ShipVO> relationships = new ArrayList<>();
}

4.4.1.3NodeVO

@Data
@AllArgsConstructor
@NoArgsConstructor
public class NodeVO{private Long id;private List<String> labels;private Map<String, Object> properties;
}

4.4.1.4ShipVO

@Data
public class ShipVO {private Long id;private String type;private Long startNode;private Long endNode;private Map<String, Object> properties;
}

4.4.2 SDN查询解析

4.4.2.1 Repo查询语句

public interface D3jsRepo extends Neo4jRepository<Object, Long> {/*** @description:查询路径:根据roadName查询Road标签查询路径* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月21日 下午2:11:09*/@Query("MATCH (n:Road{name:$roadName}) MATCH path=(n)-[*]->(n1) RETURN path")List<Map<String, InternalPath.SelfContainedSegment[]>> findPathsByRoadName(@Param("roadName") String roadName);/*** @description:查询路径:根据标签label和某个属性字段查询路径,性能比较慢,谨慎使用* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月21日 下午3:22:02*/@Query("MATCH (n) WHERE $label IN labels(n) AND n[$property] = $value MATCH path=(n)-[*]->(n1) RETURN path")List<Map<String, InternalPath.SelfContainedSegment[]>> findByLabelAndProperty(@Param("label") String label, @Param("property") String property, @Param("value") String value);/*** @description:查询路径:根据标主键ID查询路径* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月21日 下午3:42:52*/@Query("MATCH (n) WHERE id(n) = $id MATCH path=(n)-[*]->(n1) RETURN path")List<Map<String, InternalPath.SelfContainedSegment[]>> findPathById(@Param("id") Long id);
}

4.4.2.2 解析Repo查询

@Service
public class D3jsServiceImpl implements D3jsService{@Autowiredprivate D3jsRepo d3jsRepo;/*** @description:通过节点ID找路径,以该节点为起点* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月22日 上午11:17:13*/@Overridepublic NeoResults findPathsById(Long id) {NeoResults neoResult = new NeoResults();List<NodeVO> nodes = new ArrayList<>();List<ShipVO> relationships = new ArrayList<>();List<Map<String, InternalPath.SelfContainedSegment[]>> paths = d3jsRepo.findPathById(id);for (Map<String, InternalPath.SelfContainedSegment[]> path : paths) {SelfContainedSegment[] segments = path.get("path");for (SelfContainedSegment segment : segments) {addNode(nodes, segment.start());addNode(nodes, segment.end());addShip(relationships, segment.relationship());}}neoResult.setNodes(nodes);neoResult.setRelationships(relationships);return neoResult;}/*** @description:添加关系* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月16日 下午1:23:54*/private void addShip(List<ShipVO> relationships, Relationship shipTemp) {ShipVO shipVO =new ShipVO();shipVO.setId(shipTemp.id());shipVO.setStartNode(shipTemp.startNodeId());shipVO.setEndNode(shipTemp.endNodeId());shipVO.setType(shipTemp.type());shipVO.setProperties(shipTemp.asMap());relationships.add(shipVO);}/*** @description:添加节点* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月16日 下午2:27:37*/private void addNode(List<NodeVO> nodes, Node nodeTemp) {NodeVO noveVO = new NodeVO();List<String> labels = new ArrayList<>();nodeTemp.labels().forEach(labels::add);noveVO.setId(nodeTemp.id());noveVO.setLabels(labels);noveVO.setProperties(nodeTemp.asMap());nodes.add(noveVO);}
}

4.4.2.3返回解析结果

 	@GetMapping("/node/info/path/{id}")@ApiOperationSupport(order = 3)@ApiOperation(value = "3获取指定节点为起点的路径")public NeoResults queryNodeTopo(@PathVariable Long id) {NeoResults findPaths = d3jsService.findPathsById(id);return findPaths;}

4.4.3前端处理渲染

<link rel="stylesheet" href="/plugin/neod3/css/neo4jd3.min.css">
<script src="/plugin/neod3/js/d3.min.js"></script>
<script src="/plugin/neod3/js/neo4jd3.js"></script>光路起点<select id = "selectRoad" class="selectpicker" onchange = "changeRoad()" data-live-search="true" data-style="btn-info"  title="请选择起点光路" ></select><div id="neo4jd3"></div>
/*** @description:选择光路触发加载光路的路径* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月17日 下午2:10:18*/
function changeRoad(){let select =  $('#selectRoad').val(); let url = '/node/info/path/'+select;let resultData = httpRequestForJson(url,"","GET");loadNeod3Topo(resultData);
}/*** @description:初始化节点拓扑矢量图* @author:hutao* @mail:hutao1@epri.sgcc.com.cn* @date:2023年8月17日 下午2:18:48*/
var neo4jd3
function loadNeod3Topo(resultData){neo4jd3 = new Neo4jd3('#neo4jd3', {//showLabel源代码中不存在,是我自己添加的,实现效果为:节点是否显示节点标签showLabel: true,minCollision: 100,//neo4jDataUrl: '/aaa/bbbb',neo4jData: resultData,nodeRadius: 25,onNodeDoubleClick: function(node) {console.log('double click on node: ' + JSON.stringify(node));},onRelationshipDoubleClick: function(relationship) {console.log('double click on relationship: ' + JSON.stringify(relationship));},//自动缩放zoomFit: true,});
}

4.5实现效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/57877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Rust日报】2023-08-25 SDXL in Rust,AIGC狂喜!

Stable-Diffusion-XL-Burn&#xff1a;SDXL in Rust 在reddit上看到这个项目 Stable-Diffusion-XL-Burn ,它 是一个基于 Rust 的项目&#xff0c;将stable diffusion xl 移植到了 Rust 深度学习框架 burn 中。在reddit回帖上&#xff0c;已经有小伙伴在热情的尝试&#xff0c;还…

Go测试之.golden 文件

Go测试中的.golden 文件是干什么用的&#xff1f;请举例说明 在Go语言中&#xff0c;.golden文件通常用于测试中的黄金文件&#xff08;golden files&#xff09;。黄金文件是在测试期间记录预期输出结果的文件。测试用例运行时&#xff0c;黄金文件用于比较实际输出与预期输出…

【IMX6ULL驱动开发学习】11.Linux之SPI驱动

参考&#xff1a;驱动程序开发&#xff1a;SPI设备驱动_spi驱动_邓家文007的博客-CSDN博客 目录 一、SPI驱动简介 1.1 SPI架构概述 1.2 SPI适配器&#xff08;控制器&#xff09;数据结构 1.2 SPI设备数据结构 1.3 SIP设备驱动 1.4 接口函数 二、SPI驱动模板 一、SPI驱动…

718. 最长重复子数组

718. 最长重复子数组 原题链接&#xff1a;完成情况&#xff1a;题解&#xff1a;方法一&#xff1a;动态规划方法二&#xff1a;滑动窗口方法三&#xff1a;二分查找 哈希 原题链接&#xff1a; 718. 最长重复子数组 https://leetcode.cn/problems/maximum-length-of-repe…

Android App的设计规范

Android App 设计规范是为开发者和设计师提供的一系列准则和建议&#xff0c;以确保应用在 Android 设备上的外观、交互和用户体验保持一致。以下是一些常见的 Android App 设计规范要点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开…

Apifox下载安装步骤

我们先访问网址 https://apifox.com/?utm_sourcebaidu&utm_mediumsem&utm_campaign251430236&utm_content7810722111&utm_termapifox%E6%9F%A5%E7%9C%8B%E7%89%88%E6%9C%AC&bd_vid8323327349775096324 然后 这里这个免费下载已经写的这么明显了 那就直接点…

Jmeter(三十):并发测试(设置集合点)

集合点:让所有请求在不满足条件的时候处于等待状态。 如:我集合点设置为50,那么不满足50个请求的时候,这些请求都会集合在一起,处于等待状态,当达到50的时候,就一起执行。从而达到并发的效果。 那么Jmeter中可以通过同步定时器 Synchronizing Timer 来完成。 Number …

计算机竞赛 基于机器视觉的手势检测和识别算法

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的手势检测与识别算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng…

医学影像PACS系统源码,患者登记、图像采集和处理、图像存储、报告产生的影像系统

PACS系统是医院影像科室中应用的一种系统&#xff0c;主要用于获取、传输、存档和处理医学影像。它通过各种接口&#xff0c;如模拟、DICOM和网络&#xff0c;以数字化的方式将各种医学影像&#xff0c;如核磁共振、CT扫描、超声波等保存起来&#xff0c;并在需要时能够快速调取…

高忆管理:新手炒股入门零基础学?

炒股是一些人为了取得高额回报和更好的财政自由而进行的活动。但对许多新手而言&#xff0c;这是一个全新的领域&#xff0c;需求掌握许多根底常识才能够开始加入炒股商场。本文将为零根底的新手炒股入门供给一些主张和技巧&#xff1a; 一、学习根底常识 关于炒股入门的新手而…

在ros中利用串口serial发布fdilink的gps话题

文章目录 介绍FDILink通讯协议数据帧组成数据包 数据处理打开串口在头文件中定义参数串口读取 代码运用依赖&#xff1a;使用&#xff1a; 源码 介绍 DETA100系列 是一个提供 GNSS/INS & AHRS 系统的模组&#xff0c;在最苛刻的条件下提供准确的位置、速度、加速度和姿态数…

pytest笔记: pytest单元测试框架

第一步&#xff1a;安装 和查看版本 pycharm settings 查看 第二步&#xff1a; 编写test_example.py def inc(x):return x1 def test_answer():assert inc(4) 5 第三步&#xff1a;在当前路径下执行pytest 命令 PS E:\data\web测试\Selenium3自动化测试实战——基于Pyth…

Flink流批一体计算(18):PyFlink DataStream API之计算和Sink

目录 1. 在上节数据流上执行转换操作&#xff0c;或者使用 sink 将数据写入外部系统。 2. File Sink File Sink Format Types Row-encoded Formats Bulk-encoded Formats 桶分配 滚动策略 3. 如何输出结果 Print 集合数据到客户端&#xff0c;execute_and_collect…

力扣:74. 搜索二维矩阵(Python3)

题目&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非递减顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返…

MySQL概述,架构原理

一.MySQL简介 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典的MySQL AB公司开发&#xff0c;后被oracle公司收购&#xff0c;MySQL是当下最流行的关系型数据库管理系统之一&#xff0c;在WEB应用方面&#xff0c;MySQL是最好的RDBMS&#xff08;Relational Database Man…

Mybatis小记

目录 Mybatis第一个程序 xml文件 测试类 错误排查 Mybatis第一个程序 1.搭建实验数据库 2.导入MyBatis相关jar包 3.编写MyBatis核心配置文件 4.编写MyBatis工具类 5.创建实体类、 6.编写Mapper接口类 7.编写Mapper.xml配置文件 8.编写测试类 对象传参只引用需要的属性就可…

基于AVR128单片机抢答器proteus仿真设计

一、系统方案 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 void timer0_init() //定时器初始化 { TCCR00x07; //普通模式&#xff0c;OC0不输出&#xff0c;1024分频 TCNT0f_count; //初值&#xff0c;定时为10ms TIFR0x01; //清中断标志…

ChatGPT Prompting开发实战(二)

一、基于LangChain源码react来解析prompt engineering 在LangChain源码中一个特别重要的部分就是react&#xff0c;它的基本概念是&#xff0c;LLM在推理时会产生很多中间步骤而不是直接产生结果&#xff0c;这些中间步骤可以被用来与外界进行交互&#xff0c;然后产生new con…

IdentityServer密码长度超长会导致跳转到登录页

应用系统项目的安全要求越来越高&#xff0c;基本都是采取https等加密证书传输&#xff0c;无法使用https的&#xff0c;也是要求不能明文传输内容&#xff0c;因此做一些等保要求&#xff0c;密码需要加密后才能传输给服务端&#xff0c;所以前端会采取一些密码手段&#xff0…

【Android Framework系列】第12章 RecycleView相关原理及四级缓存策略分析

1 RecyclerView简介 RecyclerView是一款非常强大的widget&#xff0c;它可以帮助您灵活地显示列表数据。当我开始学习 RecyclerView的时候&#xff0c;我发现对于复杂的列表界面有很多资源可以参考&#xff0c;但是对于简单的列表展现就鲜有可参考的资源了。虽然RecyclerView的…