Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Cassitory: Redundancy Tables Within Cassandra

DZone 's Guide to

Cassitory: Redundancy Tables Within Cassandra

Learn more about Cassitory and redundancy tables within Cassandra.

· Database Zone ·
Free Resource

After working with Cassandra for a while and not having Apache Spark as a viable option, running different queries may become quite a challenge.

In the eventual case where you want to execute a query that would not be possible with the current table structure, Cassandra recommends having redundancy tables because storage is cheaper than memory.

Image title

In the pursuit of this goal, you will end up writing a lot of code just to ensure that you persist to both tables, and let’s not even think about whether you have to bring a third table into the equation.

So I decided to tackle this problem by writing a library that gives you a Repository capable of persisting an entity to multiple tables in a transactional way. Meaning that if one write operation fails, then all will be rollback.

Did I forget to mention that they all run in an async way? Awesome! Let's get started.

How Does It Work?

Cassitory has a big requirement in order to work, at least for now, which is that you have to write your Cassandra entities mapped using Cassandra annotations using Cassandra Object Mapper library

This image will illustrate the situations that you will end up writing:

Image title

As you can see, the Cassandra entities have been annotated with Cassandra annotations.

Cassitory relies on object mapper at the moment in your Cassandra entities.

Once you have all the Cassandra entities ready to use, the next step is to create an entity that has all the values that would be used to create the Cassandra entities for you and persist it.

Image title

As you can see, the concept is very simple. There is one entity that holds all the values that you need and two annotations that do all the transformation magic from this entity to the Cassandra entities.

CassandraEntity annotation: defines which Cassandra entities will be persisted. It also provides an optional destinationPackage attribute where you can specify the package of the generated code, otherwise, it will generate the code in the same package of the annotated Cassitory entity.

@CassitoryEntity(target={UserByName.class, User.class}, destinationPackage="repositories")
class UserDto {}

Mapping annotation: How to map the field to each Cassandra entity. At that point, you can annotate your entities in many ways eg.

//Map the field to the classes User and Username and populate in 
//each of them the field name.
@Mapping(target={User.class, UserByName.class}, field="name")
private String name;
//Because the field name in this entity is the same than the ones in 
//the Cassandra entities you can omit the field value.
@Mapping(target={User.class, UserByName.class})
private String name;
//In the case where you have different field names in your Cassandra 
//entities you can do this
@Mapping(target={User.class}, field="name" )
@Mapping(target={UserByName.class}, field="fullname")
private String name;
//And last, you can combine both approaches
@Mapping(target={User.class}, field="name" )
@Mapping(target={UserByName.class, UserByAge.class}, field="fullname")
private String name;

Cassitory will generate a derived BaseRepository class following the convention of:

<name of the cassitory entity class>BaseRepository

and you can use it just by creating an instance of it:

MappingManager mappingManager;
UserDtoBaseRespository repository = new UserDtoBaseRespository(mappingManager);

Conclusion

Cassitory uses annotation processing to generate code for you. The generated code does NOT use reflection. It also provides a few advantages, like:

  • Catches any mistake in the config. at compile time
  • Easy to add a new table or remove
  • Easy to integrate with your DI framework
  • Lightweight
  • Mapping annotation provides a lot of flexibility in order to simplify your config or have more complex scenarios
  • Use of transactions for the persistence and, therefore, the rollback of all the operations
  • Support for different numbers of fields between Cassandra entities

GitHub: https://github.com/caelcs/cassitory

Topics:
cassandra ,redundancy ,repository ,transactional ,apache cassandra ,java8 ,annotation processors

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}