Aerospike Engineering Blog, Technology, Product Update

Spring is a common framework used in Enterprise Java applications. Spring hides the complexity of building an Enterprise Java application; it offers numerous helpful modules which abstract the technology details away from the developer so they can concentrate on creating a solution to the business problem rather than burning cycles “fixing the plumbing”.

An increasing number of existing Enterprise Java applications need to access data sources available in the Big Data space. Spring Data offers a familiar and consistent way to access these data sources without having to train or retrain the whole development team in the new technology.

Why Aerospike?

While Aerospike is a modern NoSQL database of the key-value genre, it is much more than just a key-value store. Aerospike is all about “Speed at Scale”. What does this mean?

  • each operation on the database has a very low and predictable latency (speed), and
  • the number of requests per second – or throughput – scales massively, without an increase in latency (scale).

One of the features that sets Aerospike apart from other NoSQL databases is its high scalability through parallelism. An Aerospike Cluster scales linearly by having nodes added to it. Also, each Aerospike node efficiently and equitably uses machine resources so that all cores/CPUs, IRQs, RAM and Flash devices focus on even workload distribution and parallelism. The cluster is self-healing and zero-touch with automatic failover, rebalancing and continuous de-fragmentation without impacting throughput or latency.

Aerospike is optimal for any scenario where instantaneous, real-time data is needed, at scale. For instance:

  • storing user behaviour from a click/event stream
  • trading transactions (buy and sell orders)
  • Real-Time Bidding (RTB)
  • User profile store
  • Caching on a large scale
  • Huge web server session store for cross-channel sessions

Spring Data for Aerospike

Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store (see Spring Data).

Spring Data for Aerospike is an open source community project hosted under the Spring umbrella and sponsored by Aerospike. It provides a data layer to Aerospike that is familiar to Spring developers; it works in harmony with the full Spring suite, including Spring Boot and Spring MVC.

The Spring Data for Aerospike project provides integration with the Aerospike key-value database. Key functional areas of Spring Data for Aerospike include a POJO-centric model for interacting with an Aerospike Namespace and Set, and the ability to easily write a repository-style data access layer.

Features

Spring Data for Aerospike features the following:

  • Spring configuration support using Java-based @Configuration classes or an XML namespace for an AerospikeClient instance to access an Aerospike Cluster.
  • AerospikeTemplate helper class that increases productivity-performing Aerospike operations. This includes integrated object mapping between Records and POJOs.
  • Optimized query engine for handling multi-filter queries in the cluster.
  • Exception translation into Spring’s portable Data Access Exception hierarchy.
  • Feature-rich Object Mapping integrated with Spring’s Conversion Service.
  • Annotation-based mapping metadata but extensible to support other metadata formats.
  • Persistence and mapping lifecycle events.
  • Low-level mapping using the Aerospike Client API.
  • Java based Query, Criteria, and Update DSLs.
  • Automatic implementation of Repository interfaces including support for custom finder methods.
  • QueryDSL integration to support type-safe queries.
  • Cross-store persistence – support for JPA Entities with fields transparently persisted/retrieved using Aerospike.
  • MapReduce integration.

Using Spring Data for Aerospike

Getting the code

Spring Data for Aerospike is an open source community Spring project. You can clone, download or contribute to this GitHub repository.

A complete example

A complete Spring Boot web application example is available on GitHub here. This example uses Spring MVC, Spring Security and Spring Data for Aerospike.

Some quick examples

The following examples are code snippets from the complete example described above.

Configuration

Below is an example of a “Java” configuration that defines an AerospikeClient bean used to access the Aerospike cluster, and an AerospikeTemplate bean which can be used like any other Spring Data template.

@Configuration
@EnableAerospikeRepositories(basePackageClasses = ContactRepository.class)
public class TestConfigPerson {
    public @Bean(destroyMethod = "close") AerospikeClient aerospikeClient() {
        
        ClientPolicy policy = new ClientPolicy();
        policy.failIfNotConnected = true;
        policy.timeout = 2000;
        
        return new AerospikeClient(policy, “127.0.0.1”, 3000);
    }
    
    public @Bean AerospikeTemplate aerospikeTemplate() {
        return new AerospikeTemplate(aerospikeClient(), "test");
    }
}

Entity Class

This is a simple “Contact” entity POJO. Note the @Field annotation that maps the field “shippingAddresses” to the Bin “ShipAddresses”

public class Person extends Contact implements Comparable<Person> {
    public enum Sex {
        MALE, FEMALE;
    }
    private String firstname;
    private HashMap myHashMap;
    private String lastname;
    private String email;
    private Integer age;
    @SuppressWarnings("unused") private Sex sex;
    Date createdAt;
    List<String> skills;
    private Address address;
    @Field(value="ShipAddresses")
    private Set<Address> shippingAddresses;
    User creator;
    Credentials credentials;
}

Repository Definition

This is an example of a repository to store “Person” objects. Note that it is an interface extending AerospikeRepository. Spring does all the work in producing a functional repository to store and retrieve “Person” objects. The query builder mechanism built into the Spring Data repository infrastructure is useful for building constraining queries over entities of the repository. The mechanism strips the prefixes find…By, read…By, query…By, count…By, and get…By from the method and starts parsing the rest. The introducing clause can contain further expressions such as a Distinct to set a distinct flag on the query to be created. However, the first “By” acts as a delimiter to indicate the start of the actual criteria.

public interface PersonRepository extends AerospikeRepository<Person, String> {

    List<Person> findByLastname(String lastname);
    List<Person> findByLastnameStartsWith(String prefix);
    List<Person> findByLastnameEndsWith(String postfix);
    List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
    List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
    List<Person> findByFirstnameLike(String firstname);
    List<Person> findByFirstnameLikeOrderByLastnameAsc(String firstname, Sort sort);
    List<Person> findByAgeLessThan(int age, Sort sort);
    List<Person> findByFirstnameIn(String... firstnames);
    List<Person> findByFirstnameNotIn(Collection<String> firstnames);
    List<Person> findByFirstnameAndLastname(String firstname, String lastname);
    List<Person> findByAgeBetween(int from, int to);
    Person findByShippingAddresses(Address address);
    List<Person> findByAddress(Address address);
    List<Person> findByAddressZipCode(String zipCode);
    List<Person> findByLastnameLikeAndAgeBetween(String lastname, int from, int to);
    List<Person> findByAgeOrLastnameLikeAndFirstnameLike(int age, String lastname, String firstname);
    List<Person> findBySex(Sex sex);
    List<Person> findBySex(Sex sex, Pageable pageable);
    List<Person> findByCreator(User user);
    List<Person> findByCreatedAtLessThan(Date date);
    List<Person> findByCreatedAtGreaterThan(Date date);
    List<Person> findByCreatedAtBefore(Date date);
    List<Person> findByCreatedAtAfter(Date date);
    List<Person> findByLastnameNot(String lastname);
    List<Person> findByCredentials(Credentials credentials);
    List<Person> findCustomerByAgeBetween(Integer from, Integer to);
    List<Person> findPersonByFirstname(String firstname);
    long countByLastname(String lastname);
    int countByFirstname(String firstname);
    long someCountQuery(String lastname);
    List<Person> findByFirstnameIgnoreCase(String firstName);
    List<Person> findByFirstnameNotIgnoreCase(String firstName);
    List<Person> findByFirstnameStartingWithIgnoreCase(String firstName);
    List<Person> findByFirstnameEndingWithIgnoreCase(String firstName);
    List<Person> findByFirstnameContainingIgnoreCase(String firstName);
    Slice<Person> findByAgeGreaterThan(int age, Pageable pageable);
    List<Person> deleteByLastname(String lastname);
    Long deletePersonByLastname(String lastname);
    Page<Person> findByAddressIn(List<Address> address, Pageable page);
    List<Person> findTop3ByLastnameStartingWith(String lastname);
    Page<Person> findTop3ByLastnameStartingWith(String lastname, Pageable pageRequest);
    List<Person> findByFirstname(String string);
    List<Person> findByFirstnameAndAge(String string, int i);
    Iterable<Person> findByAgeBetweenAndLastname(int from, int to, String lastname);
    List<Person> findByFirstnameStartsWith(String string);
    Iterable<Person> findByAgeBetweenOrderByLastname(int i, int j);
}

You can see that your query options are numerous.

Using a repository

Some code snippets that use the repository are listed below.

Index creation
repository.createIndex(Person.class,”last_name_index”, “lastname”, IndexType.STRING);
repository.createIndex(Person.class,”first_name_index”, “firstname”, IndexType.STRING);

Find all
List<Person> result = (List<Person>) repository.findAll(Arrays.asList(dave.id,boyd.id));

Find by last name
List<Person> result = repository.findByLastname(“Beauford”);

Delete by ID
repository.delete(dave.getId().toString());

Find by  first name and age
List<Person> result = repository.findByFirstnameAndAge(“Leroi”,25);

Find by first name starts with D
List<Person> result = repository.findByFirstnameStartsWith(“D”);

Find by age range and last name
Iterable<Person> it = repository.findByAgeBetweenAndLastname(40, 45,”Matthews”);

Other examples

Other Spring Boot web application examples written by @carosys are available on GitHub. They include:

  • This very basic example.
  • This complete Spring Boot web application, which uses Aerospike as the persistence layer. This demo uses Spring Boot, Thymeleaf, Spring MVC, Tomcat and Aerospike.

Conclusion

Spring Data for Aerospike allows developers to access the data stored in Aerospike with the familiar Spring Data interface without forcing them to learn a new API or paradigm. Spring Data’s rich query facility is supported by “in-server” filtering and requires no extra work from  enterprise developers.

As always, we need your help and input to continue to improve and enhance your experience on Aerospike. Feel free to contribute your feedback, ideas and questions to our user forum, file Github issues or create a pull request for the next great feature you’d like to contribute to the Aerospike user community!

About Author

    Aerospike Engineering

    All posts by this author