Work with DSE Graph in your web applications part (2/2) : Visualization | Apache Cassandra and DataStax Enterprise - DataStax Academy
Skip to main content
  • Learn
    • Learning Paths
    • Online Courses
    • Short Courses
    • Ad-hoc Learning
    • Browse by Topic
    • Classroom Training
    • Public Training
    • Certifications
  • Distributed Data Show
  • Success Segments
  • Developer Blog
  • Meet The Contributors
  • Community
    • DataStax Community
    • Events
    • DataStax Developer Day
    • Support Blog
  • DATASTAX.COM HOME
  • ACADEMY HOME
  • DOCS

Download Datastax

SHARE

Share This Page


Choose the social network you'd like to share with:

Login or Sign Up
Home » Developer Blog » Work with DSE Graph in your web applications part (2/2) : Visualization

Work with DSE Graph in your web applications part (2/2) : Visualization

Aug 28, 2018
Cedrick Lunven
Teaser: 

This post is the second and last part of a series digging into integration of Graph Databases with web applications. In Part 1, we created a data access object (DAO) to implement basic CRUD operations for both vertices and edges. Here, we will have a closer look at graph visualization in user interfaces. One of the coolest features of graph is the capability to browse the data to identiy patterns and extract information from relationships. DataStax Studio provides with great visuat rendering but, why not having the same visualization in your own applications?

Topics: 
DataStax Enterprise
Graph
Gremlin
Reference Application
Drivers
Java

What's the idea ?

For an overview of the solution, please look at the diagram on the left. When it comes to architecture, a picture is worth a thousand words.

Here are the steps and components we will review.

  1. User POSTs a Gremlin query to the REST API
  2. The query is converted from String to GraphStatementand executed at the DAO level
  3. Driver returns a GraphResultSet 
  4. Mapper translates the result set to web beans with the structure expected by the front end
  5. Graph is rendered using the Javascript library VisJs
  6. Specialisation and customisation can be done in both Mapper and CSS.

Implementation

Rendering charts in user interface

When you need to deal with rich user interfaces, Javascript is a no brainer, alternative solutions like Flash or applets are long since obsolete. You can find dozens of frameworks to render charts with JS. I have used a couple myself in the past  and am very keen on D3js and HighCharts. You can see and run my experiments on github if interested using the following :

git clone https://github.com/clun/sandboxes.git
cd clu-dataviz
mvn jetty:run

Then accessing http://localhost:8181you should get something like :

But when it comes to rendering graphs and networks, I've found nothing better than VisJS (which is also used in DataStax studio). It provides tons of options to customize exactly as you wish. It is also aware of events coming from users (such as mouse clicks), allowing you to implement cool features like interactive graph browsing (c.f. Datastax Studio). This framework expects JSON data provided with a specific structure such as this:

var nodes = new vis.DataSet([
    {id: 1, label: 'Node 1'},
    {id: 2, label: 'Node 2'},
    {id: 3, label: 'Node 3'},
    {id: 4, label: 'Node 4'},
    {id: 5, label: 'Node 5'}
  ]);

  // create an array with edges
  var edges = new vis.DataSet([
    {from: 1, to: 3},
    {from: 1, to: 2},
    {from: 2, to: 4},
    {from: 2, to: 5},
    {from: 3, to: 3}
  ]);

Creating a REST API

For the backend our objective is to create a REST API accepting a Gremlin Query as input and generating the JSON Format expected by VisJS. The first thing to do is to create plain old java objects (POJOs) to reflect the Json structure. Here is a UML representation generated by ObjectAid available for Eclipse.

We chose to use SpringMVC included in SpringBoot (what else ?). The DAO generated in first blogpost can be reused and injected into the REST resources.

@RestController
@RequestMapping("/api/v1/graphs")
public class GraphResource {
   
    @Autowired
    protected GraphDao graphDao;

    @RequestMapping(value = "/{graphName}/{gremlinQuery}", method = GET,  produces = APPLICATION_JSON_VALUE)
    public ResponseEntity<VizJsGraph> executeGremlinQuery(
            @PathVariable(value = "graphName") String graphName, 
            @PathVariable(value = "gremlinQuery") String gremlinQuery) {
        return new ResponseEntity<VizJsGraph>(
                              graphDao.executeGremlinQuery(graphName, gremlinQuery, true), 
                              HttpStatus.ACCEPTED);
    }

}

Note : executeGremlinQuery has not been defined yet, we will do this in the next section.

Implementing the DAO 

As we have seen in the previous post, the DataStax Java driver accepts Gremlin queries as raw Strings (how convenient). The driver will convert each query into aGraphStatementand execute against DSE Graph.

This is what it looks like :

public VizJsGraph executeGremlinQuery(String graphName, String gremlinQuery, boolean populateEdges) {
  Assert.hasText(graphName, "'graphName' is required here");
  Assert.hasText(gremlinQuery, "'gremlinQuery' is required here");
  LOGGER.info("Executing query {} on graph {}", gremlinQuery, graphName);
        
  // QUERY FOR VERTICES
  GraphStatement graphStatement = new SimpleGraphStatement(gremlinQuery).setGraphName(graphName);
  GraphResultSet gras = dseSession.executeGraph(graphStatement);
        
  // MAPPING AS VERTICES IN UI
  VizJsGraph vizGraph    = new VizJsGraph();
  List<Object> vertexIds = new ArrayList<>();
  for (GraphNode gn : gras) {
     if (populateEdges && gn.isVertex()) vertexIds.add(gn.asVertex().getId());
     populateGraphVizJs(gn, vizGraph);
   }
   
   // SOMETHING IS MISSING 
   //--> HERE <--
   return vizGraph;
}

This works quite well, but there is more. Have you ever try to execute the  g.V()queryin DataStax Studio ? It will display the whole graph (both vertices and edges)...but it shouldn't. The gremlin query returns Vertices (V for Vertices) and only the Vertices so, what is the trick for how to collect edges as well?

The way to retrieve edges between vertices in Gremlin is described in the following documentation. If we want to display a nice graph with the edges in the user interface, we need to fire an extra query :g.V(ids.toArray()).outE().where(inV().id().is(within(ids)))where ids are the unique identifier of your vertices. 

Here is the code. I inlined the code a bit, YOU are an expert now after all.

// Add Edges to the results
dseSession.executeGraph(new SimpleGraphStatement("g.V(ids.toArray()).outE().where(inV().id().is(within(ids)))")
                              .set("ids", vertexIds)
                              .setGraphName(graphName))
          .all()
          .stream()
          .forEach(gn -> populateGraphVizJs(gn, vizGraph));

Populating the visualization via Mappers

Last missing part to have our sample running is mapping of GraphResultSetto VizJsGraph. Straightforward, this is what it looks like:

private void populateGraphVizJs(GraphNode gn, VizJsGraph graph) {
  if (gn.isVertex()) {
     Vertex v = gn.asVertex();
     graph.addVertex(new GraphVertex().id(v.getId().toString()).label(v.getLabel()););
  } else if (gn.isEdge()) {
    Edge e = gn.asEdge();
     graph.addEdge(new GraphEdge(e.getOutV().toString(), e.getInV().toString()));
  }
}

As usual, the full working application can be found on github please have a look and run a sample command. And the result is ....

This....is... a bit disapointing, isn't it? After all we have done it is still quite ugly, and its pretty difficult to extract value from that representation. You cannot give that to the business can you?

Don't worry, we are not finished yet.

Customisation (Mappers, part 2)

First, update the mapper to select which properties will be displayed in the graph, and how they will be displayed. You can use the label of the vertex or any business condition to filter. Then, define which group each Vertex will be part of. The concept of a group is used by the VisJs library in order to apply specific CSS styles for rendering. This is what it looks like in our example :

Update the Mapper :

if ("video".equals(v.getLabel())) {
  VertexProperty videoName = v.getProperty("name");
  if (videoName != null) {
    gv.setLabel(videoName.getValue().asString());
  }
} else if ("tag".equals(v.getLabel())) {
  VertexProperty videoName = v.getProperty("name");
  if (videoName != null) {
    gv.setLabel(videoName.getValue().asString());
  }   
} else if ("user".equals(v.getLabel())) {
  VertexProperty email = v.getProperty("email");
  if (email != null) {
    gv.setLabel(email.getValue().asString());
  } 
}
// Important
gv.setGroup(v.getLabel());

Update Javascript Function & apply CSS styles :

function executeGremlin(graphName) {
		$.get('api/v1/graphs/' + graphName + '/' + document.getElementById('query').value,
		  function(graph) {
			var container = document.getElementById('mynetwork');
			var data      = { nodes: graph.nodes, edges: graph.edges };
			var options = {
			        groups: {
			          video: {
			            shape: 'icon',
			            icon: {
			              face: 'FontAwesome',
			              code: '\uf03d',
			              size: 50,
			              color: '#57169a'
			            }
			          },
			          user: {
			            shape: 'icon',
			            icon: {
			              face: 'FontAwesome',
			              code: '\uf007',
			              size: 50,
			              color: '#0890D0'
			            }
			          },
			          tag: {
				        shape: 'icon',
				        icon: {
				         face: 'FontAwesome',
				          code: '\uf02b',
				              size: 50,
				              color: '#00ab8b'
				            }
				          }
			        }
			      };
			var network = new vis.Network(container, data, options);
		});
	}

If now we execute the same query we get:

Isn't that cool?

Conclusion and takeaways 

In this series of two articles, we have seen how simple it was to connect, interact and render data coming from graph databases. From this template and the code provided on github we expect you to build AWESOME applications.

If you want to improve with Gremlin Language or Graph data modeling please consider taking the FREE courses DS330 and Gremlin Recipes available here on DataStax Academy.

Happy coding!

Recommended Content

Developer Blog
Gathering the Apache Cassandra™ Tribe at DataStax Accelerate
Distributed Data Show
Distributed Data Show Episode 70: Adding a Graph Database to Legacy Applications
Distributed Data Show
Distributed Data Show Episode 66: Graph Day Interview with Dr. Gosnell
Developer Blog
Graph Day 2018 Recap
Developer Blog
Work with DSE Graph in your web applications part (2/2) : Visualization
Developer Blog
Work with DSE Graph in your web applications part (1/2) : CRUD Operations
DS332: DataStax Enterprise 6 Graph Analytics
  • RESOURCES
  • Products
  • Services
  • Events
  • Customers
  • COMPANY
  • Why DataStax
  • About
  • Careers
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Contact

DataStax

DataStax Enterprise is powered by the best distribution of Apache Cassandra™.

©2019 DataStax, All rights reserved. DataStax, Titan, and TitanDB are registered trademark of DataStax, Inc. and its subsidiaries in the United States and/or other countries.

Apache, Apache Cassandra, Cassandra, Apache Tomcat, Tomcat, Apache Lucene, Lucene, Apache Solr, Apache Hadoop, Hadoop, Apache Spark, Spark, Apache TinkerPop, TinkerPop, Apache Kafka and Kafka are either registered trademarks or trademarks of the Apache Software Foundation or its subsidiaries in Canada, the United States and/or other countries.

Privacy Policy Terms of Use

Feedback

You need to login or register to leave feedback.

CREATE NEW ACCOUNT
feedback