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

news2025/1/24 1:01:14

文章目录

  • 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.Data
	public class Data{
		private List<Graph> data = new ArrayList<>();
		
		public Data() {
			super();
			data.add(new Data.Graph());
		}
		
		@lombok.Data
		public 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{

	@Autowired
	private D3jsRepo d3jsRepo;
	
	/**
	 * @description:通过节点ID找路径,以该节点为起点
	 * @author:hutao
	 * @mail:hutao1@epri.sgcc.com.cn
	 * @date:2023年8月22日 上午11:17:13
	 */
	@Override
	public 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.coloradmin.cn/o/924605.html

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

相关文章

Python可视化工具库实战

Matplotlib Matplotlib 是 Python 的可视化基础库&#xff0c;作图风格和 MATLAB 类似&#xff0c;所以称为 Matplotlib。一般学习 Python 数据可视化&#xff0c;都会从 Matplotlib 入手&#xff0c;然后再学习其他的 Python 可视化库。 Seaborn Seaborn 是一个基于 Matplo…

七大出海赛道解读,亚马逊云科技为行业客户量身打造解决方案

伴随全球化带来的新机遇和国内市场的进一步趋于饱和&#xff0c;近几年&#xff0c;中国企业出海快速升温&#xff0c;成为了新的创业风口和企业的第二增长曲线。从范围上看&#xff0c;出海市场由近及远&#xff0c;逐步扩张。从传统的东南亚市场&#xff0c;到成熟的北美、欧…

基于python+pyqt的opencv汽车分割系统

目录 一、实现和完整UI视频效果展示 主界面&#xff1a; 识别结果界面&#xff1a; 查看分割处理过程图片界面&#xff1a; 二、原理介绍&#xff1a; 加权灰度化 ​编辑 二值化 滤波降噪处理 锐化处理 边缘特征提取 图像分割 完整演示视频&#xff1a; 完整代码链…

大数据课程K6——Spark的Shuffle详解

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的定义&&特点&&目的&&优缺点; ⚪ 掌握Spark的相关参数配置; ⚪ 掌握Hadoop的插件配置; 一、Spark Shuffle详解 1. 概述 Shuffle,就是洗牌。之所以…

QtC++ 设计模式(四)——策略模式

策略模式 序言理解源码 序言 还是参考的菜鸟教程&#xff0c;会C的还是看C的方式来得舒服。 . 理解 使用符合UML规范的便于理解和回忆&#xff0c;接口其实就是普通的基类 . 源码 strategy.h /// 策略 class Strategy { public:virtual ~Strategy();/*** brief 计算* p…

AIGC ChatGPT 完成多仪表盘完成率分析

各组完成率的统计与分析的这样一个综合案例 可以使用HTML &#xff0c;JS&#xff0c;Echarts 来完成制作 我们可以借助于AIGC&#xff0c;ChatGPT 人工智能来帮我们完成代码的输出。 在ChatGPT中我们只需要发送指令就可以了。 例如&#xff1a;请使用HTMl与JS&#xff0c;…

蝴蝶翻转

蝴蝶翻转 实现一 在计算机科学和数字信号处理中&#xff0c;蝴蝶操作是一种常用于快速傅里叶变换&#xff08;FFT&#xff09;的操作。在蝴蝶算法中&#xff0c;输入数据的一部分通过特定的运算结构进行重新排列和组合&#xff0c;以便在计算FFT时实现高效处理。 蝴蝶操作的…

【seaweedfs】3、f4: Facebook’s Warm BLOB Storage System 分布式对象存储的冷热数据

论文地址 Facebook的照片、视频和其他需要可靠存储和快速访问的二进制大型对象(BLOB)的语料库非常庞大&#xff0c;而且还在继续增长。随着BLOB占用空间的增加&#xff0c;将它们存储在我们传统的存储系统-- Haystack 中变得越来越低效。为了提高我们的存储效率(以Blob的有效复…

线程池的概念及实现原理

本篇是对前面线程池具体实现过程的补充&#xff0c;实现过程可参考 线程池的实现全过程v1.0版本&#xff08;手把手创建&#xff0c;看完必掌握&#xff01;&#xff01;&#xff01;&#xff09;_竹烟淮雨的博客-CSDN博客 线程池的实现v2.0&#xff08;可伸缩线程池&#xf…

04-Numpy基础-利用数组进行数据处理

NumPy数组使你可以将许多种数据处理任务表述为简洁的数组表达式&#xff08;否则需要编 写循环&#xff09;。用数组表达式代替循环的做法&#xff0c;通常被称为矢量化。一般来说&#xff0c;矢量化 数组运算要比等价的纯Python方式快上一两个数量级&#xff08;甚至更多&…

Python代理池健壮性测试 - 压力测试和异常处理

大家好&#xff01;在构建一个可靠的Python代理池时&#xff0c;除了实现基本功能外&#xff0c;我们还需要进行一系列健壮性测试来确保其能够稳定运行&#xff0c;并具备应对各种异常情况的能力。本文将介绍如何使用压力测试工具以及合适的异常处理机制来提升Python代理池的可…

vue+file-saver+xlsx+htmlToPdf+jspdf实现本地导出PDF和Excel

页面效果如下&#xff08;echarts图表按需添加&#xff0c;以下代码中没有&#xff09; 1、安装插件 npm install xlsx --save npm install file-saver --save npm install html2canvas --save npm install jspdf --save2、main.js引入html2canvas import htmlToPdf from …

Tomcat的安装与介绍

首先我们先了解一下什么是服务器&#xff1f;什么是服务器软件&#xff1f; 什么是服务器&#xff1f;安装了服务器软件的计算机。 什么是服务器软件&#xff1f; 服务器软件是一种运行在服务器操作系统上&#xff0c;用于接收和处理客户端请求&#xff0c;并提供相应服务和资…

【Go 基础篇】Go语言闭包详解:共享状态与函数式编程

介绍 在Go语言中&#xff0c;闭包是一种强大的编程特性&#xff0c;它允许函数内部包含对外部作用域变量的引用。闭包使得函数可以捕获和共享外部作用域的状态&#xff0c;实现更加灵活和复杂的编程模式。本篇博客将深入探讨Go语言中闭包的概念、用法、实现原理以及在函数式编…

【Linux】冯诺依曼体系结构思想

冯诺依曼体系结构 冯诺依曼体系结构冯诺依曼体系结构的五大部分冯诺依曼体系结构的运行过程存储器中的木桶效应扩展&#xff1a;计算机存储设备金字塔实例&#xff1a;qq聊天数据传输过程 &#x1f340;小结&#x1f340; &#x1f389;博客主页&#xff1a;小智_x0___0x_ &…

【VMware】CentOS 设置静态IP(Windows 宿主机)

文章目录 1. 更改网络适配器设置2. 配置虚拟网络编辑器3. 修改 CentOS 网络配置文件4. ping 测试结果 宿主机&#xff1a;Win11 22H2 虚拟机&#xff1a;CentOS-Stream-9-20230612.0 (Minimal) 1. 更改网络适配器设置 Win R&#xff1a;control 打开控制面板 依次点击&#x…

婉约而深刻:二叉树的中序遍历之旅

力扣题目传送门https://leetcode.cn/problems/binary-tree-inorder-traversal/ 二叉树 在这篇文章中&#xff0c;我们将深入探讨题目 "94. 二叉树的中序遍历" 的内涵与解题方法。这个问题引导我们遍历一棵二叉树&#xff0c;以中序的方式呈现节点顺序&#xff0c;从…

windows安装新openssl后依然显示旧版本

1、Windows环境下升级openssl后&#xff0c;通过指令openssl version -a查看版本号&#xff1a; 这个版本号是以前的老版本&#xff0c;不知道在哪里 2、网上找了老半天也没找到答案&#xff0c;最后通过指令 where openssl 才找到原来的openssl在哪里&#xff0c;把老的卸载掉…

【安全】原型链污染 - Hackit2018

目录 准备工作 解题 代码审计 Payload 准备工作 将这道题所需依赖模块都安装好后 运行一下&#xff0c;然后可以试着访问一下&#xff0c;报错是因为里面没内容而已&#xff0c;不影响,准备工作就做好了 解题 代码审计 const express require(express) var hbs require…

aqs的今生

《AQS的前世&#xff0c;从1990年的论文说起》中我们已经对AQS做了简单的介绍&#xff0c;并学习了先于AQS出现的3种基于排队思想的自旋锁。今天我们深入到AQS的设计中&#xff0c;探究Doug Lea是如何构建JUC框架基础组件的。不过在正式开始前&#xff0c;我们先来回顾上一篇中…