Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Voxxed Days Bucharest 2023: NoSQL Endgame

Voxxed Days Bucharest 2023: NoSQL Endgame

The amount of data collected by applications nowadays is growing at a scary pace. Many of them need to handle billions of users generating and consuming data at an incredible speed. Maybe you are wondering how to create an application like this? What is required? What works best for your project?

In this session, we'll compare popular Java and JVM persistence frameworks for NoSQL databases.
We are going to look at Spring Data, Micronaut Data, Quarkus/Panache, Jakarta NoSQL and GORM (which indeed is actually a Marvel character in the Conan Universe ;-)
How do they compare, what are the strengths, weaknesses, differences and similarities? We'll show each of them with a selection of different NoSQL database systems (Key-Value, Document, Column, Graph) to learn how they take specific features and powers of a particular NoSQL type into consideration and provide support for.

Will there be a clear winner in the end, or maybe it depends on the particular DB type and use case and you might need more than one, with different strengths, just like the Avengers...?

Werner Keil

April 17, 2023
Tweet

More Decks by Werner Keil

Other Decks in Technology

Transcript

  1. Werner Keil Jakarta EE Specification Committee Member Let’s meet @otaviojava

    @wernerkeil Otávio Santana Distinguished Software Engineer, Zup Innovation
  2. What are these challenges? @otaviojava @wernerkeil • Agile development process

    • High performance and availability • Manage huge data volumes
  3. Advantages of NoSQL @otaviojava @wernerkeil • Handles large volumes of

    data at high-speed • Stores unstructured, semi-structured, or structured data • Easy updates to schemas and fields • Developer-friendly • Takes advantage of the cloud to deliver zero downtime
  4. Why this talk Tons of persistence frameworks Which one performs

    best for your case? JVM can cope with heavy loads Would normally take ages to compare
  5. Column-Oriented Apollo Aphrodite Ares Kratos Duty Duty Duty Dead Gods

    Love, happy Sun War 13 Color weapon Sword Row-key Columns HBase Scylla SimpleDB Cassandra DynamoDB Clouddata
  6. Document stores { "name":"Diana", "duty":[ "Hunt", "Moon", "Nature" ], "siblings":{

    "Apollo":"brother" } } ApacheCouchDB MongoDB Couchbase
  7. Graph databases Apollo Ares Kratos was killed by was killed

    by killed killed Neo4j InfoGrid Sones HyperGraphDB
  8. Multi-Model 01 02 03 04 OrientDB (graph, document) Couchbase (key

    value, document) Elasticsearch (document, graph) ArangoDB (document, graph, key-value)
  9. SQL vs NoSQL SQL KEY-VALUE COLUMN DOCUMENTS GRAPH Table Bucket

    Column family Collection Row Key/value pair Column Documents Vertex Column Key/value pair Key/value pair Vertex and Edge property Relationship Link Edge
  10. BASE vs ACID • Basically Available • Soft state •

    Eventual consistency • Atomicity • Consistency • Isolation • Durability
  11. CAP

  12. Relational Application NoSQL Application Logic Tier Logic Tier DAO DAO

    JPA JPA JPA JPA JDBC JDBC JDBC JDBC Data Tier API API API Data Tier
  13. JPA problem for NoSQL 01 02 03 04 05 06

    Saves Async Async Callback Time to Live (TTL) Consistency Level SQL based Diversity in NoSQL
  14. Annotated Entities 01 02 03 Mapped Superclass Entity Column @Entity("god")

    public class God { @Column private String name; @Column private long age; @Column private Set<String> powers; }
  15. Template God artemis = ...; DocumentTemplate template = … template.insert(artemis);

    template.update(artemis); DocumentQuery query = ... List<God> gods = template.select(query);
  16. Repository @MongoRepository interface BookRepository extends CrudRepository<Book, ObjectId> { Book find(String

    title); } Or @MongoRepository public abstract class AbstractBookRepository implements CrudRepository<Book, ObjectId> { public abstract List<Book> findByTitle(String title); }
  17. Entity @MappedEntity public class Book { @Id @GeneratedValue private ObjectId

    id; private String title; private int pages; public Book(String title, int pages) { this.title = title; this.pages = pages; } // ... }
  18. Query by Text @MongoFindQuery(filter = "{title:{$regex: :t}}", sort = "{title:

    1}") List<Book> customFind(String t); @MongoAggregateQuery("[{$match: {name:{$regex: :t}}}, {$sort: {name: 1}}, {$project: {name: 1}}]") List<Person> customAggregate(String t); @MongoUpdateQuery(filter = "{title:{$regex: :t}}", update = "{$set:{name: 'tom'}}") List<Book> customUpdate(String t); @MongoDeleteQuery(filter = "{title:{$regex: :t}}", collation = "{locale:'en_US', numericOrdering:true}") void customDelete(String t);
  19. Entity @Entity class User { ObjectId id String emailAddress String

    password String fullname Date dateCreated Date lastUpdated static constraints = { emailAddress email: true password nullable: true fullname blank: false } }}
  20. @Document(collection = "gods") public class God { … } interface

    GodRepository extends MongoRepository<God, String> { … } What about the Controller? <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> spring.data.mongodb.database=mythology spring.data.mongodb.port=27017 Logistics Domain
  21. MovieEntity MovieRepository PersonEntity Roles … Other reactive dependencies … <dependency>

    <groupId>org.neo4j.springframework.data</groupId> <artifactId>spring-data-neo4j-rx-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> org.neo4j.driver.uri=bolt://localhost:7687 org.neo4j.driver.authentication.username=neo4j org.neo4j.driver.authentication.password=secret Logistics Domain
  22. Entities @Node("Person") public class PersonEntity { @Id private final String

    name; private final Integer born; } @Node("Movie") public class MovieEntity { @Id private final String title; @Property("tagline") private final String description; @Relationship(type = "ACTED_IN", direction = INCOMING) private Map<PersonEntity, Roles> actorsAndRoles = new HashMap<>(); @Relationship(type = "DIRECTED", direction = INCOMING) private List<PersonEntity> directors = new ArrayList<>(); }
  23. Entity public class Person extends PanacheMongoEntity { public String name;

    public LocalDate birthDate; public Status status; // return name as uppercase in the model public String getName(){ return name.toUpperCase(); } // store all names in lowercase in the DB public void setName(String name){ this.name = name.toLowerCase(); } }
  24. Repository @ApplicationScoped public class PersonRepository implements PanacheMongoRepository<Person> { // put

    your custom logic here as instance methods public Person findByName(String name){ return find("name", name).firstResult(); } public List<Person> findAlive(){ return list("status", Status.ALIVE); } public void deleteLoics(){ delete("name", "Loïc"); } }
  25. Motivation BaseDocument baseDocument = new BaseDocument(); baseDocument.addAttribute(name, value); Document document

    = new Document(); document.append(name, value); JsonObject jsonObject = JsonObject.create(); jsonObject.put(name, value); ODocument document = new ODocument(“collection”); document.field(name, value);
  26. Make NoSQL easier @Inject Template template; … template.insert(book); List<Book> books

    = template.select(Book.class) .where("title").eq("Effective Java").list();
  27. Entity @Entity public class Person{ @Id private String id; @Column

    private String name; @Column private String city; } @Entity public record Book(@Id String id, @Column("title") String title, @Column("edition") int edition){}
  28. Entity @Entity public class Person{ @Id private String id; @Column

    private String name; @Column private String city; } key value key key key value value value Column Family Graph Document Key Value
  29. Template @Inject Template template; ... Car ferrari = template.insert(ferrari); Optional<Car>

    car = template.find(Car.class, 1L); List<Car> cars = template.select(Car.class).where("city").eq("Rome").result(); template.delete(Car.class).where("id").eq(1L).execute(); Optional<Car> result = template.singleResult("select * from Car where id = 1");
  30. Repository @Repository public interface CarRepository extends CrudRepository<Car, Long> { List<Car>

    findByType(CarType type); Optional<Car> findByName(String name); }
  31. Diversity @Entity("god") public class God { @Column private String name;

    @UDT("weapon") @Column private Weapon weapon; } @Repository interface GodRepository extends CassandraRepository<God, String> { @CQL("select * from God where name = ?") List<God> findByName(String name); }
  32. Repository with Queries @Repository interface PersonRepository extends CrudRepository<Person, Long> {

    @Query("select * from Person") Optional<Person> findByQuery(); @Query("select * from Person where id = @id") Optional<Person> findByQuery(@Param("id") String id); }
  33. Conclusions Switching between different NoSQL vendors not so easy ❌

    Micronaut Data still supports very few NoSQL databases ❌ Still in Progress ❌ Often faster with a lower footprint and polyglot language support for Java, Kotlin and Groovy ✅
  34. Conclusions Provides a cleaner and more readable DAO implementation ✅

    Works with Grails, Micronaut or Spring Boot, polyglot language support for Java and Groovy ✅ Removes a lot of boiler-plate code ✅ Only 3 to 4 of the most popular NoSQL databases are supported out of the box, others require more effort or won’t work yet ❌
  35. Conclusions Provides a cleaner and more readable DAO implementation ✅

    Loosely coupled code makes switching between different NoSQL vendors just a matter of configuration ✅ Removes a lot of boiler-plate code ✅ Only a few popular NoSQL databases are supported out of the box at this moment ❌
  36. Conclusions Switching between different NoSQL vendors not so easy ❌

    Quarkus / Panache still supports very few NoSQL databases ❌ Removes a lot of boiler-plate code ✅ Can be faster with native GraalVM option Polyglot language support for Java or Kotlin ✅
  37. Conclusions Still in Progress ❌ Supports a huge number of

    NoSQL database systems ✅ Loosely coupled code makes switching between different NoSQL vendors just a matter of configuration ✅ Removes boiler-plate code and provides a cleaner, more readable DAO ✅
  38. ▪ GitHub repositories ▪ https://github.com/JNOSQL/nosql-endgame ▪ Project page ▪ http://jnosql.org

    ▪ Specifications ▪ Jakarta NoSQL: https://jakarta.ee/specifications/nosql/ ▪ Jakarta Data: https://jakarta.ee/specifications/data/ @wernerkeil Links @otaviojava