Neo4j深度学习
Neo4j的简介
Neo4j是用Java实现的开源NoSQL图数据库。从2003年开始开发,2007年正式发布第一版,其源码托管于GitHtb。Neo4j作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理、软件分析、组织和项目管理、社交项目等方面。
Neo4j的安装(docker安装)
通过docker拉起镜像
docker pull neo4j:4.4.5
创建/data/neo4j文件夹,用于配置文件夹的挂载
kmdir /data/neo4j
启动docker容器(需要开启对应的映射端口,这里需要开放的端口就是 7474,7687)
docker run \
-d \
--restart=always \
--name neo4j \
-p 7474:7474 \
-p 7687:7687 \
-v neo4j:/data \
neo4j:4.4.5
neo4j控制面板的地址: http://localhost:7474/browser/
初始的账号为:neo4j,密码为:neo4j。
如果出现下面情况,说明neo4j设置了只应许本地连接。
需要进入容器中修改 neo4f.conf文件
进入neo4j容器
docker exec -it 对应的容器Id /bin/bash
进入/conf文件夹中
cd /conf
在容器中默认是没有安装vim的,所以我需要手动安装
apt-get update
apt-get install -y vim
修改neo4j.conf中的配置
将Bolt connetor的配置进行修改
dbms.connector.bolt.enabled=true
#dbms.connector.bolt.tls_level=DISABLED
dbms.connector.bolt.listen_address=对应Ip:7687
Neo4j的使用
Neo4j的数据结构
- 节点
-
- 存储实体数据,在上图中,演员、电影都是节点。
- 可以理解为关系型数据库中的表。
- 关系
-
- 存储节点之间的关系。
- 关系只能有一个类型,必须有开始节点和结束节点以及指向。
- 关系可以自我循环引用,但是两头永远不能为空。
- 属性
-
- 节点和关系都可以有属性,它是由键值对组成的。
- 节点的属性可以理解为关系型数据库中的字段。
- 关系中的属性进一步的明确了关系。
- 标签
-
- 标签是对节点的分类,这样使得构建Neo4j数据模型更加简单。
- 在上面的电影案例中,Movie、Person就是标签。
Cypher使用
1.创建数据
//查询所有数据
MATCH (n) RETURN n
//强制删除所有节点和关系,慎用!
MATCH (n) DETACH DELETE n
CREATE (n {name: $value}) RETURN n //创建节点,该节点具备name属性,n为该节点的变量,创建完成后返回该节点
CREATE (n:$Tag {name: $value}) //创建节点,指定标签
CREATE (n)-[r:KNOWS]->(m) //创建n指向m的关系,并且指定关系类型为:KNOWS//示例
CREATE (n {name:'迪士尼营业部'})
CREATE (n:AGENCY {name:'航头营业部'})
//创建浦东新区转运中心、上海转运中心节点,并且创建关系为:IN_LINE,创建完成后返回节点和关系
//TLT -> Two Level Transport(二级转运中心)
//OLT -> One Level Transport(一级转运中心)
CREATE (n:TLT {name:'浦东新区转运中心'}) -[r:IN_LINE]-> (m:OLT {name:'上海转运中心'}) RETURN n,r,m
//关系也是可以反向,并且可以为关系中指定属性
CREATE (n:TLT {name:'浦东新区转运中心'}) <-[r:OUT_LINE]- (m:OLT {name:'上海转运中心'}) RETURN n,r,m
2.查询数据
查询数据的格式为下:
[MATCH WHERE] //条件查询
[WITH [ORDER BY] [SKIP] [LIMIT]] //查询的结果以管道的形式传递给下面的语句,聚合查询必须使用WITH
RETURN [ORDER BY] [SKIP] [LIMIT] //返回、排序、跳过、返回个数
插入数据进行测试
CREATE (北京市转运中心:OLT {bid: 8001, name: "北京市转运中心", address: "北京市转运中心", location : point({latitude:39.904179, longitude:116.407387})})
CREATE (上海市转运中心:OLT {bid: 8002, name: "上海市转运中心", address: "上海市转运中心", location : point({latitude:31.230525, longitude:121.473667})})
CREATE (南京市转运中心:OLT {bid: 8003, name: "南京市转运中心", address: "南京市转运中心", location : point({latitude:32.059344, longitude:118.796624})})
CREATE (太原市转运中心:OLT {bid: 8004, name: "太原市转运中心", address: "太原市转运中心", location : point({latitude:37.870451, longitude:112.549656})})
CREATE (郑州市转运中心:OLT {bid: 8005, name: "郑州市转运中心", address: "郑州市转运中心", location : point({latitude:34.745551, longitude:113.624321})})
CREATE(北京市转运中心)-[:IN_LINE {cost:10684.9}]->(上海市转运中心),(北京市转运中心)<-[:OUT_LINE {cost:10684.9}]-(上海市转运中心),(北京市转运中心)-[:IN_LINE {cost:8993.1}]->(南京市转运中心),(北京市转运中心)<-[:OUT_LINE {cost:8993.1}]-(南京市转运中心),(南京市转运中心)-[:IN_LINE {cost:2699.4}]->(上海市转运中心),(南京市转运中心)<-[:OUT_LINE {cost:2699.4}]-(上海市转运中心),(太原市转运中心)-[:IN_LINE {cost:3609.7}]->(郑州市转运中心),(太原市转运中心)<-[:OUT_LINE {cost:3609.7}]-(郑州市转运中心),(郑州市转运中心)-[:IN_LINE {cost:5659.7}]->(南京市转运中心),(郑州市转运中心)<-[:OUT_LINE {cost:5659.7}]-(南京市转运中心)
CREATE (昌平区转运中心:TLT {bid: 90001, name: "昌平区转运中心", address: "昌平区转运中心", location : point({latitude:40.220952, longitude:116.231034})})
CREATE (北京市昌平区新龙城:AGENCY {bid: 100260, name: "北京市昌平区新龙城", address: "龙跃苑四区3号楼底商", phone : "010-53049073,010-53576707", location : point({latitude:40.07544443596149, longitude:116.3470535709328})})
CREATE(北京市昌平区新龙城)-[:IN_LINE {cost:189.7}]->(昌平区转运中心),(北京市昌平区新龙城)<-[:OUT_LINE {cost:189.7}]-(昌平区转运中心)
CREATE (北京市昌平区定泗路:AGENCY {bid: 100280, name: "北京市昌平区定泗路", address: "北七家镇定泗路苍龙街交叉口", phone : "010-86392987", location : point({latitude:40.11765281246394, longitude:116.37212849638287})})
CREATE(北京市昌平区定泗路)-[:IN_LINE {cost:166.2}]->(昌平区转运中心),(北京市昌平区定泗路)<-[:OUT_LINE {cost:166.2}]-(昌平区转运中心)
CREATE (海淀区转运中心:TLT {bid: 90002, name: "海淀区转运中心", address: "海淀区转运中心", location : point({latitude:39.959893, longitude:116.2977})})
CREATE (北京市海淀区小营:AGENCY {bid: 100347, name: "北京市海淀区小营", address: "北京市昌平区回龙观街道金燕龙大厦停车场", phone : "010-86483817,010-86483817,010-86483817", location : point({latitude:40.06177798692319, longitude:116.32706587559049})})
CREATE(北京市海淀区小营)-[:IN_LINE {cost:116.1}]->(海淀区转运中心),(北京市海淀区小营)<-[:OUT_LINE {cost:116.1}]-(海淀区转运中心)
CREATE (北京市海淀区万泉河:AGENCY {bid: 100227, name: "北京市海淀区万泉河", address: "北京市海淀区四季青镇杏石口路47号院", phone : "18521852356", location : point({latitude:39.94882822425318, longitude:116.25707017441161})})
CREATE(北京市海淀区万泉河)-[:IN_LINE {cost:36.8}]->(海淀区转运中心),(北京市海淀区万泉河)<-[:OUT_LINE {cost:36.8}]-(海淀区转运中心)
CREATE(昌平区转运中心)-[:IN_LINE {cost:383.3}]->(北京市转运中心),(昌平区转运中心)<-[:OUT_LINE {cost:383.3}]-(北京市转运中心),(海淀区转运中心)-[:IN_LINE {cost:112.3}]->(北京市转运中心),(海淀区转运中心)<-[:OUT_LINE {cost:112.3}]-(北京市转运中心)
CREATE (浦东新区转运中心:TLT {bid: 90003, name: "浦东新区转运中心", address: "浦东新区转运中心", location : point({latitude:31.221461, longitude:121.544346})})
CREATE (上海市浦东新区南汇:AGENCY {bid: 210057, name: "上海市浦东新区南汇", address: "园春路8号", phone : "18821179169", location : point({latitude:31.035240152911637, longitude:121.73459966751048})})
CREATE(上海市浦东新区南汇)-[:IN_LINE {cost:275.4}]->(浦东新区转运中心),(上海市浦东新区南汇)<-[:OUT_LINE {cost:275.4}]-(浦东新区转运中心)
CREATE (上海市浦东新区周浦:AGENCY {bid: 210127, name: "上海市浦东新区周浦", address: "川周公路3278-8号", phone : "021-68060322", location : point({latitude:31.132409729356993, longitude:121.59815370294322})})
CREATE(上海市浦东新区周浦)-[:IN_LINE {cost:111.6}]->(浦东新区转运中心),(上海市浦东新区周浦)<-[:OUT_LINE {cost:111.6}]-(浦东新区转运中心)
CREATE (奉贤区转运中心:TLT {bid: 90004, name: "奉贤区转运中心", address: "奉贤区转运中心", location : point({latitude:30.918406, longitude:121.473945})})
CREATE (上海市奉贤区东部:AGENCY {bid: 210017, name: "上海市奉贤区东部", address: "上上海市奉贤区洪庙镇洪兰路351", phone : "021-57171717", location : point({latitude:30.917752751719863, longitude:121.67587819184698})})
CREATE(上海市奉贤区东部)-[:IN_LINE {cost:192.9}]->(奉贤区转运中心),(上海市奉贤区东部)<-[:OUT_LINE {cost:192.9}]-(奉贤区转运中心)
CREATE (上海市奉贤区青村:AGENCY {bid: 210442, name: "上海市奉贤区青村", address: "姚家村1127号", phone : "021-57566663,021-57566606", location : point({latitude:30.916946897994983, longitude:121.57954144207972})})
CREATE(上海市奉贤区青村)-[:IN_LINE {cost:100.9}]->(奉贤区转运中心),(上海市奉贤区青村)<-[:OUT_LINE {cost:100.9}]-(奉贤区转运中心)
CREATE(浦东新区转运中心)-[:IN_LINE {cost:68.0}]->(上海市转运中心),(浦东新区转运中心)<-[:OUT_LINE {cost:68.0}]-(上海市转运中心),(奉贤区转运中心)-[:IN_LINE {cost:347.4}]->(上海市转运中心),(奉贤区转运中心)<-[:OUT_LINE {cost:347.4}]-(上海市转运中心)
CREATE (玄武区转运中心:TLT {bid: 90004, name: "玄武区转运中心" , location : point({latitude:32.048644, longitude:118.797779})})
CREATE (江苏省南京市玄武区紫金墨香苑:AGENCY {bid: 25073, name: "江苏省南京市玄武区紫金墨香苑", address: "栖霞区燕尧路100号", phone : "025-58765331,025-83241955,025-83241881", location : point({latitude:32.117016089520305, longitude:118.86319310255513})})
CREATE(江苏省南京市玄武区紫金墨香苑)-[:IN_LINE {cost:98.0}]->(玄武区转运中心),(江苏省南京市玄武区紫金墨香苑)<-[:OUT_LINE {cost:98.0}]-(玄武区转运中心)
CREATE (江苏省南京市玄武区长江路:AGENCY {bid: 25023, name: "江苏省南京市玄武区长江路", address: "观音阁10号", phone : "18521133265,18695799166", location : point({latitude:32.04803554410631, longitude:118.79190455263355})})
CREATE(江苏省南京市玄武区长江路)-[:IN_LINE {cost:5.6}]->(玄武区转运中心),(江苏省南京市玄武区长江路)<-[:OUT_LINE {cost:5.6}]-(玄武区转运中心)
CREATE(玄武区转运中心)-[:IN_LINE {cost:12.0}]->(南京市转运中心),(玄武区转运中心)<-[:OUT_LINE {cost:12.0}]-(南京市转运中心)
CREATE (小店区转运中心:TLT {bid: 90005, name: "小店区转运中心" , location : point({latitude:37.736865, longitude:112.565524})})
CREATE (山西省太原市青龙:AGENCY {bid: 351068, name: "山西省太原市青龙", address: "长治路33号经典家园停车场内13号商铺", phone : "0351-2025888", location : point({latitude:37.83589608758359, longitude:112.56059258109424})})
CREATE(山西省太原市青龙)-[:IN_LINE {cost:110.3}]->(小店区转运中心),(山西省太原市青龙)<-[:OUT_LINE {cost:110.3}]-(小店区转运中心)
CREATE (山西省太原市长风街:AGENCY {bid: 351045, name: "山西省太原市长风街", address: "平阳路104号省农机公司院内", phone : "18636100730", location : point({latitude:37.809964384001226, longitude:112.55299317699505})})
CREATE(山西省太原市长风街)-[:IN_LINE {cost:82.1}]->(小店区转运中心),(山西省太原市长风街)<-[:OUT_LINE {cost:82.1}]-(小店区转运中心)
CREATE(小店区转运中心)-[:IN_LINE {cost:149.4}]->(太原市转运中心),(小店区转运中心)<-[:OUT_LINE {cost:149.4}]-(太原市转运中心)
CREATE (中原区转运中心:TLT {bid: 90006, name: "中原区转运中心" , location : point({latitude:34.74828, longitude:113.612966})})
CREATE (河南省郑州市郑上路:AGENCY {bid: 371067, name: "河南省郑州市郑上路", address: "中原西路西四环西北角", phone : "0371-55116757,0371-68014786", location : point({latitude:34.74753024533005, longitude:113.57428550005442})})
CREATE(河南省郑州市郑上路)-[:IN_LINE {cost:35.4}]->(中原区转运中心),(河南省郑州市郑上路)<-[:OUT_LINE {cost:35.4}]-(中原区转运中心)
CREATE (河南省郑州市颍河路:AGENCY {bid: 371086, name: "河南省郑州市颍河路", address: "航海西路与西三环交叉口向南300米路西中贸商务", phone : "19139415556", location : point({latitude:34.71593280680163, longitude:113.60398506929064})})
CREATE(河南省郑州市颍河路)-[:IN_LINE {cost:36.9}]->(中原区转运中心),(河南省郑州市颍河路)<-[:OUT_LINE {cost:36.9}]-(中原区转运中心)
CREATE(中原区转运中心)-[:IN_LINE {cost:11.5}]->(郑州市转运中心),(中原区转运中心)<-[:OUT_LINE {cost:11.5}]-(郑州市转运中心)
基础查询
MATCH (n) RETURN n //查询所有的数据,数据量大是勿用
MATCH (n:AGENCY) RETURN n //查询所有的网点(AGENCY)
MATCH (n:OLT {name: "北京市转运中心"}) -- (m) RETURN n,m //查询所有与“北京市转运中心”有关系的节点
MATCH (n:OLT {name:"北京市转运中心"}) --> (m:OLT) RETURN n,m //查询所有"北京市转运中心"关联的一级转运中心
MATCH (n:OLT {name:"北京市转运中心"}) -[r:IN_LINE]- (m) RETURN n,r,m //可以指定关系标签查询
MATCH p = (n:OLT {name:"北京市转运中心"}) --> (m:OLT) RETURN p //将查询赋值与变量
//通过 type()函数查询关系类型
MATCH (n:OLT {name:"北京市转运中心"}) -[r]-> (m:OLT {name:"南京市转运中心"}) RETURN type(r)
关系深度查询
//查询【北京市转运中心】关系中深度为1~2层关系的节点
MATCH (n:OLT {name:"北京市转运中心"}) -[*1..2]->(m) RETURN *
//也可以这样
MATCH (n:OLT {name:"北京市转运中心"}) -[*..2]->(m) RETURN *
//也可以通过变量的方式查询
MATCH path = (n:OLT {name:"北京市转运中心"}) -[*..2]->(m)
RETURN path
//查询关系,relationships()获取结果中的关系,WITH向后传递数据
MATCH path = (n:OLT {name:"北京市转运中心"}) -[*..2]->(m)
WITH n,m, relationships(path) AS r
RETURN r
//查询两个网点之间所有的路线,最大深度为6,可以查询到2条路线
MATCH path = (n:AGENCY) -[*..6]->(m:AGENCY)
WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"
RETURN path重点:查询两地的最最短距离
//查询两个网点之间最短路径,查询深度最大为10
MATCH path = shortestPath((n:AGENCY) -[*..10]->(m:AGENCY))
WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"
RETURN path//查询两个网点之间所有的路线中成本最低的路线,最大深度为10(如果成本相同,转运节点最少)
MATCH path = (n:AGENCY) -[*..10]->(m:AGENCY)
WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"
UNWIND relationships(path) AS r //unwind将列表变成单独的一行一行的形式,就类是进行循环
WITH sum(r.cost) AS cost, path
RETURN path ORDER BY cost ASC, LENGTH(path) ASC LIMIT 1
//UNWIND是将列表数据展开操作
//sum()是聚合统计函数,类似还有:avg()、max()、min()等
分页查询
//分页查询网点,按照bid正序排序,每页查询2条数据,第一页
MATCH (n:AGENCY)
RETURN n ORDER BY n.bid ASC SKIP 0 LIMIT 2
//第二页
MATCH (n:AGENCY) skip就是跳过的个数,这里的效果就是查询第二页
RETURN n ORDER BY n.bid ASC SKIP 2 LIMIT 2
//……
3.更新数据
// 更新/设置 属性
MATCH (n:AGENCY {name:"北京市昌平区新龙城"})
SET n.address = "龙跃苑四区3号楼底商101号"
RETURN n
//通过remove移除属性
MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) REMOVE n.address RETURN n
//没有address属性的增加属性
MATCH (n:AGENCY) WHERE n.address IS NULL SET n.address = "暂无地址" RETURN n
4.删除数据
//删除节点
MATCH (n:AGENCY {name:"航头营业部"}) DELETE n
//有关系的节点是不能直接删除的
MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) DELETE n
//删除节点和关系,强制删除
MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) DETACH DELETE n
//删除所有节点和关系,慎用!
MATCH (n) DETACH DELETE n
5.索引
// 更新/设置 属性
MATCH (n:AGENCY {name:"北京市昌平区新龙城"})
SET n.address = "龙跃苑四区3号楼底商101号"
RETURN n
//通过remove移除属性
MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) REMOVE n.address RETURN n
//没有address属性的增加属性
MATCH (n:AGENCY) WHERE n.address IS NULL SET n.address = "暂无地址" RETURN n
SDN(Spring Data Neo4k)使用
导入依赖
<!--SDN依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-neo4j</artifactId></dependency>
编写application.yml
server:port: 9902
spring:application:name: sl-express-sdndata:neo4j:database: neo4jneo4j:authentication:username: neo4jpassword: neo4j123uri: neo4j://192.168.150.101:7687 #对应的neo4j的地址
使用SDN提供的Repository
SDN也是遵循了Spring Data JPA规范,同时也提供了Neo4jRepository,该接口中提供了基本的CRUD操作,我们定义Repository需要继承该接口,实现类会自动生成并配置到ioc,后续使用直接从ioc中获取即可。
我们编写Repository时只需要继承Neo4jRepository接口即可,在Neo4jRepository中提供了增删改查等一系列简单的操作方法。
实现Neo4jRepository的格式为下:
import com.sl.ms.Entitys.AgencyEntity;
import org.springframework.data.neo4j.repository.Neo4jRepository;/*** 网点操作*/
//Neo4jRepository需要提供: 实体类和Id的类型
public interface AgencyRepository extends Neo4jRepository<AgencyEntity, Long> {}
Neo4jRepository需要提供: 实体类和Id的类型。
在SDK中只要我们使用符合规范的名命,SDN就可以自动实现对应的方法(有点类似mybatis-plus)。
对应名字规范为下:
例子为下:
import com.sl.ms.Entitys.AgencyEntity;
import org.springframework.data.neo4j.repository.Neo4jRepository;/*** 网点操作*/
public interface AgencyRepository extends Neo4jRepository<AgencyEntity, Long> {/*** 根据bid查询** @param bid 业务id* @return 网点数据*/AgencyEntity findByBid(Long bid);/*** 根据bid删除** @param bid 业务id* @return 删除的数据条数*/Long deleteByBid(Long bid);
}
进行测试
测试代码为下:
import com.sl.ms.Entitys.AgencyEntity;
import com.sl.ms.Repository.AgencyRepository;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.*;
import javax.annotation.Resource;
import java.util.List;@SpringBootTest
class AgencyRepositoryTest {@Resourceprivate AgencyRepository agencyRepository;@Testpublic void testSave() {AgencyEntity agencyEntity = new AgencyEntity();agencyEntity.setAddress("测试数据地址");agencyEntity.setBid(9001L);agencyEntity.setName("测试节点");agencyEntity.setPhone("1388888888888");this.agencyRepository.save(agencyEntity);System.out.println(agencyEntity);}
}
测试结果为下:
复杂查询(自定义cql)
例子(就是获取两地的最短距离)
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.sl.ms.Entitys.AgencyEntity;
import com.sl.ms.Repository.TransportLineRepository;
import com.sl.ms.dto.OrganDTO;
import com.sl.ms.dto.TransportLineNodeDTO;
import com.sl.ms.enums.OrganTypeEnum;
import org.neo4j.driver.internal.InternalPoint2D;
import org.neo4j.driver.types.Path;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Optional;@Component
public class TransportLineRepositoryImpl implements TransportLineRepository {@Resourceprivate Neo4jClient neo4jClient;/*** 根据起止网点 查询转运路线最短的路线信息* @param start 开始网点* @param end 结束网点* @return*///查询的CQL语句为: (最好不用进行拼接,直接用一个完整的字符串)
// MATCH path = shortestPath((n:AGENCY) -[*..10]->(m:AGENCY))
// WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"
// RETURN path@Overridepublic TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end) {//获取网点数据在Neo4j中的类型,获取@Node中的属性值,这样可以动态获取节点的标签//这里的标签有: 一级转运中心,二级转运中心,站点String type = AgencyEntity.class.getAnnotation(Node.class).value()[0];//构造CQL 查询语句String Cql = StrUtil.format("MATCH path = shortestPath((n:{}) -[*..10]->(m:{})) WHERE n.bid=$startId AND m.bid=$endId RETURN path",type, type);//执行查询Optional<TransportLineNodeDTO> one = this.neo4jClient.query(Cql)// 绑定参数, cql中使用$绑定变量.bind(start.getBid()).to("startId").bind(end.getBid()).to("endId")// 设置响应类型,最终返回的类型,这里我们需要返回.fetchAs(TransportLineNodeDTO.class)// mappedBy 设置结果映射.mappedBy((typeSystem, record) -> {//record中就是查询的结果(一条最短路线),获取第一个参数,也就是path// 获取0号下标的 Path路径Path path = record.get(0).asPath();// 创建路线对象 TransportLineNodeDTOTransportLineNodeDTO transportLineNodeDTO = new TransportLineNodeDTO();path.nodes().forEach(node -> {// 遍历路径下的所有节点Map<String, Object> nodeMap = node.asMap();// 将每一个节点信息封装成一个OrganDTO// 通过节点得到参数map,将map转为OrganDTO tips: BeanUtilOrganDTO organDTO = BeanUtil.toBeanIgnoreError(nodeMap, OrganDTO.class);//此时organDTO中的type和经纬度都是null,我们需要为其赋值//标签会存在多个,这里我们就取第一个String title = CollUtil.getFirst(node.labels());// OrganDTO设置类型: 取Node中第一个标签作为类型 tips: OrganTypeEnumorganDTO.setType(OrganTypeEnum.valueOf(title).getCode());// OrganDTO设置经纬度: 取出经纬度 经纬度类: InternalPoint2D//从Map中获取经纬度InternalPoint2D location = MapUtil.get(nodeMap, "location", InternalPoint2D.class);organDTO.setLatitude(location.x());//设置纬度,为xorganDTO.setLongitude(location.y());//设置经度,为y// 存入到 路线对应的节点集合中transportLineNodeDTO.getNodeList().add(organDTO);});path.relationships().forEach(relationship -> {// 遍历路径下的所有关系// 将每个路线的成本加一起 得到路线总成本 保留2位小数Map<String, Object> relationshipMap = relationship.asMap();//获取成本Double cost = MapUtil.get(relationshipMap, "cost", Double.class);//将成本进行累加transportLineNodeDTO.setCost(transportLineNodeDTO.getCost() + cost);});// 返回路线数据return transportLineNodeDTO;}).one();//返回可能会有多个,我们直接取一个即可return one.orElse(null); //不会空时返回数据,为空时则返回null}
}
进行测试
import com.sl.ms.Entitys.AgencyEntity;
import com.sl.ms.Repository.TransportLineRepository;
import com.sl.ms.dto.TransportLineNodeDTO;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
class TransportLineRepositoryTest {@Resourceprivate TransportLineRepository transportLineRepository;@Testvoid findShortestPath() {AgencyEntity start = AgencyEntity.builder().bid(100280L).build();AgencyEntity end = AgencyEntity.builder().bid(210057L).build();TransportLineNodeDTO transportLineNodeDTO = this.transportLineRepository.findShortestPath(start, end);System.out.println(transportLineNodeDTO);}
}
最终成功获取到最短的路径和费用。
相关文章:

Neo4j深度学习
Neo4j的简介 Neo4j是用Java实现的开源NoSQL图数据库。从2003年开始开发,2007年正式发布第一版,其源码托管于GitHtb。Neo4j作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理、软件分析、组织和…...

【数据结构C/C++】链式存储与顺序存储结构栈
文章目录 链式存储结构顺序存储结构 下面这篇文章是我大二时候写的比较详细的实现过程,再这篇文章我也会再一次比较简单的再次简述一下链式与顺序存储结构的实现方式。 链式存储结构与顺序存储结构详解 这里我就不使用C再一次实现这两个栈了,有兴趣的也可…...

【数据库系统概论】数据定义之基本表的定义/创建、修改和删除
前言 🚩定义/创建基本表语法示例 修改基本表语法示例 删除基本表语法示例 感谢 💖 前言 🚩 SQL支持数据库系统的三级模式结构,其模式、外模式和内模式中的基本对象有表、视图和索引,因此,SQL的数据定义功能…...

面试算法22:链表中环的入口节点(1)
题目 如果一个链表中包含环,那么应该如何找出环的入口节点?从链表的头节点开始顺着next指针方向进入环的第1个节点为环的入口节点。 例如,在如图4.3所示的链表中,环的入口节点是节点3。 分析 第1步:确认是否包含环…...

蓝桥杯---第二讲---二分与前缀和
文章目录 前言Ⅰ. 数的范围0x00 算法思路0x00 代码书写 Ⅱ. 数的三次方根0x00 算法思路0x01代码书写 Ⅲ. 前缀和0x00 算法思路0x01 代码书写 Ⅳ. 子矩阵的和0x00 算法思路0x01 代码书写 Ⅴ. 机器人跳跃问题0x00 算法思路0x01 代码书写 Ⅵ. 四平方和0x00 算法思路0x01 代码书写 …...

d3dx9_39.dll如何修复?最新修复d3dx9_39.dll方法分享
大家好!今天我要和大家分享的主题是“d3dx9_39.dll丢失的修复方法”。我们都知道,在使用电脑的过程中,经常会遇到各种问题,而其中最常见的就是文件丢失。d3dx9_39.dll就是其中一个常见的丢失文件。那么,如何修复这个丢…...

阿里云轻量应用服务器月流量限制说明(部分套餐不限流量)
阿里云轻量应用服务器部分套餐限制月流量,轻量应用服务器按照套餐售卖,有的套餐限制月流量,有的不限制流量。像阿里云轻量2核2G3M带宽轻量服务器一年108元和轻量2核4G4M带宽一年297.98元12个月,这两款是不限制月流量的。阿里云百科…...

项目设计:YOLOv5目标检测+机构光相机(intel d455和d435i)测距
1.介绍 1.1 Intel D455 Intel D455 是一款基于结构光(Structured Light)技术的深度相机。 与ToF相机不同,结构光相机使用另一种方法来获取物体的深度信息。它通过投射可视光谱中的红外结构光图案,然后从被拍摄物体表面反射回来…...

WPF中DataContext的绑定技巧
先看效果: 上面的绑定值都是我们自定义的属性,有了以上的提示,那么我们可以轻松绑定字段,再也不用担心错误了。附带源码。 目录 1.建立mvvm项目 2.cs后台使用DataContext绑定 3.xaml前台使用DataContext绑定 4.xaml前台使用Da…...

【Spring MVC研究】MVC原理:DispatcherServlet的初始化,初始化好等于MVC准备好
文章目录 1. EnableWebMVC 开启 MVC 功能2. 初始化自定义的 MVC 组件2.1. 初始化过程2.2. 如何分析复杂的 Spring 组件注册 3. 容器启动后会初始化 DispatcherServlet4. DispatcherServlet 初始化过程总结5. 资料参考 把DispatcherServlet 准备好意味着服务器已经可以处理请求了…...

Kafka的分布式架构与高可用性
导语 一开始我们就说过Kafka是一款开源的高吞吐、分布式的消息队列系统,那么今天我们就来说下它的分布式架构和高可用性以及双/多中心部署。 Kafka 体系架构简介 以下是 Kafka 的软件架构,整个 Kafka 体系结构由 Producer、Consumer、Broker、ZooKeepe…...

Spring Cloud学习笔记【分布式请求链路跟踪-Sleuth】
文章目录 Spring Cloud Sleuth概述概述主要功能:Sleuth中的术语和相关概念官网 zipkin配置下载运行zipkin下载zipkin运行 demo配置服务提供者 lf-userpom.xmlapplication.ymlUserController 服务调用者 lf-authpom.xmlapplication.ymlAuthController 测试 Spring Cl…...

Java开发中的操作日志详解(InsCode AI 创作助手)
Java开发中的操作日志详解 一、操作日志的作用 故障排除和调试: 操作日志可以记录应用程序的各种活动,包括错误、异常、警告和信息性消息。这有助于开发人员快速定位和解决问题。性能分析: 通过记录关键操作和性能指标,操作日志…...

FutureTask和CompletableFuture的模拟使用
模拟了查询耗时操作,并使用FutureTask和CompletableFuture分别获取计算结果,统计执行时长 package org.alllearn.futurtask;import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; import lombok.AllArgsConstructor; imp…...

Redis作为缓存,mysql的数据如何与redis进行同步?
Redis作为缓存,mysql的数据如何与redis进行同步? 一定要设置前提,先介绍业务背景 延时双删 双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致 读操作:缓存命中,直接返回;缓存未…...

申请免费 SSL 证书为您的小程序加密通信
在今天的网络环境中,数据安全和隐私保护变得尤为重要。无论是网站还是应用程序,为其提供安全的通信渠道都是至关重要的。对于小程序开发者来说,使用 SSL(Secure Sockets Layer)证书可以有效地保障用户数据的安全&#…...

Go 并发编程
并发编程 1.1 并发与并⾏ 并⾏与并发是两个不同的概念,普通解释: 并发:交替做不同事情的能⼒并⾏:同时做不同事情的能⼒ 如果站在程序员的⻆度去解释是这样的: 并发:不同的代码块交替执⾏并⾏…...

鱼眼相机去畸变(图像拉直/展开/矫正)算法及实战总结
本文介绍两种方法 1、经纬度矫正法 2、棋盘格矫正法 一、经纬度矫正法 1、算法说明 经纬度矫正法, 可以把鱼眼图想象成半个地球, 然后将地球展开成地图,经纬度矫正法主要是利用几何原理, 对图像进行展开矫正。 经过P点的入射光线…...

es6 数据类型
es6 数据类型 map 数据类型 >Map 对象保存键值对。 用途 : Object的key无法支持该数据时需要了解对象大小时 map 数据类型任何值(对象或者原始值) 都可以作为一个键。 Object 的键只能是字符串 let myMap new Map(); let myMap1 new Map(); var keyStrin…...

【postgresql】
看到group by 1,2 和 order by 1, 2。看不懂,google,搜到了Stack Overflow 上有回答 What does SQL clause “GROUP BY 1” mean? 大概意思就是,group by, order by 后面跟数字,指的是 selec…...

【C++】空间配置器 allocator:原理及底层解析
文章目录 空间配置器一级空间配置器二级空间配置器1. 内存池2. SGI-STL中二级空间配置器设计 - - 哈希桶3. 二级空间配置器的空间申请 空间配置器的默认选择空间配置器的在封装:添加了数据类型大小空间配置器对象的构造与析构 容器中的 allocator 空间配置器 提到空…...

微信小程序 movable-area 区域拖动动态组件演示
movable-area 组件在小程序中的作用是用于创建一个可移动的区域,可以在该区域内拖动视图或内容。这个组件常用于实现可拖动的容器或可滑动的列表等交互效果。 使用 movable-area 组件可以对其内部的 movable-view 组件进行拖动操作,可以通过设置不同的属…...

隔离上网,安全上网
SDC沙盒数据防泄密系统(安全上网,隔离上网) •深信达SDC沙盒数据防泄密系统,是专门针对敏感数据进行防泄密保护的系统,根据隔离上网和安全上网的原则实现数据的代码级保护,不会影响工作效率,不…...

NOSQL Redis 数据持久化 RDB、AOF(二) 恢复
redis 执行flushall 或 flushdb 也会产生dump.rdb文件,但里面是空的。 注意:千万执行,不然rdb文件会被覆盖的。 dump.rdb 文件如何恢复数据 讲备份文件 dump.rdb 移动到redis安装目录并启动服务即可。 dump.rdb 自动触发 和手动触发 自…...

UDP通信
UDP通信 #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen); - 参数:- sockfd : 通信的fd- buf : 要发送的数据- len : 发送…...

Bootstrap对溢出内容的两种处理:滚动条和隐藏两种方式
Bootstrap中定义了以下两个类来处理内容溢出的情况: 类overflow-auto:在固定宽度和高度的元素上,如果内容溢出了元素,将生成一个垂直滚动条,通过滚动条可以查看溢出的内容。 类overflow-hidden:在固定宽度和高度的元素…...

elasticsearch基本语法
这里写自定义目录标题 elasticsearch简介基本语法索引创建索引修改索引删除索引 查询简单查询精确查询条件查询范围查询:聚合查询:排序和分页: 参考文献: elasticsearch简介 Elasticsearch 是一个开源的分布式搜索和分析引擎&…...

Maven Spring jar包启动报错 排查
Maven Spring jar包启动报错排查 背景 maven 编译jar包,放在linux服务器启动不起来,提示:xxxx-0.0.1-SNAPSHOT.jar中没有主清单属性 原因 pom 配置文件,多了 <skip>true</skip> <build><plugins>&l…...

LeetCode-2485-找出中枢整数
题目描述: 给你一个正整数 n ,找出满足下述条件的 中枢整数 x : 1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。 返回中枢整数 x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中…...

nano pi m1配置脚本(全志H3)
为nanopi m1写一个自动配置脚本,简化自己的操作 配置:H3芯片,1G内存,64G卡 系统:friendlycore focal 4.14版本 一、系统安装 烧录系统后,插入机器,但是使用df -ih发现只有900K的nodesÿ…...