springboot 整合 neo4j

书写理由:图形数据库势必会成为全新的一种数据存储工具,有必要了解一下图形数据库的相关操作,因此在忙完公司事情的时候,写下自己的项目经历,与广大程序员同学进行学习交流

需求:公司要对组织结构进行灵活划分,和业务统计,技术选型上就采用了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类配置

package com.sxx.neo4j.demo.config;

import com.steelbridgelabs.oss.neo4j.structure.Neo4JGraph;
import com.steelbridgelabs.oss.neo4j.structure.providers.Neo4JNativeElementIdProvider;
import org.apache.commons.lang3.StringUtils;
import org.neo4j.driver.v1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.util.List;


/**
 * @Auther: shiyi
 * @Date: 2019-04-29 08:50
 * @Description:
 */
@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层

  

package com.sxx.neo4j.demo.controller;

import com.sxx.neo4j.demo.entity.FuzzySearchRequest;
import com.sxx.neo4j.demo.entity.PageRequest;
import com.sxx.neo4j.demo.entity.PageResponse;
import com.sxx.neo4j.demo.sercive.StructureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @Auther: shiyi
 * @Date: 2019-04-29 09:59
 * @Description:
 */
@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.java 工具类

package com.sxx.neo4j.demo;

import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import org.neo4j.driver.internal.value.PathValue;
import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.types.Node;
import org.neo4j.driver.v1.types.Path;
import org.neo4j.driver.v1.types.Relationship;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Auther: shiyi
 * @Date: 2019-06-20 10:22
 * @Description: 节点工具类
 */
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;
    }


}

结束语: 真是代码一行一行的敲的,楼主原创,切勿抄袭,有不对的地方希望大家可以指正!突然发现要吃午饭了!

 

猜你喜欢

转载自www.cnblogs.com/shiyixin0125/p/11057342.html
今日推荐