neo4j数据库使用Bolt转换RestApi请求结果格式

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

在做图数据库的数据库可视化的时候,使用到了eisman/neo4jd3这个可视化库,查看了一下其数据格式,发现和neo4j自带的RestApi接口大致一致,d3库数据格式为👇,

{
    "results": [
        {
            "columns": ["user", "entity"],
            "data": [
                {
                    "graph": {
                        "nodes": [
                            {
                                "id": "1",
                                "labels": ["User"],
                                "properties": {
                                    "userId": "eisman"
                                }
                            },
                            {
                                "id": "8",
                                "labels": ["Project"],
                                "properties": {
                                    "name": "neo4jd3",
                                    "title": "neo4jd3.js",
                                    "description": "Neo4j graph visualization using D3.js.",
                                    "url": "https://eisman.github.io/neo4jd3"
                                }
                            }
                        ],
                        "relationships": [
                            {
                                "id": "7",
                                "type": "DEVELOPES",
                                "startNode": "1",
                                "endNode": "8",
                                "properties": {
                                    "from": 1470002400000
                                }
                            }
                        ]
                    }
                }
            ]
        }
    ],
    "errors": []
}

而neo4j RestAPI返回的数据为↓,可以看到两者的格式还是有些地方不一样的

{
    "results": [
        {
            "columns": [
                "p"
            ],
            "data": [
                {
                    "row": [
                        [
                            {
                                "updateDate": 1608600619,
                                "departmentId": 880,
                                "sex": "35",
                                "mobile": "11112247826",
                                "political": "党员",
                                "birth": 801936000,
                                "userCode": "110000200001010001",
                                "post": "会计",
                                "leaveDate": 1608600622,
                                "name": "张三",
                                "national": "",
                                "email": "",
                                "education_degree": "",
                                "createDate": 1607576509,
                                "status": "在职"
                            },
                            {},
                            {
                                "updateDate": 1608600619,
                                "name": "财务部",
                                "pid": 879,
                                "order": 4,
                                "syncId": "880"
                            }
                        ]
                    ],
                    "meta": [
                        [
                            {
                                "id": 22,
                                "type": "node",
                                "deleted": false
                            },
                            {
                                "id": 2,
                                "type": "relationship",
                                "deleted": false
                            },
                            {
                                "id": 1,
                                "type": "node",
                                "deleted": false
                            }
                        ]
                    ]
                }
            ]
        }
    ],
    "errors": []
}

使用postman请求Neo4j REST API 文档

  • 这里用到的接口 /db/data/transaction/commit
  • POST body
{
  "statements" : [{
      "statement": "MATCH p=(n:oa_userInfo)-[:`部门`]-() where n.name='张三' RETURN p LIMIT 25"
    }]
}

在这里插入图片描述

这里要加上鉴权,以及请求头Content-Type: application/json
在这里插入图片描述
这样就可以得到上边的结果,可以使用neo4jd3对数据渲染

由于在系统中已经使用了bolt的连接方式,于是尝试使用neo4j.ogm驱动中的session去请求查询,将结果转换,返回和RestApi一样的结果
springboot中可以直接取得SessionFactory (编码使用的是kotlin)

@Autowired
 private lateinit var sessionFactory: SessionFactory

声明一个结果类

class QueryRest {

  data class results(
          var errors: MutableList<Any>?,
          var results: MutableList<Result>?
  )

  data class Result(
          var columns: MutableList<String>,
          var `data`: MutableList<Data>
  )

  data class Data(
          var graph: Graph
  )

  data class Graph(
          var nodes: List<Node>,
          var relationships: List<Relationship>
  )

  data class Node(
          var id: String,
          var labels: ArrayList<String>,
          var properties: Any?
  )

  data class Relationship(
          var endNode: String,
          var id: String,
          var properties: Any?,
          var startNode: String,
          var type: String
  )
}

ServerImpl

初步实现的效果,直接传递Cypher语句并不严谨,可能会存在注入问题

    override fun query(sql: String): QueryRest.results {
        val session: Session = sessionFactory.openSession()
        val grep = session.query(sql, mutableMapOf<String, String>())
        val results = mutableListOf<QueryRest.Result>()
        val columns = mutableListOf<String>()

        val datas = mutableListOf<QueryRest.Data>()
        grep.forEach { map ->
            map.forEach { (key, value) ->
                columns.add(key)
                val v = value as Array<*>
                v.forEach {
                    val vv = it as Path.Segment
                    val nodeStart = QueryRest.Node(
                            id = vv.start().id().toString(),
                            labels = vv.start().labels() as ArrayList<String>,
                            properties = vv.start().asMap()
                    )
                    val nodeEnd = QueryRest.Node(
                            id = vv.end().id().toString(),
                            labels = vv.end().labels() as ArrayList<String>,
                            properties = vv.end().asMap()
                    )
                    val nodes = mutableListOf<QueryRest.Node>(nodeStart, nodeEnd)
                    val relationship = QueryRest.Relationship(
                            id = vv.relationship().id().toString(),
                            type = vv.relationship().type(),
                            startNode = vv.relationship().startNodeId().toString(),
                            endNode = vv.relationship().endNodeId().toString(),
                            properties = vv.relationship().asMap()
                    )
                    val relationships = mutableListOf<QueryRest.Relationship>(relationship)
                    val graph = QueryRest.Graph(nodes, relationships)
                    datas.add(QueryRest.Data(graph))
                    logger.info("$value -- $vv")
                }
            }
        }
        results.add(QueryRest.Result(columns.distinct() as MutableList<String>, datas))
        return QueryRest.results(mutableListOf(), results)
    }

over


2020/12/22 更新

使用过程中发现ogm的一个TODO,是否自动映射Bean,现在我使用的neo4j-ogm-bolt-driver:3.2.18默认是开启映射的,所以上方的转换代码可能会出现一些问题,影响到我们功能的使用。
Are we going to use the neo4jOperations conversion method to cast the value object to its proper class?

    /**
     * a cypher statement this method will return a Result object containing a collection of Map's which represent Neo4j
     * objects as properties, along with query statistics if applicable.
     * Each element of the query result is a map which you can access by the name of the returned field
     * TODO: Are we going to use the neo4jOperations conversion method to cast the value object to its proper class?
     *
     * @param cypher     The parameterisable cypher to execute.
     * @param parameters Any parameters to attach to the cypher.
     * @param readOnly   true if the query is readOnly, false otherwise
     * @return A {@link Result} of {@link Iterable}s with each entry representing a neo4j object's properties.
     */
    Result query(String cypher, Map<String, ?> parameters, boolean readOnly);

在这里插入图片描述
通过Debug neo4j-ogm源代码,找到自动转换的类,发现无法使用重写解决,经过研究Neo4jSession的类变量,针对这个问题,对原有的handlers做了如下更改:

private fun handlers(grep: org.neo4j.ogm.model.Result): QueryRest.results {
        val results = mutableListOf<QueryRest.Result>()
        val columns = mutableListOf<String>()
        val daTas = mutableListOf<QueryRest.Data>()
        grep.forEach { map ->
            map.forEach { (key, value) ->
                columns.add(key)
                if (value is Array<*>) {
                    // 是查询的结点关系数据
                    // MATCH p=(n)-[r]-()
                    value.forEach {
                        val vv = it as Path.Segment
                        val nodeStart = QueryRest.Node(
                            id = vv.start().id().toString(),
                            labels = vv.start().labels() as ArrayList<String>,
                            properties = vv.start().asMap()
                        )
                        val nodeEnd = QueryRest.Node(
                            id = vv.end().id().toString(),
                            labels = vv.end().labels() as ArrayList<String>,
                            properties = vv.end().asMap()
                        )
                        val nodes = mutableListOf<QueryRest.Node>(nodeStart, nodeEnd)
                        val relationship = QueryRest.Relationship(
                            id = vv.relationship().id().toString(),
                            type = vv.relationship().type(),
                            startNode = vv.relationship().startNodeId().toString(),
                            endNode = vv.relationship().endNodeId().toString(),
                            properties = vv.relationship().asMap()
                        )
                        val relationships = mutableListOf<QueryRest.Relationship>(relationship)
                        val graph = QueryRest.Graph(nodes, relationships)
                        daTas.add(QueryRest.Data(graph))
                    }
                } else if (value is NodeModel) {
                    // 是查询的结点数据
                    // MATCH (n:make_sec_entity) RETURN n LIMIT 3
                    val arraylist = ArrayList<String>(7)
                    value.labels.forEach {
                        arraylist.add(it)
                    }
                    val propertiesMap = HashMap<String, String>(8)
                    value.propertyList.forEach {
                        propertiesMap[it.key] = it.value.toString()
                    }
                    val node = QueryRest.Node(
                        id = value.id.toString(),
                        labels = arraylist,
                        properties = propertiesMap
                    )
                    val nodes = mutableListOf(node)
                    daTas.add(QueryRest.Data(QueryRest.Graph(nodes, null)))
                    // throw BizException(500, "暂时不可查询未计算关系的数据")
                } else {
                    val node = beanToNodeModel(value)
                    val nodes = mutableListOf(node)
                    daTas.add(QueryRest.Data(QueryRest.Graph(nodes, null)))
                }
            }
        }
        results.add(QueryRest.Result(columns.distinct() as? MutableList<String>, daTas))
        if (results.size != 0) {
            logger.info("-*---图数据查询成功")
        }
        return QueryRest.results(mutableListOf(), results)
    }

    private fun beanToNodeModel(bean: Any): QueryRest.Node {
        val neo4jSession = session as Neo4jSession
        val metadata = neo4jSession.metaData()
        val label = metadata.classInfo(bean::class.java).neo4jName()
        val id = metadata.classInfo(bean::class.java).getFieldInfo("id").read(bean)
        return QueryRest.Node(
            id = id.toString(),
            labels = arrayListOf(label),
            properties = bean
        )
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值