diff --git a/pom.xml b/pom.xml
index 473cba4f..9c29cc78 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,7 @@
helidon-examples
payara-micro-example
watsonx-ai-examples
+ yugabytedb-example
diff --git a/yugabytedb-example/pom.xml b/yugabytedb-example/pom.xml
new file mode 100644
index 00000000..07eae667
--- /dev/null
+++ b/yugabytedb-example/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+ dev.langchain4j
+ yugabytedb-example
+ 1.8.0-beta15-SNAPSHOT
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+ dev.langchain4j
+ langchain4j-community-yugabytedb
+ 1.8.0-beta15-SNAPSHOT
+
+
+
+ org.testcontainers
+ testcontainers
+ 1.19.7
+
+
+
+ dev.langchain4j
+ langchain4j-embeddings-all-minilm-l6-v2
+ 1.7.1-beta14
+
+
+
+ org.slf4j
+ slf4j-simple
+ 2.0.12
+
+
+
+
+
+
diff --git a/yugabytedb-example/run-example.sh b/yugabytedb-example/run-example.sh
new file mode 100755
index 00000000..aba5353f
--- /dev/null
+++ b/yugabytedb-example/run-example.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# Run YugabyteDB examples as standalone applications
+# This avoids exec:java classloader issues with Testcontainers
+
+set -e
+
+EXAMPLE_CLASS=${1:-YugabyteDBEmbeddingStoreExample}
+
+echo "๐ Building project..."
+../mvnw clean compile -q
+
+echo "๐ฆ Running example: $EXAMPLE_CLASS"
+echo ""
+
+# Run with proper classpath
+../mvnw exec:exec -Dexec.executable="java" \
+ -Dexec.args="-cp %classpath $EXAMPLE_CLASS" \
+ -q
+
+echo ""
+echo "โ
Example execution completed!"
+
diff --git a/yugabytedb-example/src/main/java/YugabyteDBEmbeddingStoreExample.java b/yugabytedb-example/src/main/java/YugabyteDBEmbeddingStoreExample.java
new file mode 100644
index 00000000..3fe7abf3
--- /dev/null
+++ b/yugabytedb-example/src/main/java/YugabyteDBEmbeddingStoreExample.java
@@ -0,0 +1,104 @@
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEmbeddingStore;
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEngine;
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
+import dev.langchain4j.store.embedding.EmbeddingMatch;
+import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
+import dev.langchain4j.store.embedding.EmbeddingStore;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+import java.time.Duration;
+import java.util.List;
+
+public class YugabyteDBEmbeddingStoreExample {
+
+ public static void main(String[] args) {
+ GenericContainer> yugabyteContainer = null;
+ YugabyteDBEngine engine = null;
+
+ try {
+ DockerImageName dockerImageName = DockerImageName.parse("yugabytedb/yugabyte:2025.1.0.1-b3");
+ yugabyteContainer = new GenericContainer<>(dockerImageName)
+ .withExposedPorts(5433, 7000, 9000, 15433, 9042)
+ .withCommand("bin/yugabyted", "start", "--background=false")
+ .waitingFor(Wait.forListeningPorts(5433).withStartupTimeout(Duration.ofMinutes(5)));
+
+ yugabyteContainer.start();
+
+ EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
+
+ // Create YugabyteDB engine with PostgreSQL driver
+ engine = YugabyteDBEngine.builder()
+ .host(yugabyteContainer.getHost())
+ .port(yugabyteContainer.getMappedPort(5433))
+ .database("yugabyte")
+ .username("yugabyte")
+ .password("yugabyte")
+ .usePostgreSQLDriver(true) // Use PostgreSQL JDBC driver
+ .build();
+
+ EmbeddingStore embeddingStore = YugabyteDBEmbeddingStore.builder()
+ .engine(engine)
+ .tableName("test_embeddings")
+ .dimension(embeddingModel.dimension())
+ .createTableIfNotExists(true)
+ .build();
+
+ TextSegment segment1 = TextSegment.from("I like football.");
+ Embedding embedding1 = embeddingModel.embed(segment1).content();
+ embeddingStore.add(embedding1, segment1);
+
+ TextSegment segment2 = TextSegment.from("The weather is good today.");
+ Embedding embedding2 = embeddingModel.embed(segment2).content();
+ embeddingStore.add(embedding2, segment2);
+
+ Embedding queryEmbedding = embeddingModel.embed("What is your favourite sport?").content();
+
+ EmbeddingSearchRequest embeddingSearchRequest = EmbeddingSearchRequest.builder()
+ .queryEmbedding(queryEmbedding)
+ .maxResults(1)
+ .build();
+
+ List> relevant = embeddingStore.search(embeddingSearchRequest).matches();
+
+ EmbeddingMatch embeddingMatch = relevant.get(0);
+
+ System.out.println(embeddingMatch.score()); // ~0.8144
+ System.out.println(embeddingMatch.embedded().text()); // I like football.
+
+ System.out.println("\nโ
Example completed successfully!");
+
+ } catch (Exception e) {
+ System.err.println("โ Error running example: " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ // Give Testcontainers time to cleanup gracefully
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ }
+
+ // Cleanup resources
+ System.out.println("๐งน Cleaning up resources...");
+ if (engine != null) {
+ try {
+ engine.close();
+ } catch (Exception e) {
+ System.err.println("Error closing engine: " + e.getMessage());
+ }
+ }
+ if (yugabyteContainer != null) {
+ try {
+ yugabyteContainer.stop();
+ } catch (Exception e) {
+ System.err.println("Error stopping container: " + e.getMessage());
+ }
+ }
+ }
+ }
+}
+
diff --git a/yugabytedb-example/src/main/java/YugabyteDBEmbeddingStoreWithMetadataExample.java b/yugabytedb-example/src/main/java/YugabyteDBEmbeddingStoreWithMetadataExample.java
new file mode 100644
index 00000000..b4fe517b
--- /dev/null
+++ b/yugabytedb-example/src/main/java/YugabyteDBEmbeddingStoreWithMetadataExample.java
@@ -0,0 +1,131 @@
+import dev.langchain4j.community.store.embedding.yugabytedb.DefaultMetadataStorageConfig;
+import dev.langchain4j.community.store.embedding.yugabytedb.MetadataStorageConfig;
+import dev.langchain4j.community.store.embedding.yugabytedb.MetadataStorageMode;
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEmbeddingStore;
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEngine;
+import dev.langchain4j.data.document.Metadata;
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
+import dev.langchain4j.store.embedding.EmbeddingMatch;
+import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
+import dev.langchain4j.store.embedding.EmbeddingStore;
+import dev.langchain4j.store.embedding.filter.Filter;
+import dev.langchain4j.store.embedding.filter.comparison.IsEqualTo;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+import java.time.Duration;
+import java.util.List;
+
+public class YugabyteDBEmbeddingStoreWithMetadataExample {
+
+ public static void main(String[] args) {
+ GenericContainer> yugabyteContainer = null;
+ YugabyteDBEngine engine = null;
+
+ try {
+ DockerImageName dockerImageName = DockerImageName.parse("yugabytedb/yugabyte:2025.1.0.1-b3");
+ yugabyteContainer = new GenericContainer<>(dockerImageName)
+ .withExposedPorts(5433, 7000, 9000, 15433, 9042)
+ .withCommand("bin/yugabyted", "start", "--background=false")
+ .waitingFor(Wait.forListeningPorts(5433).withStartupTimeout(Duration.ofMinutes(5)));
+
+ yugabyteContainer.start();
+
+ EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
+
+ // Create YugabyteDB engine with PostgreSQL driver
+ engine = YugabyteDBEngine.builder()
+ .host(yugabyteContainer.getHost())
+ .port(yugabyteContainer.getMappedPort(5433))
+ .database("yugabyte")
+ .username("yugabyte")
+ .password("yugabyte")
+ .usePostgreSQLDriver(true)
+ .build();
+
+ // Configure metadata storage (JSONB format)
+ MetadataStorageConfig metadataConfig = DefaultMetadataStorageConfig.builder()
+ .storageMode(MetadataStorageMode.COMBINED_JSONB)
+ .build();
+
+ EmbeddingStore embeddingStore = YugabyteDBEmbeddingStore.builder()
+ .engine(engine)
+ .tableName("test_embeddings_with_metadata")
+ .dimension(embeddingModel.dimension())
+ .metadataStorageConfig(metadataConfig)
+ .createTableIfNotExists(true)
+ .build();
+
+ // Add embeddings with metadata
+ TextSegment segment1 = TextSegment.from("I like football.",
+ Metadata.from("category", "sports").put("user", "john"));
+ Embedding embedding1 = embeddingModel.embed(segment1).content();
+ embeddingStore.add(embedding1, segment1);
+
+ TextSegment segment2 = TextSegment.from("The weather is good today.",
+ Metadata.from("category", "weather").put("user", "alice"));
+ Embedding embedding2 = embeddingModel.embed(segment2).content();
+ embeddingStore.add(embedding2, segment2);
+
+ TextSegment segment3 = TextSegment.from("I love basketball.",
+ Metadata.from("category", "sports").put("user", "bob"));
+ Embedding embedding3 = embeddingModel.embed(segment3).content();
+ embeddingStore.add(embedding3, segment3);
+
+ // Search with metadata filter
+ Embedding queryEmbedding = embeddingModel.embed("What sport do you like?").content();
+
+ Filter categoryFilter = new IsEqualTo("category", "sports");
+
+ EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
+ .queryEmbedding(queryEmbedding)
+ .maxResults(5)
+ .filter(categoryFilter)
+ .build();
+
+ List> relevant = embeddingStore.search(searchRequest).matches();
+
+ System.out.println("Found " + relevant.size() + " sports-related results:");
+ for (EmbeddingMatch match : relevant) {
+ System.out.println("Score: " + match.score());
+ System.out.println("Text: " + match.embedded().text());
+ System.out.println("Metadata: " + match.embedded().metadata());
+ System.out.println("---");
+ }
+
+ System.out.println("\nโ
Example completed successfully!");
+
+ } catch (Exception e) {
+ System.err.println("โ Error running example: " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ // Give Testcontainers time to cleanup gracefully
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ }
+
+ // Cleanup resources
+ System.out.println("๐งน Cleaning up resources...");
+ if (engine != null) {
+ try {
+ engine.close();
+ } catch (Exception e) {
+ System.err.println("Error closing engine: " + e.getMessage());
+ }
+ }
+ if (yugabyteContainer != null) {
+ try {
+ yugabyteContainer.stop();
+ } catch (Exception e) {
+ System.err.println("Error stopping container: " + e.getMessage());
+ }
+ }
+ }
+ }
+}
+
diff --git a/yugabytedb-example/src/main/java/YugabyteDBWithPostgreSQLDriverExample.java b/yugabytedb-example/src/main/java/YugabyteDBWithPostgreSQLDriverExample.java
new file mode 100644
index 00000000..17007c61
--- /dev/null
+++ b/yugabytedb-example/src/main/java/YugabyteDBWithPostgreSQLDriverExample.java
@@ -0,0 +1,126 @@
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEmbeddingStore;
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEngine;
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
+import dev.langchain4j.store.embedding.EmbeddingMatch;
+import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
+import dev.langchain4j.store.embedding.EmbeddingStore;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * This example demonstrates using YugabyteDB with the PostgreSQL JDBC driver.
+ *
+ * PostgreSQL JDBC driver is recommended for:
+ * - Standard SQL operations
+ * - Maximum PostgreSQL compatibility
+ * - Simple single-node or replicated deployments
+ */
+public class YugabyteDBWithPostgreSQLDriverExample {
+
+ public static void main(String[] args) {
+ GenericContainer> yugabyteContainer = null;
+ YugabyteDBEngine engine = null;
+
+ try {
+ DockerImageName dockerImageName = DockerImageName.parse("yugabytedb/yugabyte:2025.1.0.1-b3");
+ yugabyteContainer = new GenericContainer<>(dockerImageName)
+ .withExposedPorts(5433, 7000, 9000, 15433, 9042)
+ .withCommand("bin/yugabyted", "start", "--background=false")
+ .waitingFor(Wait.forListeningPorts(5433).withStartupTimeout(Duration.ofMinutes(5)));
+
+ yugabyteContainer.start();
+
+ EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
+
+ System.out.println("=== Using PostgreSQL JDBC Driver ===");
+ System.out.println("Driver: org.postgresql.Driver");
+ System.out.println("Best for: Standard SQL operations and PostgreSQL compatibility");
+ System.out.println();
+
+ // Create YugabyteDB engine with PostgreSQL JDBC driver
+ engine = YugabyteDBEngine.builder()
+ .host(yugabyteContainer.getHost())
+ .port(yugabyteContainer.getMappedPort(5433))
+ .database("yugabyte")
+ .username("yugabyte")
+ .password("yugabyte")
+ .usePostgreSQLDriver(true) // โ Use PostgreSQL JDBC driver
+ .maxPoolSize(10)
+ .build();
+
+ EmbeddingStore embeddingStore = YugabyteDBEmbeddingStore.builder()
+ .engine(engine)
+ .tableName("postgres_driver_embeddings")
+ .dimension(embeddingModel.dimension())
+ .createTableIfNotExists(true)
+ .build();
+
+ // Add some sample data
+ TextSegment segment1 = TextSegment.from("PostgreSQL driver provides excellent compatibility.");
+ Embedding embedding1 = embeddingModel.embed(segment1).content();
+ embeddingStore.add(embedding1, segment1);
+
+ TextSegment segment2 = TextSegment.from("YugabyteDB is PostgreSQL compatible.");
+ Embedding embedding2 = embeddingModel.embed(segment2).content();
+ embeddingStore.add(embedding2, segment2);
+
+ TextSegment segment3 = TextSegment.from("Vector search works seamlessly with pgvector.");
+ Embedding embedding3 = embeddingModel.embed(segment3).content();
+ embeddingStore.add(embedding3, segment3);
+
+ // Search for similar embeddings
+ Embedding queryEmbedding = embeddingModel.embed("Tell me about PostgreSQL compatibility").content();
+
+ EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
+ .queryEmbedding(queryEmbedding)
+ .maxResults(2)
+ .build();
+
+ List> relevant = embeddingStore.search(searchRequest).matches();
+
+ System.out.println("Search Results:");
+ for (EmbeddingMatch match : relevant) {
+ System.out.println(" Score: " + String.format("%.4f", match.score()));
+ System.out.println(" Text: " + match.embedded().text());
+ System.out.println();
+ }
+
+ System.out.println("\nโ
Example completed successfully!");
+
+ } catch (Exception e) {
+ System.err.println("โ Error running example: " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ // Give Testcontainers time to cleanup gracefully
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ }
+
+ // Cleanup resources
+ System.out.println("๐งน Cleaning up resources...");
+ if (engine != null) {
+ try {
+ engine.close();
+ } catch (Exception e) {
+ System.err.println("Error closing engine: " + e.getMessage());
+ }
+ }
+ if (yugabyteContainer != null) {
+ try {
+ yugabyteContainer.stop();
+ } catch (Exception e) {
+ System.err.println("Error stopping container: " + e.getMessage());
+ }
+ }
+ }
+ }
+}
+
diff --git a/yugabytedb-example/src/main/java/YugabyteDBWithSmartDriverExample.java b/yugabytedb-example/src/main/java/YugabyteDBWithSmartDriverExample.java
new file mode 100644
index 00000000..02c20abe
--- /dev/null
+++ b/yugabytedb-example/src/main/java/YugabyteDBWithSmartDriverExample.java
@@ -0,0 +1,132 @@
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEmbeddingStore;
+import dev.langchain4j.community.store.embedding.yugabytedb.YugabyteDBEngine;
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
+import dev.langchain4j.store.embedding.EmbeddingMatch;
+import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
+import dev.langchain4j.store.embedding.EmbeddingStore;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * This example demonstrates using YugabyteDB with the YugabyteDB Smart Driver.
+ *
+ * YugabyteDB Smart Driver is recommended for:
+ * - Advanced distributed database features
+ * - Topology-aware load balancing
+ * - Node-aware connection management
+ * - Multi-region deployments
+ */
+public class YugabyteDBWithSmartDriverExample {
+
+ public static void main(String[] args) {
+ GenericContainer> yugabyteContainer = null;
+ YugabyteDBEngine engine = null;
+
+ try {
+ DockerImageName dockerImageName = DockerImageName.parse("yugabytedb/yugabyte:2025.1.0.1-b3");
+ yugabyteContainer = new GenericContainer<>(dockerImageName)
+ .withExposedPorts(5433, 7000, 9000, 15433, 9042)
+ .withCommand("bin/yugabyted", "start", "--background=false")
+ .waitingFor(Wait.forListeningPorts(5433).withStartupTimeout(Duration.ofMinutes(5)));
+
+ yugabyteContainer.start();
+
+ EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
+
+ System.out.println("=== Using YugabyteDB Smart Driver ===");
+ System.out.println("Driver: com.yugabyte.Driver");
+ System.out.println("Best for: Distributed deployments with topology-aware load balancing");
+ System.out.println();
+
+ // Create YugabyteDB engine with Smart Driver
+ engine = YugabyteDBEngine.builder()
+ .host(yugabyteContainer.getHost())
+ .port(yugabyteContainer.getMappedPort(5433))
+ .database("yugabyte")
+ .username("yugabyte")
+ .password("yugabyte")
+ .usePostgreSQLDriver(false) // โ Use YugabyteDB Smart Driver (default)
+ .maxPoolSize(10)
+ .build();
+
+ EmbeddingStore embeddingStore = YugabyteDBEmbeddingStore.builder()
+ .engine(engine)
+ .tableName("smart_driver_embeddings")
+ .dimension(embeddingModel.dimension())
+ .createTableIfNotExists(true)
+ .build();
+
+ // Add some sample data
+ TextSegment segment1 = TextSegment.from("Smart Driver provides topology-aware load balancing.");
+ Embedding embedding1 = embeddingModel.embed(segment1).content();
+ embeddingStore.add(embedding1, segment1);
+
+ TextSegment segment2 = TextSegment.from("Distributed databases benefit from cluster-aware drivers.");
+ Embedding embedding2 = embeddingModel.embed(segment2).content();
+ embeddingStore.add(embedding2, segment2);
+
+ TextSegment segment3 = TextSegment.from("Multi-region deployments require smart connection management.");
+ Embedding embedding3 = embeddingModel.embed(segment3).content();
+ embeddingStore.add(embedding3, segment3);
+
+ // Search for similar embeddings
+ Embedding queryEmbedding = embeddingModel.embed("How do distributed databases handle connections?").content();
+
+ EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
+ .queryEmbedding(queryEmbedding)
+ .maxResults(2)
+ .build();
+
+ List> relevant = embeddingStore.search(searchRequest).matches();
+
+ System.out.println("Search Results:");
+ for (EmbeddingMatch match : relevant) {
+ System.out.println(" Score: " + String.format("%.4f", match.score()));
+ System.out.println(" Text: " + match.embedded().text());
+ System.out.println();
+ }
+
+ System.out.println("\nSmart Driver Features:");
+ System.out.println(" โ Topology-aware load balancing");
+ System.out.println(" โ Automatic failover");
+ System.out.println(" โ Connection pooling per node");
+ System.out.println(" โ Preferred region support");
+
+ System.out.println("\nโ
Example completed successfully!");
+
+ } catch (Exception e) {
+ System.err.println("โ Error running example: " + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ // Give Testcontainers time to cleanup gracefully
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ }
+
+ // Cleanup resources
+ System.out.println("๐งน Cleaning up resources...");
+ if (engine != null) {
+ try {
+ engine.close();
+ } catch (Exception e) {
+ System.err.println("Error closing engine: " + e.getMessage());
+ }
+ }
+ if (yugabyteContainer != null) {
+ try {
+ yugabyteContainer.stop();
+ } catch (Exception e) {
+ System.err.println("Error stopping container: " + e.getMessage());
+ }
+ }
+ }
+ }
+}