Preface

NoSQL databases provide different data modeling and performance characteristics compared to Relational Databases, yet the necessity to map between the Database specific format and Java objects is still prevalent. Hibernate is an Object/Relational Mapping solution for Java environments. The term Object/Relational Mapping refers to the technique of mapping data from an object model representation to a relational data model representation (and vice versa).

Hibernate NoSQL is an extension to Hibernate ORM, providing a similar developer experience to NoSQL Database users. It takes care of the mapping from Java classes to documents/graphs/tables (and from Java data types to datastore data types), but also provides data query and retrieval facilities. It can significantly reduce development time otherwise spent with manual data handling in the various proprietary query languages and specialized drivers. Hibernate NoSQL’s design goal, similar to Hibernate ORM’s, is to relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for manual, hand-crafted data processing. However, unlike many other persistence solutions, Hibernate NoSQL does not hide the power of the native query language and driver from you.

Hibernate NoSQL may not be the best solution for data-centric applications that use highly specialized driver/datastore features to implement the business logic, it is most useful with object-oriented domain models and business logic in the Java-based middle-tier. However, Hibernate NoSQL can certainly help you to remove or encapsulate vendor-specific query and driver code and will help with the common task of result set translation from the native driver representation to a graph of objects.

System Requirements

Hibernate NoSQL 1.0 requires at least Java 17 or 21 and JDBC 4.2.

Getting Started

While a strong background in SQL is not required to use Hibernate, a basic understanding of its concepts is useful - especially the principles of data modeling. Understanding the basics of transactions and design patterns such as Unit of Work are important as well.

Get Involved

  • Use Hibernate NoSQL and report any bugs or issues you find. See Issue Tracker for details.

  • Try your hand at fixing some bugs or implementing enhancements. Again, see Issue Tracker.

  • Engage with the community using the methods listed in the Community section.

  • Help improve this documentation. Contact us on the developer mailing list or Zulip if you have interest.

  • Spread the word. Let the rest of your organization know about the benefits of Hibernate.

1. Compatibility

1.1. Dependencies

Hibernate NoSQL 1.0.0.Alpha1 requires the following dependencies (among others):

Table 1.1: Compatible versions of dependencies

Version

Java Runtime

17 or 21

Hibernate ORM

7.4.5.Final

JDBC (bundled with the Java Runtime)

4.2

Find more information for all versions of Hibernate NoSQL on our compatibility matrix.

The compatibility policy may also be of interest.

If you get Hibernate NoSQL from Maven Central, it is recommended to import Hibernate Platform as part of your dependency management to keep all its artifact versions aligned.

Gradle
dependencies {
  implementation platform "org.hibernate.nosql:hibernate-platform:1.0.0.Alpha1"

  // use the versions from the platform
  implementation "org.hibernate.nosql:hibernate-nosql-core"
  // Use a NoSQL dialect of your choice
  implementation "org.hibernate.nosql:hibernate-neo4j"
  implementation "jakarta.transaction:jakarta.transaction-api"
}
Maven
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.hibernate.nosql</groupId>
            <artifactId>hibernate-platform</artifactId>
            <version>1.0.0.Alpha1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<!-- use the versions from the platform -->
<dependencies>
    <dependency>
        <groupId>org.hibernate.nosql</groupId>
        <artifactId>hibernate-nosql-core</artifactId>
    </dependency>
    <!-- Use a NoSQL dialect of your choice -->
    <dependency>
        <groupId>org.hibernate.nosql</groupId>
        <artifactId>hibernate-neo4j</artifactId>
    </dependency>
    <dependency>
        <groupId>jakarta.transaction</groupId>
        <artifactId>jakarta.transaction-api</artifactId>
    </dependency>
</dependencies>

1.2. Database

Hibernate NoSQL 1.0.0.Alpha1’s compatibility with a given database and version depends on the dialect being used.

Refer to the Dialects guide for details about both dialects and supported databases.

2. Overview

2.1. Modules

Hibernate NoSQL is split into

  • hibernate-nosql-core - Implementation of the Jakarta JNoSQL specification

  • hibernate-platform - The platform or bill-of-materials (BOM) module which can be used to align versions of the Hibernate modules along with the versions of its libraries

  • hibernate-<nosql-database> - A module per supported NoSQL database, enabling the use of Hibernate ORM APIs with that database

2.2. Relation to Hibernate ORM and JDBC

The various Hibernate NoSQL database modules make use of Hibernate ORM SPIs, like Dialect, to implement support for the respective NoSQL database. Sometimes these modules also come with a minimal JDBC driver implementation, that delegates work to an underlying native driver, which is supported by the NoSQL database vendor directly.

The goal of these JDBC driver implementations is not to fully implement the JDBC specification, but rather implement enough aspects, such that Hibernate ORM can reasonably work with them. The JDBC drivers that come with these modules are only intended to be used with Hibernate ORM and not directly by an application, since the drivers will require passing the native query language, as well as special parameter markers or use a certain serialization format. Similarly, binding/extraction of parameters/results for various data types is only implemented for the purposes of Hibernate ORM.

3. NoSQL data stores

3.1. Milvus

Milvus is a very targeted database, with its main focus on vector search. The hibernate-milvus artifact strives to support CRUD functionality, basic queries and common HQL/Criteria vector search queries.

The hibernate-milvus module implements the JDBC driver API on top of the native driver io.milvus:milvus-sdk-java via the class org.hibernate.milvus.jdbc.internal.MilvusDriver. The JDBC URL format is jdbc:milvus://<host>[:<port>]/<database>[?queryParam1=value1[&queryParam2=value2]*] and supports the following query parameters:

  • secure - true or false (default) indicating whether to use https or http to connect to the database host

The short name Milvus will automatically resolve to the dialect class org.hibernate.milvus.MilvusDialect when configured for the hibernate.dialect configuration property, but note that the MilvusDialect will be automatically selected through the DialectResolver contract, unless hibernate.boot.allow_jdbc_metadata_access is set to false.

3.1.1. Features and considerations

Schema generation support

Schema generation is supported, but Milvus requires that a collection (table) contains at least one vector field (non-null until version 3.0) and that an index exists, as well as that the collection is "loaded". This artifact will automatically add a vector field named embedding, if no vector field was found on an entity mapping and fill it with a [0, 0] vector on insert. It will also create a COSINE vector index automatically and load the collection via the schema generation (hbm2ddl).

Indexes can also be declared via the Jakarta Persistence @Table(indexes) annotation and will create automatic indexes or vector indexes, depending on the type of the column/field.

Declaring an index for a vector field, will create a vector index. To specify the metric or other index parameters, provide the options member and give a comma-separated list of assignment-operator-separated key-value pairs e.g. @Index( name = "VectorEntity_ip", columnList = "the_ip_vector", options = "metric=ip").

Supported values for metric are defined via the io.milvus.v2.common.IndexParam.MetricType enumeration, e.g. l2, ip, cosine, hamming, jaccard etc. The valid values for the type option are defined via the io.milvus.v2.common.IndexParam.IndexType enumeration, e.g. flat, ivf_flat, hnsw, diskann etc.

Consult the vendor documentation for an explanation of the available options per type.

Vector distance transformation

Plain vector distance function usage in the select clause and order by clause are allowed and transformed appropriately. Ordering by distance is only supported in the natural order of the distance metric that means "closer". The inner_product metric natural order is descending, whereas all the other metrics require ascending order.

Driver requests require that vector distance filtering happens through dedicated values radius and range_filter. In order to support that, the dialect analyzes the predicate and tries to hoist the vector distance filtering as a top-level predicate. Therefore, it’s important to ensure the vector distance restriction can be hoisted i.e. the following is illegal x is null or cosine_distance(…​) < 1.

Translation between the vector distance and the native driver score is done automatically, but beware that Milvus only has 32-bit float precision for the vector distance/score when trying to compare distance values and the transformations between distance and score representation can therefore lead to some inaccuracies when working with exact values. If exact values are used, try to round, truncate or simply subtract a slight error margin from the float value.

Note that due to the nature of the fixed comparison operators that are applied for radius and range_filter, the driver might apply slight offsets (Float.MIN_VALUE) to filter values to emulate a greater than (>) operator when the natural operator is greater or equal (>=) and so on.

Data type transformation

The native Milvus driver does not support transferring 8- or 16-bit integers, as well as 32-bit floats. When widening a 32-bit float to a 64-bit double, there is a chance that the string representation of the two values is different, which is why this driver chose to widen 32-bit floats by doing Double.parseDouble( Float.toString( floatValue ) ) instead. Keep this in mind when working with floating point comparisons, like vector distance comparisons.

Id list transformation

Driver requests require that primary key based filtering happens through a dedicated list of values. In order to support that, the dialect analyzes the predicate and tries to hoist the id filtering as a top-level predicate. Therefore, it’s important to ensure the id restriction can be hoisted i.e. the following is illegal x is null or id in :list.

3.1.2. Limitations

Transaction support

Milvus does NOT support transactions, so better ensure that every interaction that you do with your database through Hibernate ORM APIs is idempotent.

Native query support

Milvus does NOT have a native query language. Therefore, the native queries that are passed to the JDBC layer are a String serialized form of the request object, to be passed to the native driver. Parsing and serialization is done with org.hibernate.milvus.jdbc.MilvusJsonHelper, which you can use to construct custom native queries.

Limited query support

Milvus lacks many basic querying features. The following is a non-exhaustive list of HQL/Criteria features that DON’T work

  • CTEs (with clause)

  • Select statements in from clause

  • Set operations (union, except, intersect)

  • Insert-Select statements

  • Select statement with distinct clause

  • select clause with anything but path or vector distance items

  • Joins

  • Subqueries

  • having clause

  • group by clause with more than one item or non-path item

  • order by clause with anything but natural vector distance order (until Milvus 3.0)

  • fetch clause with anything but ROWS ONLY

  • update statement with where clause other than single primary key restriction

  • Anything involving SQL fragments e.g. @ColumnTransformer, @Formula, @JoinFormula, @GeneratedColumn, @Filter, @FilterJoinTable, @SQLRestriction, @SQLJoinTableRestriction, @SQLOrder

  • Anything involving SQL statements e.g. @NamedNativeQuery, @SQLSelect, SQLDelete, @SQLInsert, @SQLUpdate

  • @Inheritance(strategy) other than SINGLE_TABLE

  • Locking (optimistic and pessimistic) as well as @Version

  • Case insensitive like predicate

  • Not equal (<>/!=) or is distinct from operator for vector distance

  • No or multiple from clause items

  • Functions anywhere but in the where clause, except vector distance and aggregate functions in select clause

  • Most functions, except

    • mod

    • power

    • json_array

    • json_value

    • json_query

    • json_exists

    • array

    • array_list

    • array_length

    • array_get

    • array_contains

    • array_includes

    • array_intersects

    • <metric>_distance i.e. vector distance functions

    • No support for binary, varbinary and blob data types

3.2. Neo4j

Neo4j is a graph database with lots of functionality. The hibernate-neo4j artifact strives to support CRUD functionality and many kinds of search queries and functions.

The hibernate-neo4j is designed to work with the official JDBC driver org.neo4j:neo4j-jdbc-full-bundle via the class org.neo4j.jdbc.Neo4jDriver. The JDBC URL format is jdbc:neo4j://<host>[:<port>]/<database>[?queryParam1=value1[&queryParam2=value2]*]. For further details, consult the driver documentation of the vendor.

The short name Neo4j will automatically resolve to the dialect class org.hibernate.neo4j.Neo4jDialect when configured for the hibernate.dialect configuration property, but note that the Neo4jDialect will be automatically selected through the DialectResolver contract, unless hibernate.boot.allow_jdbc_metadata_access is set to false.

3.2.1. Features and considerations

Schema generation support

Schema generation is supported and constraints are emitted, depending on database support, since not null constraints are only supported in the Neo4j enterprise edition.

Cypher as native query language

This dialect renders Cypher queries instead of relying on the SQL translation layer of the Neo4j JDBC driver, which means that SQL fragments (e.g. @ColumnTransformer, @Formula, @JoinFormula, @GeneratedColumn, @Filter, @FilterJoinTable, @SQLRestriction, @SQLJoinTableRestriction, @SQLOrder) need to be valid Cypher fragments.

3.2.2. Limitations

Limited query support

Neo4j supports many querying features, yet some translations have not been implemented yet or are simply lacking. The following is a non-exhaustive list of HQL/Criteria features that DON’T work

  • Insert-Select statements

  • Subquery in update set clause

4. Credits

The full list of contributors to Hibernate NoSQL can be found on the GitHub repository.

The following contributors were involved in this documentation:

  • Christian Beikov

Appendix A: Configuration Settings

References