Building AI-Powered Database Apps with Hibernate Vector and the Oracle Database 23ai — Part 2 — Using the Hibernate Vector module with Oracle AI Vector Search

Introduction — Hibernate Vector module with Oracle AI Vector Search
Part 1 in this series introduced the Hibernate Vector module and how to use it with Oracle Database 23ai by creating Hibernate DB apps that work with vectors and tables with embeddings of the VECTOR data type. Please check it if you need a quick introduction to the topic.
Now Part 2 will show you how to implement similarity search using the Hibernate Vector module, Jakarta Persistence, Oracle AI Vector Search, Oracle JDBC, and the Oracle Database 23ai.
The good news is that you can still use HQL (Hibernate Query Language) combined with several functions as the Hibernate Vector module implementation maps to the underlying functions implemented by Oracle AI Vector Search.
So, without further ado, let’s get started!
Prerequisites
- JDK — Java Development Kit 17 or newer
- Oracle Database Free Release 23ai — Container Image
- Oracle JDBC Driver 23ai
- Your preferred Java IDE — Eclipse, IntelliJ, VS Code
- Apache Maven
- Gradle
Step 1: Configure Your Java Project
There are no changes here - the steps are pretty much the same as in Part 1 of this series. This assumes you know Java, Hibernate, Maven or Gradle, and relational database concepts. Start by creating a Maven project (or using your preferred build tool). Add the dependencies to your build configuration file.
Using Maven
<dependencies>
<!-- Oracle JDBC Driver -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc17</artifactId>
<version>23.7.0.25.01</version>
</dependency>
<!-- Oracle UCP -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ucp17</artifactId>
<version>23.7.0.25.01</version>
</dependency>
<!-- Hibernate Core -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.6.10.Final</version>
</dependency>
<!-- Hibernate Vector Module -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-vector</artifactId>
<version>6.6.10.Final</version>
</dependency>
<!-- Jakarta EE -->
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<version>2.0.1</version>
</dependency>
Using Gradle
dependencies {
// Oracle JDBC Driver
implementation 'com.oracle.database.jdbc:ojdbc17:23.7.0.25.01'
// Oracle UCP
implementation 'com.oracle.database.jdbc:ucp17:23.7.0.25.01'
// Hibernate Core
implementation 'org.hibernate.orm:hibernate-core:6.6.10.Final'
// Hibernate Vector Module
implementation 'org.hibernate.orm:hibernate-vector:6.6.10.Final'
// Jakarta EE
implementation 'jakarta.persistence:jakarta.persistence-api:3.2.0'
implementation 'jakarta.transaction:jakarta.transaction-api:2.0.1'
}
Step 2: Configure Hibernate
The same here - no changes at all. As usual, you must create your Hibernate configuration file (hibernate.properties or hibernate.cfg.xml) to enable it to access your Oracle Database 23ai instance.
# Oracle JDBC driver
hibernate.connection.url=jdbc:oracle:thin:@<DB_HOST>:<DB_PORT>/FREEPDB1
hibernate.connection.username=<DB_USER>
hibernate.connection.password=<DB_PASSWORD>
hibernate.connection.driver_class=oracle.jdbc.OracleDriver
hibernate.dialect=org.hibernate.dialect.OracleDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update
# Oracle Universal Connection Pool (UCP)
hibenrate.connection.driver_class=oracle.jdbc.OracleDriver
hibernate.oracleucp.connectionFactoryClassName=oracle.jdbc.datasource.impl.OracleDataSource
hibernate.oracleucp.initialPoolSize=3
hibernate.oracleucp.minPoolSize=3
hibernate.oracleucp.maxPoolSize=5
hibernate.oracleucp.connectionPoolName=hibernateVectorPool
hibernate.oracleucp.dataSourceName=hibernateVectorDataSource
hibernate.oracleucp.connectionProperties={autoCommit=false}
hibernate.oracleucp.fastConnectionFailoverEnabled=false
hibernate.oracleucp.validateConnectionOnBorrow=true
hibernate.oracleucp.secondsToTrustIdleConnection=120
hibernate.oracleucp.inactiveConnectionTimeout=180
hibernate.oracleucp.maxStatements=20
Step 3: Create Java Entity With Vector Data Type
Here’s the first change. We have to modify our entity to accommodate another VECTOR
data type column, that is, embedding_two. It’s a minor adjustment anyway, so please just add it. Given that using Java Records with Hibernate has some limitations, we’ll add the respective setters/getters as expected as well.
@Entity
@Table(name = "VECTOR_USER.vector_data_search")
public class HibernateVectorDataTypeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "embedding")
@JdbcTypeCode(SqlTypes.VECTOR_FLOAT32)
@Array(length = 3)
private float[] embedding;
@Column(name = "embedding_two")
@JdbcTypeCode(SqlTypes.VECTOR_FLOAT32)
@Array(length = 3)
private float[] embeddingTwo;
Step 4: Storing and Retrieving Vector Embeddings
Once your entity is set up, you can store and retrieve vectors using Hibernate as explained in Part 1 as well — so all methods are the same except the insertVector() method which has been modified to support the inserts that consider the second column now.
Insert vector
private void insertVector() {
try (Session session = sessionFactory.openSession()) {
Transaction tx = session.beginTransaction();
HibernateVectorDataTypeEntity entity = new HibernateVectorDataTypeEntity();
float[] emb1 = { randFloat(), randFloat(), randFloat() };
float[] emb2 = { randFloat(), randFloat(), randFloat() };
entity.setEmbedding(emb1);
entity.setEmbeddingTwo(emb2);
session.persist(entity);
tx.commit();
}
}
Note that values will be created by a helper method called randFloat(), as it will generate values from a normal distribution centered at 0 with a considerable spread between [-50, 50]. This is interesting because to demonstrate the similarity searches, we do not want all vectors to be the same, or pretty similar.
private float randFloat() {
return (float) (Math.random() * 100 - 50);
}
All remaining Java methods that work directly with Hibernate and data (readVector(), updateVector(), and deleteVector()) have similar implementations as explained in Part 1, and some utility methods have been added as required.
Step 5: Oracle AI Vector Search with Hibernate Vector
As cited before, you can still use HQL (Hibernate Query Language) combined with several functions as the Hibernate Vector module implementation maps to the underlying Oracle AI Vector Search functions.
Below is the list of supported functions (not an exhaustive list).
Last but not least, let’s have a look at how to use them from your Java code.
Similarity search with cosine_distance()
public void cosineSimilaritySearch(float[] searchVector) {
try (Session session = sessionFactory.openSession()) {
Query<HibernateVectorDataTypeEntity> query = session.createQuery(
"SELECT e FROM HibernateVectorDataTypeEntity e " + "ORDER BY cosine_distance(e.embedding, :vector) ASC",
HibernateVectorDataTypeEntity.class);
query.setParameter("vector", searchVector);
List<HibernateVectorDataTypeEntity> results = query.getResultList();
System.out.println("\nCosine Similarity Results:");
results.forEach(e -> System.out.println("ID: " + e.getId() + " - " + Arrays.toString(e.getEmbedding())));
}
}
Similarity search with l1_distance()
public void l1DistanceSearch(float[] searchVector) {
try (Session session = sessionFactory.openSession()) {
Query<HibernateVectorDataTypeEntity> query = session.createQuery(
"SELECT e FROM HibernateVectorDataTypeEntity e " + "ORDER BY l1_distance(e.embedding, :vector) ASC",
HibernateVectorDataTypeEntity.class);
query.setParameter("vector", searchVector);
List<HibernateVectorDataTypeEntity> results = query.getResultList();
System.out.println("\nL1 Distance Results:");
results.forEach(e -> System.out.println("ID: " + e.getId() + " - " + Arrays.toString(e.getEmbedding())));
}
}
Similarity search with l2_distance()
public void l2DistanceSearch(float[] searchVector) {
try (Session session = sessionFactory.openSession()) {
Query<HibernateVectorDataTypeEntity> query = session.createQuery(
"SELECT e FROM HibernateVectorDataTypeEntity e " + "ORDER BY l2_distance(e.embedding, :vector) ASC",
HibernateVectorDataTypeEntity.class);
query.setParameter("vector", searchVector);
List<HibernateVectorDataTypeEntity> results = query.getResultList();
System.out.println("\nL2 Distance Results:");
results.forEach(e -> System.out.println("ID: " + e.getId() + " - " + Arrays.toString(e.getEmbedding())));
}
}
Step 6: Test the sample app
Now, you can run and test the application using your preferred IDE (or the CLI). You may want to set breakpoints to query the database and check the records.
Besides, you may enable query debugging if you want to have a look at the underlying HQL queries. As cited in Part 1, just go to your hibernate.properties file and change hibernate.show_sql from false to true.
Note that this time, we inserted 100 records as we needed a larger dataset to exercise the similarity vector searches properly, as shown below.

Next, you will see the results of the same similiarty searches we explained before (Java methods/code above).
Similarity search — cosine_distance() results

Similarity search — l1_distance() results

Similarity search — l2_distance() results

Delete all vectors (database cleanup)
As one last step, we will delete all the records by using a helper Java method called cleanDatabase(), as show below.

Code sample
Below is the complete source code so you can give it a try!
HibernateVectorDataTypeEntity.java
HibernateVectorDataTypeOracleDatabase.java
Wrap-Up
That’s it! This blog post presented a combination of the Hibernate Vector module, Jakarta Persistence, and Oracle AI Vector Search, exploring how they can easily enable the creation of GenAI solutions. As we learned, Java developers now have an easy way to handle vector data and enable vector similarity searches, ultimately improving their productivity and the time-to-market of their applications!
As one last tip, I invite you to check out the new Database Navigator tool published at JetBrains Marketplace. In a nutshell, it features a robust SQL and PL/SQL editor with advanced capabilities for managing database connections, executing scripts, editing database objects, and modifying data and code with IntelliJ!
I will soon post more examples of scenarios involving LangChain4J, the OracleEmbeddingStore, GraalVM, Micronaut, Quarkus, and other GenAI / Agentic AI-related topics!
That’s it! I hope you liked this blog post, thanks for reading!
References
Overview of Oracle AI Vector Search
Oracle AI Vector Search Technical Architecture
Oracle Database Free Release 23ai — Container Image
Oracle JDBC Driver 23ai (23.4+) — Maven Central
Oracle® Database JDBC Java API Reference, Release 23ai
Database Navigator — JetBrains Marketplace
Quickstart: Connect to Oracle Database 23ai using IntelliJ IDEA
Developers Guide For Oracle JDBC on Maven Central
Develop Java applications with Oracle Database
Oracle Developers and Oracle OCI Free Tier
Join our Oracle Developers channel on Slack to discuss Java, GenAI, Agentic AI, JDK, JDBC, GraalVM, Micronaut, Spring Boot, Helidon, Quarkus, Reactive Streams, Cloud, DevOps, SRE, IaC, and other topics!
Build, test, and deploy your applications on Oracle Cloud — for free! Get access to OCI Cloud Free Tier!