graph databases

Spring Boot and Spring Data

Continuing on from the previous article, I finally managed to get to Spring Data. In a way, this is just Spring JPA and looks like this:

@Configuration
@EnableAutoConfiguration
public class Application {

  public static void main(String[] args) {

    ConfigurableApplicationContext context = SpringApplication.run(Application.class);
    PersonRepository repository = context.getBean(PersonRepository.class);

    for (Person person : repository.findAll()) {
      System.out.println(person);
    }
    context.close();
  }
}

Although this looks similar to the Hibernate JPA previously, there are some significant changes. The first is the use of a Repository interface, PersonRepository. This has to descend from the Spring Data Repository interface, usually via another interface:

public interface PersonRepository extends CrudRepository<Person, Long> {
}

I’ve used CrudRepository, the most basic, and given it the class name of the POJO and the type of the unique identifier, which is a Long. Notice that you have to use the class equivalent of the primitive type. You don’t need to define anything else if you don’t want to; CrudRepository defines the basic functions as standard:

public interface CrudRepository<T extends Object, ID extends Serializable> extends Repository<T, ID> {
  public <S extends T> S save(S s);
  public <S extends T> Iterable<S> save(Iterable<S> itrbl);
  public T findOne(ID id);
  public boolean exists(ID id);
  public Iterable<T> findAll();
  public Iterable<T> findAll(Iterable<ID> itrbl);
  public long count();
  public void delete(ID id);
  public void delete(T t);
  public void delete(Iterable<? extends T> itrbl);
  public void deleteAll();
}

As before, the field mappings have to be put directly in the POJO using annotations. Something to remember is that with Spring JPA you have to make sure the column names are lower case.

Next you have to configure the connection properties. This goes in a file called “application.properties”, the default:

spring.datasource.url=jdbc:jtds:sqlserver://localhost:1433/A_DB
spring.datasource.username=aaron
spring.datasource.password=********
spring.datasource.driverClassName=net.sourceforge.jtds.jdbc.Driver

You may have noticed in the application definition is the use of the EnableAutoConfiguration annotation. This is from Spring Boot, which is our next subject.

Spring Boot

So far, behind the scenes, so to speak, we’ve been adding dependencies into the Maven POM file with some abandon, but, to get Spring Boot working, we have to remove them. Why use Spring Boot? I can’t really give you a straight answer, other than to say there are a lot fewer problems when using Spring Data. Take my word for it.

As described in the starting guide instruction on the Spring Boot web site, you have to add the following:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.1.8.RELEASE</version>
</parent>

… which goes in the project root. Next you want something to tell Spring Boot to pull in the Data JPA layer:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

… which goes in the dependencies. Clear everything else out of the dependencies: this will cause all kinds of errors in the code, but resist the temptation to fix this by pulling in the dependencies. You will regret it if you don’t. Do a build (or clean and build), you’ll find that new dependencies have been pulled in via the parent and you don’t have to define anything. This also sorts out any import errors.

The dependencies that do have to be put in are specific to this particular project and that is the JTDS driver for MS SQL Server:

<dependency>
  <groupId>net.sourceforge.jtds</groupId>
  <artifactId>jtds</artifactId>
  <version>1.2</version>
</dependency>

You will be surprised to find that all this works straight away with no other configuration.

Spring Boot Web Services

So far, we’ve just been playing with the data, outputting the results to the console. To get it to do something useful, we need to introduce web services, in the form of a REST interface. This is what Spring Boot is really used for and this introduces the idea of Micro Services.

Micro Services are an architectural concept that takes componentisation to a system level. A system is divided up into sub-systems, each of which is considered a system in its own right, with its own security, metrics etc., and even its own built-in web server. These components are connected together using REST web services, so the definitions of these interfaces become very important. The implementation of one sub-system, or Micro Service, is independent of others, providing the interfaces are adhered to, so you can have one service built using .Net and another in Java, yet another in Node.js and JavaScript. There are lots of technologies being introduced and maturing that support, take advantage of or are being taken advantage of by this concept, in particular Docker, for deployment, Spring Boot and Drop Wizard for Java development.

Now we’ll add a REST service to the previous data project. First, we remove the data code from the Application class:

  public static void main(String[] args) {
    SpringApplication.run(Application.class);
  }

Exactly as before, just without the data code. This has been moved to the web service class, MyController:

@RestController
public class PersonController {

  @Autowired
  private PersonRepository repository;

  @RequestMapping("/")
  public String index() {
    StringBuilder sb = new StringBuilder();
    sb.append("<!DOCTYPE html>").append("<html lang='en'>");
    sb.append("<head>").append("<meta charset='UTF-8'>");
    sb.append("<title>Something, something</title>").append("</head>");
    sb.append("<body>");
    sb.append("<table>");
    for (Person person : repository.findAll()) {
      sb.append("<tr>");
      sb.append("<td>").append(person.getId()).append("</td>");
      sb.append("<td>").append(person.getFirstName()).append("</td>");
      sb.append("<td>").append(person.getLastName()).append("</td>");
      sb.append("</tr>");
    }
    sb.append("</table>");

    sb.append("</body>");
    sb.append("</html>");
    return sb.toString();
  }
}

The class is designated a RestController, which tells Spring that it’s the class that handles http requests as REST requests. The RequestMapping annotation tells it which path to respond to, in this case the root. I’m responding with a string at this point and creating a simple web page as the payload.

Notice that the repository is automatically created by annotating the declaration with @Autowired.

The POM has also been added to with Spring Boot dependencies, spring-boot-starter-web and spring-boot-starter-jetty:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

The former seems to be mostly used to enable the web services, but also to prevent Tomcat being used. Instead it used Jetty, which is simpler. The only other thing needed is to tell Maven that this is a Boot application, rather than a Java one:

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

That’s pretty much it. If you now run up the application, it will start Jetty on port 8080 and the response will be a web page with the Persons loaded from the database.

JSON

Instead of delivering an HTML page as the payload, we can deliver a JSON string. This is all built into Spring Boot and is just a case of altering the definition of the index function:

  @RequestMapping("/")
  public Person[] index() {
    List personList = new ArrayList();
    personList.addAll((Collection) repository.findAll());
    return personList.toArray(new Person[0]);
  }

findAll returns an Iterable, so this needs to be converted to an array via ArrayList. The array of JobType objects is coded to JSON and sent as the response automatically.

Introduction to Neo4j

Neo Technologies run little evening seminars to introduce their graph database technology and I took the liberty of attending one yesterday evening. You get a free book!

 

They’re based around the back of the Tate Modern, in an area which seems like an extension of Shoreditch with loads of start-ups and overpriced coffee.

It was a very interesting presentation, given by Rik Van Bruggen (Belgian), giving the background to the database and a really good demo using belgian beers as a dataset. Neo4j also has a community version that you can download as well as a free on-line course (with registration).

Rik also demonstrated a web site that visualises recommendations in Amazon.com, which is quite groovy.

The Graphs of Gaming and Recruitment

Yesterday evening, I went to a presentation on Graph Databases (specifically Neo4j, who were the organisers), hosted by Skills Matter.

First up was Nigel Small who talked about Zerograph, a new container/server for Neo4j.

Nigel gave a quick overview of Zerograph, highlighting it’s ability to host more than one database and the use of ZeroMQ (thus the name) to increase reliability and robustness. ZeroMQ is a message queue, which is a piece of software designed to buffer and schedule messages between two systems in a more controlled way than a direct connection. It also, in ZeroMQ’s case, allows for temporary disconnections, saving the messages to be processed when the connection is resumed. How this works in practise is another matter.

One of things emphasised throughout the talks was the speed with which Neo4j processes queries and returns results. Graph databases are designed to cope with information which is highly relational in nature, so something that in standard SQL would take seconds or even minutes with multiple joins, takes a fraction of that in a graph database.

Next up was Mark Wright to talk about the work at his company Stitched regarding the use of Neo4j in social networks for recruiting.

A quite amusing presentation, Mark illustrated the problems with existing social networks, such as Facebook and LinkedIn, and how “private” networks could be used to give more authentic results.

The last speaker was Yan Cui, from GamesSys, to talk about his experiences using Neo4j to model his company’s Freemium online game “Here Be Monsters“.

The game is resource based and can be incredibly complex and interrelated, so any small change in the underlying data can have considerable consequences. They’ve tried to make changes by rule-of-thumb, but this proved too unwieldy, slow and error-prone, so they’ve been modelling it with Neo4j and had much better results.

One of the things mentioned during the presentations was Cypher. Being interested in cryptography, I was a little baffled, but this turns out to be the Neo4j equivalent of SQL:

MATCH (n:Person)-[:KNOWS]->(m:Person) WHERE n.name="Alice"

Looks similar enough, although I can’t see why they didn’t call it Graph Query Language (GQL), which would be much more obvious.