书写理由:图形数据库势必会成为全新的一种数据存储工具,有必要了解一下图形数据库的相关操作,因此在忙完公司事情的时候,写下自己的项目经历,与广大程序员同学进行学习交流
需求:公司要对组织结构进行灵活划分,和业务统计,技术选型上就采用了neo4j图形计算数据库
说明:neo4j安装网上很多,这里不再赘述。
不多说了直接上代码吧:
第一步:pom.xml 添加一下依赖
<dependency> <groupId>org.neo4j.driver</groupId> <artifactId>neo4j-java-driver</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>com.steelbridgelabs.oss</groupId> <artifactId>neo4j-gremlin-bolt</artifactId> <version>0.3.1</version> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency>
第二步:配置neo4j相关配置到 application.properties(yml)文件
#neo4j 配置 spring.data.neo4j.uri=http://localhost:7474 spring.data.neo4j.username=neo4j spring.data.neo4j.password=123456 spring.data.neo4j.url=bolt://localhost:7687 #neo4j因果集群url配置 spring.data.neo4j.urls=bolt+routing://localhost:7687,bolt+routing://localhost:7687,bolt+routing://localhost:7687
第三步:neo4j数据库链接Driver类配置
@Component public class GremlinGraph { @Autowired private Neo4jConfiguration config; @Autowired private Driver neo4jDriver; /** * 获取驱动 * * @return */ @Bean(name = "neo4jDriver") private Driver getNeo4jDriver() { String url = config.getUrl(); String username = config.getUsername(); String password = config.getPassword(); List<URI> urls = config.getUrls(); Driver driver; if (StringUtils.isBlank(url)) { driver = GraphDatabase.routingDriver(urls, AuthTokens.basic(username, password), Config.defaultConfig()); } else { driver = GraphDatabase.driver(url, AuthTokens.basic(username, password)); } return driver; } public Neo4JGraph getGraph() { Neo4JNativeElementIdProvider vertexIdProvider = new Neo4JNativeElementIdProvider(); Neo4JNativeElementIdProvider edgeIdProvider = new Neo4JNativeElementIdProvider(); Neo4JGraph graph = new Neo4JGraph(neo4jDriver, vertexIdProvider, edgeIdProvider); graph.setProfilerEnabled(true); return graph; } }
第四步:这里举一个深度模糊查询并分页的api查询语句)
4.1 Controller层
@RestController @RequestMapping(value = "/neo4j") public class StructureController { @Autowired private StructureService structureService; @RequestMapping(value = "/page/force/grap", method = RequestMethod.POST) public PageResponse<Map<String, Object>> pageForceGraph(@RequestBody PageRequest<FuzzySearchRequest> request) { // 这里需要校验如参数(这里就省略了) return structureService.pageForceGraph(request); } }
4.2 service层
public PageResponse<Map<String, Object>> pageForceGraph(PageRequest<FuzzySearchRequest> request) { PageResponse<Map<String, Object>> response = new PageResponse<>(); FuzzySearchRequest searchRequest = request.getRequest(); int pageSize = request.getPageSize() == 0 ? 10 : request.getPageSize(); // 查询neo4j数据库进行迷糊和分页查询 List<Record> records = structureDao.pageForceGraph(request); if (CollectionUtils.isEmpty(records)) { // 这里抛业务异常(项目做了全局异常处理) } // 查询要查询的数据总量 Long count = structureDao.count(searchRequest.getParentNodeId(), searchRequest.getName()); // 组装返沪数据 response.setTotal(count); long pages = count / pageSize +(count % pageSize !=0 ? 1: 0); response.setPages(pages); Map<String, List<Map<String, Object>>> graphs = NodeUtil.getGrap(records); response.setNodes(graphs.get("nodes")); response.setEdges(graphs.get("edges")); return response; }
4.3 structureDao层 (这里设计到2个方法,count和pageForceGraph)
/** * 分页模糊查询 * * @param request 父级 主键id 以及节点属性名称 * @return 节点集合信息 */ public List<Record> pageForceGraph(PageRequest<FuzzySearchRequest> request) { List<Record> response = new ArrayList<>(); FuzzySearchRequest searchRequest = request.getRequest(); String cql; String name = searchRequest.getName(); Long nodeId = searchRequest.getParentNodeId(); // 计算分页参数 int pageSize = request.getPageSize() == 0 ? 10 : request.getPageSize(); int pageNum = request.getPageNum() == 0 ? 1 : request.getPageNum(); int skipCount = (pageNum - 1) * pageSize; // 获取驱动 try (Neo4JGraph graph = gremlinGraph.getGraph()) { if (StringUtils.isNotEmpty(name)) { cql = String.format("match data=(n)-[*1]-(m) where id(n)={nodeId} and name=~"+"'.*" + name + "'.*" +"return data skip %s limit %s",skipCount, pageSize); } else { cql = String.format("match data=(n)-[*1]-(m) where id(n)={nodeId} return data skip %s limit %s",skipCount, pageSize); } StatementResult execute = graph.execute(cql, Collections.singletonMap("nodeId", nodeId)); response = execute.list(); } catch (Exception e) { // log.error("......") } return response; } /** * 查询节点数量 * * @param nodeId 父级 主键id * @param name 节点属性名称 * @return 节点数量 */ public Long count(Long nodeId, String name) { Long response = 0L; String cql; try (Neo4JGraph graph = gremlinGraph.getGraph()) { if (StringUtils.isNotEmpty(name)) { cql = "match data=(n)-[*1]-(m) where id(n)={nodeId} and name=~"+"'.*" + name + "'.*" +"return count(data))"; } else { cql = "match data=(n)-[*1]-(m) where id(n)={nodeId} return count(data))"; } StatementResult execute = graph.execute(cql, Collections.singletonMap("nodeId", nodeId)); List<Record> list = execute.list(); if (CollectionUtils.isNotEmpty(list)) { Record record = list.get(0); List<Value> values = record.values(); Value value = values.get(0); response = value.asLong(); } } catch (Exception e) { // log.error("......") } return response; }
4.4 NodeUtil
public class NodeUtil { /** * records 转 map * * @param records * @return */ public static Map<String, List<Map<String, Object>>> getGrap(List<Record> records) { Map<String, List<Map<String, Object>>> map = new HashMap<>(2); List<Node> nodeList = new ArrayList<>(); List<Relationship> edgeList = new ArrayList<>(); records.forEach(e->{ // data 为cql cypher查询语句命名的别名 PathValue pathValue =(PathValue)e.get("data"); Path path = pathValue.asPath(); nodeList.addAll(IteratorUtils.asList(path.nodes())); edgeList.addAll(IteratorUtils.asList(path.relationships())); }); map.put("nodes",node2List((nodeList.stream().distinct().collect(Collectors.toList())))); map.put("edges",edge2List((edgeList.stream().distinct().collect(Collectors.toList())))); return map; } /** * nodes 转list * * @param nodes * @return */ public static List<Map<String, Object>> node2List(List<Node> nodes) { List<Map<String, Object>> maps = new ArrayList<>(); nodes.forEach(node->{ Map<String, Object> map = new HashMap<>(); map.putAll(node.asMap()); map.put("label", node.labels()); map.put("id", node.id()); maps.add(map); }); return maps; } /** * Relationship 转list * * @param edges * @return */ public static List<Map<String, Object>> edge2List(List<Relationship> edges) { List<Map<String, Object>> maps = new ArrayList<>(); edges.forEach(edge->{ maps.add(edge2Map(edge)); }); return maps; } /** * Relationship 转 map * * @param edge * @return */ public static Map<String, Object> edge2Map(Relationship edge) { Map<String, Object> map = new HashMap<>(); map.put("source", edge.startNodeId()); map.put("relation", edge.type()); map.put("target", edge.endNodeId()); return map; } }
结束语: 真是代码一行一行的敲的,楼主原创,切勿抄袭,有不对的地方希望大家可以指正!突然发现要吃午饭了!