Getting started with Oracle’s official contribution to LangChain4J

Introduction
You may have come across my previous post about LangChain4J with the Oracle Database 23ai, in which I presented how to implement a RAG (Retrieval-Augment Generation) scenario with Oracle AI Vector Search.
The implementation in my previous blog post was an illustration that I created to present the concepts and support many of my talks at technology conferences, meetups, hackathons, and other developer relations activities.
However, our Java JDBC Engineering team recently implemented Oracle’s official contribution to LangChain4J. This blog post provides a quick guide to Oracle’s official implementation with LangChain4J, the Oracle Database 23ai, and its JDBC Driver.
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 (23.4+)
- Your preferred Java IDE — Eclipse, IntelliJ, VS Code
- Apache Maven or Gradle
Oracle Embedding Store in LangChain4J
So, the LangChain4J project now offers out-of-the-box integration with Oracle Database 23ai. It can act as a vector store, enabling efficient storage and retrieval of vector embeddings for advanced similarity searches supported by Oracle AI Vector Search, as explained in my previous blog post - Retrieval-Augmented Generation (RAG) with LangChain4j, OpenAI, and the Oracle Database 23ai.
As expected, Oracle’s contribution to LangChain4J created an OracleEmbeddingStore
that implements the EmbeddingStore
interface to provide native integration to the Oracle Database 23ai.
Configuring the Oracle Embedding Store
Below, we have listed the main configuration details:
Using Maven
<dependency>
<groupId>dev.langchain4j</groupId>
<artificatId>langchain4j-oracle</artificatId>
<version>1.0.0-beta1</version>
</dependency>
Using Gradle
dependencies {
implementation 'dev.langchain4j:langchain4j-oracle:1.0.0-beta1'
}
Using the Oracle Embedding Store
Now, you can use the OracleEmbeddingStore as expected.
First, there’s a handy OracleEmbeddingStore’s builder() method for creating OracleEmbeddedStore instances. It expects a DataSource and an embedding table name as arguments, so if an embedding table exists in your target database, provide the table name as well.
EmbeddingStore embeddingStore = OracleEmbeddingStore.builder()
.dataSource(myDataSource)
.embeddingTable("my_embedding_table")
.build();
If the table does not exist, create it by passing a CreateOption to the builder.
EmbeddingStore embeddingStore = OracleEmbeddingStore.builder()
.dataSource(myDataSource)
.embeddingTable("my_embedding_table", CreateOption.CREATE_IF_NOT_EXISTS)
.build();
Besides, a connection pool will avoid the latency of repeatedly creating new database connections, so it is recommended to configure a DataSource that pools connections, such as Oracle’s UCP — Universal Connection Pool. Below is an example with UCP’s PoolDataSource:
PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
dataSource.setConnectionFactoryClassName(
"oracle.jdbc.datasource.impl.OracleDataSource");
String urlFromEnv = System.getenv("ORACLE_JDBC_URL");
By default the EmbeddingTable will have the following columns:
The builder also allows us to create indexes on the embedding and metadata columns of a target EmbeddingTable
by providing an instance of the Index class. Note that by default no index is created on the target EmbeddingTable.
Two builders, IVFIndexBuilder
andJSONIndexBuilder
, are available and presented below.
IVFIndexBuilder
IVFIndexBuilder allows the configuration of an IVF (Inverted File Flat) index on the embedding column of the EmbeddingTable.
OracleEmbeddingStore embeddingStore =
OracleEmbeddingStore.builder()
.dataSource(myDataSource)
.embeddingTable(EmbeddingTable.builder()
.createOption(CreateOption.CREATE_OR_REPLACE) // use NONE if the table already exists
.name("my_embedding_table")
.idColumn("id_column_name")
.embeddingColumn("embedding_column_name")
.textColumn("text_column_name")
.metadataColumn("metadata_column_name")
.build())
.index(Index.ivfIndexBuilder().createOption(CreateOption.CREATE_OR_REPLACE).build())
.build();
JSONIndexBuilder
JSONIndexBuilder allows the configuration of a function-based index on keys of the metadata column of the EmbeddingTable.
OracleEmbeddingStore.builder()
.dataSource(myDataSource)
.embeddingTable(EmbeddingTable.builder()
.createOption(CreateOption.CREATE_OR_REPLACE) // use NONE if the table already exists
.name("my_embedding_table")
.idColumn("id_column_name")
.embeddingColumn("embedding_column_name")
.textColumn("text_column_name")
.metadataColumn("metadata_column_name")
.build())
.index(Index.jsonIndexBuilder()
.createOption(CreateOption.CREATE_OR_REPLACE)
.key("name", String.class, JSONIndexBuilder.Order.ASC)
.key("year", Integer.class, JSONIndexBuilder.Order.DESC)
.build())
.build();
For more information about using indexes, please check the official documentation — Guidelines for Using Vector Indexes.
A complete code sample is available for you as a reference.
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.rag.content.Content;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.rag.query.Query;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.oracle.CreateOption;
import dev.langchain4j.store.embedding.oracle.OracleEmbeddingStore;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import org.testcontainers.oracle.OracleContainer;
import java.sql.SQLException;
public class OracleEmbeddingStoreExample {
public static void main(String[] args) throws SQLException {
PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
dataSource.setConnectionFactoryClassName(
"oracle.jdbc.datasource.impl.OracleDataSource");
String urlFromEnv = System.getenv("ORACLE_JDBC_URL");
if (urlFromEnv == null) {
OracleContainer oracleContainer = new OracleContainer(
"gvenzl/oracle-free:23.4-slim-faststart")
.withDatabaseName("pdb1")
.withUsername("testuser")
.withPassword("testpwd");
oracleContainer.start();
dataSource.setURL(oracleContainer.getJdbcUrl());
dataSource.setUser(oracleContainer.getUsername());
dataSource.setPassword(oracleContainer.getPassword());
} else {
dataSource.setURL(urlFromEnv);
dataSource.setUser(System.getenv("ORACLE_JDBC_USER"));
dataSource.setPassword(System.getenv("ORACLE_JDBC_PASSWORD"));
}
EmbeddingStore<TextSegment> embeddingStore = OracleEmbeddingStore.builder()
.dataSource(dataSource)
.embeddingTable("test_content_retriever",
CreateOption.CREATE_OR_REPLACE)
.build();
EmbeddingModel embeddingModel = new AllMiniLmL6V2QuantizedEmbeddingModel();
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(2)
.minScore(0.5)
.build();
TextSegment segment1 = TextSegment.from("I like soccer.");
Embedding embedding1 = embeddingModel.embed(segment1).content();
embeddingStore.add(embedding1, segment1);
TextSegment segment2 = TextSegment.from("I love Stephen King.");
Embedding embedding2 = embeddingModel.embed(segment2).content();
embeddingStore.add(embedding2, segment2);
Content match = retriever
.retrieve(Query.from("What is your favourite sport?"))
.get(0);
System.out.println(match.textSegment());
}
}
Last but not least, as I covered in other blog posts, the Oracle AI Vector similarity search is supported by measuring the distance between two vectors using Cosine Similarity, which measures the cosine of the angle between two vectors.
If you need a quick introduction to fundamental topics related to Oracle AI Vector Search, please check the two technical resources below:
What Is a Vector Database and How Can It Help Meet Business Needs
Also, check the official documentation for comprehensive information about Oracle AI Vector Search.
Oracle Database 23ai
If you want to test everything, start a database with a lightweight Docker container. The summarized steps are provided below. First, run the docker pull command below (for Windows):
docker pull container-registry.oracle.com/database/free:latest
Now, you can run the docker images command below to confirm that it was pulled properly:

For more detailed information, go to the Oracle Database 23ai Free container image documentation.
Oracle Database 23ai — container image
Then, run the command below from the Windows Command Prompt (cmd):
docker run -d -p 1521:1521 -e ORACLE_PWD=<your_password> -v oracle-volume:/opt/oracle/oradata container-registry.oracle.com/database/free:latest
Replace <your password> above with your chosen password as required. The command above will run a new persistent database container (data is kept throughout container lifecycles).
If everything goes well, you can run the command docker ps -al to confirm that your container instance is starting as expected.

Please note that the Oracle Database 23ai will be ready to use when the STATUS field shows (healthy), as below.

There are some additional options if you want to configure environment variables to support your connection details, such as username, password, and other variables. You can also check more details about the specific database user (SYS, SYSTEM, PDBADMIN) you may want to use.
Wrapping it up
That’s it. You can now proceed to create your applications with Oracle’s official contribution to LangChain4J (langchain4j-oracle) and the Oracle Database 23ai. I’m keen to see what the Java developers will create with such a great combination!
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!
We hope you liked this blog post. Stay tuned!
References
Oracle JDBC Driver 23ai (23.4+) — Maven Central
LangChain4J — OracleEmbeddingStore — Javadoc
Maven — Oracle Embedding Store (langchain4j-oracle)
LangChain4J — EmbeddingStore — Javadoc
Oracle AI Vector Search Technical Architecture
Oracle Database Free Release 23ai — Container Image
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!