利用Spring boot、neo4j、echarts可视化雪中悍刀行

2 篇文章 0 订阅
1 篇文章 1 订阅

效果如下:

搜索李淳罡:

 

添加节点和关系,在这里添加李淳罡-喜欢-绿袍,如下多出李淳罡和绿袍的关系和绿袍的节点

 

在neo4j中,存储如下图

SDN似乎无法任意存储关系,故在这里使用的neo4j-java-driver完成的以上功能:

[neo4jConfig.java]

加载驱动和提供session

package com.sandalen.water.config;

import com.sandalen.water.PropertiesClass.Neo4jProperties;
import org.neo4j.driver.v1.AuthTokens;
import org.neo4j.driver.v1.Driver;
import org.neo4j.driver.v1.GraphDatabase;
import org.neo4j.driver.v1.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Neo4jConfig {
    @Autowired
    private Neo4jProperties neo4jProperties;

    @Bean(name="NeoSession")
    public Session initDriver(){
        Session session = null;
        try
        {
            Driver driver = GraphDatabase.driver(neo4jProperties.getURI(), AuthTokens.basic(neo4jProperties.getUsername(), neo4jProperties.getPassword()));
            session = driver.session();
            return session;
        }
        catch (Exception e){
            e.printStackTrace();
            return session;
        }

    }
}

 [CypherUtils.java]

这里主要定义了一些cypher语句

package com.sandalen.water.other;

import org.springframework.stereotype.Component;


@Component
public class CypherUtils {
    

    public static String createSingle(String entity){
        return "merge (m:Person{name:\""+entity+"\"}) return m";
    }

    public static String createRelationByTwoNodes(String entityFrom,String relation,String entityTo){
        return "match(m:Person{name:\""+entityFrom+"\"}),(n:Person{name:\""+entityTo+"\"}) merge (m)-[r:"+relation+"]->(n) return m,n,r";
    }

    public static String searchAll(String entityName){
        if(entityName == "" || entityName == null){
            return "match (m)-[edge]->(n) return m,edge,n";
        }

        return "match (m)-[edge]-(n) where n.name='" + entityName + "' return m,edge,n";
    }
    

}

[Neo4jUtils.java]

添加、查找关系和节点的逻辑实现,其中添加的逻辑是先查询输入的两个实体,若任意实体不存在则先创建,再根据这两个节点添加关系。

查找的逻辑很简单,不再赘述。

package com.sandalen.water.util;


import com.sandalen.water.other.CypherUtils;
import org.neo4j.driver.v1.*;
import org.neo4j.driver.v1.types.Relationship;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class Neo4jUtils {
    private static Session session;

    @Autowired
    public Neo4jUtils(Session NeoSession){
        Neo4jUtils.session= NeoSession;
    }

    public static boolean create(String entityFrom,String relation,String entityTo){
        try {
            StatementResult statementResult = session.run(CypherUtils.createSingle(entityFrom));
            List<Record> entityFromlist = statementResult.list();

            StatementResult entityToResult = session.run(CypherUtils.createSingle(entityTo));
            List<Record> entityToList = entityToResult.list();

            if(entityFromlist.size() == 0){
                session.run(CypherUtils.createSingle(entityFrom));
            }

            if(entityToList.size() == 0){
                session.run(CypherUtils.createSingle(entityTo));
            }

            StatementResult result = session.run(CypherUtils.createRelationByTwoNodes(entityFrom, relation, entityTo));
            return true;
        }
        catch (Exception e){
            e.printStackTrace();
            return false;
        }

    }

    public static Map<String,Object> searchAll(String entityName){
        StatementResult result = session.run(CypherUtils.searchAll(entityName));
        List<Record> list = result.list();

        Map<String,Object> resultMap = new HashMap<>();

        Set<String> nodes = new HashSet<>();
        List<String> relationships = new ArrayList<>();
        for (Record r : list){
            String start_node = r.get("m").get("name").toString().replace("\"","");
            String relationship = r.get("edge").asRelationship().type().replace("\"","");
            String end_node = r.get("n").get("name").toString().replace("\"","");

//            System.out.println(start_node + "-" + relationship + "->" + end_node );
            relationship = start_node + "-" + relationship + "-" + end_node;
            nodes.add(start_node);
            nodes.add(end_node);
            relationships.add(relationship);

        }


        resultMap.put("nodes",nodes);
        resultMap.put("relationships",relationships);

        return resultMap;
    }

}

[controller]

package com.sandalen.water.controller;

import com.sandalen.water.bean.RespBean;
import com.sandalen.water.service.KgService;
import com.sandalen.water.util.Neo4jUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RequestMapping("/kg")
@RestController
public class KgController {
    @Autowired
    private KgService kgService;

    @RequestMapping("/saveEntity")
    public RespBean saveEntity(String entityFrom,String relation,String entityTo){
        boolean isCreated = Neo4jUtils.create(entityFrom, relation, entityTo);
        if(isCreated){
            return RespBean.ok("创建数据成功");
        }

        return RespBean.error("创建失败");

    }

    @RequestMapping("/search")
    public RespBean searchAll(String entityName){
        Map<String, Object> map = Neo4jUtils.searchAll(entityName);
        return RespBean.ok("获取数据成功",map);
    }

}

[前端]

前端代码只提供页面的,我使用的是element Ui和vue

<template>
  <div class="kgContainer">
    <div class="alert alert-info" role="alert" style="margin-bottom: 20px;">
      <h1>Prompt</h1>
      <font size="4">输入你想要搜索的知识</font>
    </div>
    <div class="search" style="text-align: center;margin-bottom: 50px;">
      <el-input v-model="entityName" placeholder="请输入内容" style="width: 400px;"></el-input>
      <el-button type="primary" icon="el-icon-search" @click="initData">搜索</el-button>
      <el-input v-model="form.entityFrom" placeholder="请输入内容" style="width: 100px;"></el-input>
      <el-input v-model="form.relation" placeholder="请输入内容" style="width: 100px;"></el-input>
      <el-input v-model="form.entityTo" placeholder="请输入内容" style="width: 100px;"></el-input>
      <el-button type="primary" icon="el-icon-search" @click="add">添加</el-button>
    </div>
    <div class="kgShow" id="kgShow" style="width: 100%;">

    </div>

    <!--<div class="test" id="tst" style="width: 100%;height: 500px;"></div>-->
  </div>
</template>

<script>
  var echarts = require('echarts');
  export default {
    data() {
      return {
        entityName: '',
        option: '',
        form: {
          entityFrom: '',
          relation: '',
          entityTo: ''
        },
        nodes: [],
        relationships: []
      }
    },
    mounted() {
      this.initData()
      this.tst()
    },
    inject: ['reload'],
    methods: {
      initData() {
        this.$store.dispatch('kg/search', this.entityName).then(response => {
          const nodes = response.nodes
          const relationship = response.relationships
          const nodesList = []
          for(let i = 0; i < nodes.length; i++) {
            const tmp = {
              name: nodes[i],
              symbolSize: 50,
              itemStyle: {
                normal: {
                  show: true,
                }
              }
            }
            nodesList.push(tmp)
          }

          const links = []
          for(let i = 0; i < relationship.length; i++) {
            const relationshipArray = relationship[i].split("-")
            const tmp = {
              source: relationshipArray[0],
              target: relationshipArray[2],
              name: relationshipArray[1]
            }
            links.push(tmp)
          }

          const option = {
            title: {
              text: '雪中悍刀行'
            },
            tooltip: {
              formatter: function(x) {
                return x.data.name;
              }
            },
            animationDurationUpdate: 1500,
            animationEasingUpdate: 'quinticInOut',
            series: [{
              type: 'graph',
              layout: 'force',
              symbolSize: 80,
              roam: true,
              label: {
                normal: {
                  show: true,
                }
              },
              edgeSymbol: ['circle', 'arrow'],
              edgeSymbolSize: [4, 10],
              edgeLabel: {
                normal: {
                  textStyle: {
                    fontSize: 20
                  }
                }
              },
              force: {
                repulsion: 3000, //斥力
                edgeLength: [20, 80] //默认距离
              },
              //            layout:'circular',
              draggable: true,
              lineStyle: {
                normal: {
                  width: 2,
                  color: '#4b565b',
                  curveness: 0.2,
                  length: 20
                }
              },
              edgeLabel: {
                normal: {
                  show: true,
                  formatter: function(x) {
                    return x.data.name;
                  }
                }
              },
              data: nodesList,
              links: links
            }]
          }
          this.option = option

          this.showKg()
        })
      },
      add() {
        this.$store.dispatch('kg/save', this.form).then(response => {
          if(response.status == 200) {
            this.$message({
              message: response.msg,
              type: 'success'
            })

            this.reload()
          }
        })
      },
      getInfo(params) {
        alert(params)
      },
      showKg() {
        const kgShow = document.getElementById('kgShow')
        const myChart = echarts.init(kgShow, 'light')
        myChart.setOption(this.option)

        let data = myChart._model.option.series[0].data;
        myChart.on("click", (chartParam) => {
          //        console.log(myChart._model)
          //        console.log(chartParam)
          const entityName = data[chartParam.dataIndex].name
          this.entityName = entityName
          this.initData()
        });

        myChart.on("mouseover", (chartParam) => {
          console.log(chartParam)
        })
       
      }
    }
  }
</script>

<style>
  .kgContainer {
    width: 100%;
    background-color: #FFFFFF;
    padding: 32px;
  }
  
  .kgShow {
    width: 100%;
    height: 500px;
  }
</style>

 

  • 6
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 26
    评论
回答: 要通过echarts可视化Neo4j数据,你可以按照以下步骤进行操作。首先,你需要在你的项目中引入echarts库。然后,你可以使用Neo4j的查询语句获取你需要的数据。例如,你可以使用类似于`graph.run('match(n)<-\[r\]->(m) where n.name = "甲" return r').data()`的查询语句来获取关系的属性内容\[2\]。接下来,你可以将查询结果转换为echarts所需的数据格式,并将其传递给echarts进行可视化展示。你可以使用Java或其他编程语言来处理数据并生成echarts所需的JSON格式数据。最后,你可以将生成的JSON数据传递给echarts进行可视化展示。在你的Neo4j项目中,你可以创建一个控制器类来处理echarts的请求,并将可视化结果返回给前端\[3\]。这样,你就可以通过echarts实现Neo4j数据的可视化展示了。 #### 引用[.reference_title] - *1* *3* [利用Spring bootneo4jecharts可视化雪中悍刀行](https://blog.csdn.net/qq_34661106/article/details/103540826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [neo4j web可视化 echarts django](https://blog.csdn.net/Qq2466930350/article/details/127208289)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值