Neo4j是用Java实现的开源NoSQL图数据库。从2003年开始开发,2007年正式发布第一版,其源码托管于GitHtb。Neo4j作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理、软件分析、组织和项目管理、社交项目等方面。
通过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的数据结构
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依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-neo4j</artifactId>
- </dependency>
编写application.yml
- server:
- port: 9902
- spring:
- application:
- name: sl-express-sdn
- data:
- neo4j:
- database: neo4j
- neo4j:
- authentication:
- username: neo4j
- password: neo4j123
- uri: 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
{ -
- }
Neo4jRepository需要提供: 实体类和Id的类型。
在SDK中只要我们使用符合规范的名命,SDN就可以自动实现对应的方法(有点类似mybatis-plus)。
对应名字规范为下:
例子为下:
- import com.sl.ms.Entitys.AgencyEntity;
- import org.springframework.data.neo4j.repository.Neo4jRepository;
-
- /**
- * 网点操作
- */
- public interface AgencyRepository extends Neo4jRepository
{ - /**
- * 根据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 {
- @Resource
- private AgencyRepository agencyRepository;
- @Test
- public 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 {
- @Resource
- private Neo4jClient neo4jClient;
- /**
- * 根据起止网点 查询转运路线最短的路线信息
- * @param start 开始网点
- * @param end 结束网点
- * @return
- */
-
- //查询的CQL语句为: (最好不用进行拼接,直接用一个完整的字符串)
- // MATCH path = shortestPath((n:AGENCY) -[*..10]->(m:AGENCY))
- // WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"
- // RETURN path
- @Override
- public 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
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();
- // 创建路线对象 TransportLineNodeDTO
- TransportLineNodeDTO transportLineNodeDTO = new TransportLineNodeDTO();
- path.nodes().forEach(node -> {
- // 遍历路径下的所有节点
- Map
nodeMap = node.asMap(); - // 将每一个节点信息封装成一个OrganDTO
- // 通过节点得到参数map,将map转为OrganDTO tips: BeanUtil
- OrganDTO organDTO = BeanUtil.toBeanIgnoreError(nodeMap, OrganDTO.class);
- //此时organDTO中的type和经纬度都是null,我们需要为其赋值
- //标签会存在多个,这里我们就取第一个
- String title = CollUtil.getFirst(node.labels());
- // OrganDTO设置类型: 取Node中第一个标签作为类型 tips: OrganTypeEnum
- organDTO.setType(OrganTypeEnum.valueOf(title).getCode());
- // OrganDTO设置经纬度: 取出经纬度 经纬度类: InternalPoint2D
- //从Map中获取经纬度
- InternalPoint2D location = MapUtil.get(nodeMap, "location", InternalPoint2D.class);
- organDTO.setLatitude(location.x());//设置纬度,为x
- organDTO.setLongitude(location.y());//设置经度,为y
- // 存入到 路线对应的节点集合中
- transportLineNodeDTO.getNodeList().add(organDTO);
- });
- path.relationships().forEach(relationship -> {
- // 遍历路径下的所有关系
- // 将每个路线的成本加一起 得到路线总成本 保留2位小数
- Map
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 {
- @Resource
- private TransportLineRepository transportLineRepository;
- @Test
- void 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);
- }
- }
最终成功获取到最短的路径和费用。