書寫理由:圖形數據庫勢必會成為全新的一種數據存儲工具,有必要了解一下圖形數據庫的相關操作,因此在忙完公司事情的時候,寫下自己的項目經歷,與廣大程序員同學進行學習交流
需求:公司要對組織結構進行靈活划分,和業務統計,技術選型上就采用了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; } }
結束語: 真是代碼一行一行的敲的,樓主原創,切勿抄襲,有不對的地方希望大家可以指正!突然發現要吃午飯了!