from Neo4j to GraphJSON with Ruby

馋奶兔 提交于 2019-12-24 15:52:51

问题


I'm trying to get visualizations using d3.js or alchemy.js--but alchemy, in particular, requires the datasource to be in GraphJSON.

I've been playing around with the tutorials and examples of Max De Marzi (using neography), Michael Hunger (cy2neo, js), Neo4j, and Neo4j.rb -- but I cannot seem to get all the way there. Mostly because I don't know what I'm doing--but this is how I'm trying to learn.

What I'm trying to achieve would be along the lines of: https://bl.ocks.org/mbostock/3750558 or the default visualization here: http://graphalchemist.github.io/Alchemy/#/docs

And you can see what GraphJSON formatting should look like by finding it on this page also: http://graphalchemist.github.io/Alchemy/#/docs

If I run the following...

get '/followers' do
  Neo4j::Session.open(:server_db, "http://localhost:7474")
  query = Neo4j::Session.query('MATCH (a--(b)--(c) RETURN a,b,c LIMIT 30')
  puts "--------------"
  puts query_to_graph_json(query) 
  query_to_graph_json(query) 
end

# This is supposed to grab nodes and edges, but it never gets edges.
# It's originally from a conversation at the neo4j.rb site 

  def query_to_graph_json(query)
    nodes = {}
    edges = {}

    add_datum = Proc.new do |datum|
      case datum
      when Neo4j::ActiveNode, Neo4j::Server::CypherNode
        nodes[datum.neo_id] = {
        id: datum.neo_id,
        properties: datum.props #was attributes, but kept saying that wasn't a method
        }
      when Neo4j::ActiveRel, Neo4j::Server::CypherRelationship
        edges[[datum.start_node.neo_id, datum.end_node.neo_id]] = {
        source: datum.start_node.neo_id,
        target: datum.end_node.neo_id,
        type: datum.rel_type,
        properties: datum.props
        }
      else
        raise "Invalid value found: #{datum.inspect}"
      end
    end

    query.each do |row|
      row.to_a.each do |datum|
        if datum.is_a?(Array)
          datum.each {|d| add_datum.call(d) }
        else
          add_datum.call(datum)
        end
      end
    end

    {
      nodes: nodes.values,
      edges: edges.values
    }.to_json
  end

I'll get...

{
  "nodes": [
    {
      "id": 597,
      "properties": {
        "name": "John",
        "type": "Person"
      }
    },
    {
      "id": 127,
      "properties": {
        "name": "Chris",
        "type": "Person"
      }
    },
    {
      "id": 129,
      "properties": {
        "name": "Suzie",
        "type": "Person"
      }
    },
],
  "edges": [

  ]
}

The problem being that I need the edges.

If I run...

get '/followers' do
  content_type :json
  neo = Neography::Rest.new("http://localhost:7474")
  cypher = "MATCH (a)--(b)--(c) RETURN ID(a),a.name,ID(b),b.name,ID(c),c.name LIMIT 30"
  puts neo.execute_query(cypher).to_json
end

I'll get a table of paths. But it's not formatted in the way I need--and I have no idea how it might get from this format to the GraphJSON format.

{
  "columns": [
    "ID(a)",
    "a.name",
    "ID(b)",
    "b.name",
    "ID(c)",
    "c.name"
  ],
  "data": [
    [
      597,
      "John",
      127,
      "Chris",
      129,
      "Suzie"
    ],
    [
      597,
      "John",
      6,
      "Adam",
      595,
      "Pee-Wee"
    ]
  ]
}

回答1:


I think that one problem that you're having is that, instead of matching two nodes and one relationship, you're matching three nodes and two relationships. Here's your MATCH:

MATCH (a)--(b)--(c)

It should be like:

MATCH (a)-[b]-(c)

In a MATCH clause the [] can be excluded and you can just do a raw -- (or --> or <--) which represents the relationship.

You probably want to be querying for one specific direction though. If you query bidirectionally you'll get the same relationship twice with the start and end nodes switched.

Using neo4j-core (which I biased towards as one of the maintainers ;)

nodes = []
rels = []
session.query('(source)-[rel]->(target)').pluck(:source, :rel, :target).each do |source, rel, target|
  nodes << source
  nodes << target
  rels << rel
end

{
  nodes: nodes,
  edges: rels
}.to_json

Also note that if you don't specify any labels your query might be slow, depending on the number of nodes). Depends on what you need ;)




回答2:


This Cypher query should return the edges array as per the example format:

MATCH (a)-[r]-(b)
WITH collect(
    {
        source: id(a),
        target: id(b),
        caption: type(r)
    }
) AS edges
RETURN edges

Running this against some sample data, the results look like this:

[
          {
            "source": 9456,
            "target": 9454,
            "caption": "LIKES"
          },
          {
            "source": 9456,
            "target": 9454,
            "caption": "LIKES"
          },
          {
            "source": 9456,
            "target": 9455,
            "caption": "LIKES"
          },
          {
            "source": 9454,
            "target": 9456,
            "caption": "LIKES"
          }
]


来源:https://stackoverflow.com/questions/35277838/from-neo4j-to-graphjson-with-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!