跳到主要内容

Hibernate

LangChain4j は Hibernate とシームレスに統合され、開発者は Hibernate がサポートするすべてのデータベースにベクトル埋め込みを直接保存およびクエリできます。この統合は、セマンティック検索、RAG などのアプリケーションに最適です。

Maven 依存関係​


<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-hibernate</artifactId>
<version>1.23.0-beta33</version>
</dependency>

Hibernate NoSQL 経由で埋め込みを Milvus に保存するには、代わりに次のアーティファクトを使用してください。 これには langchain4j-hibernate がすでに含まれています:


<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-hibernate-milvus</artifactId>
<version>1.23.0-beta33</version>
</dependency>

Gradle 依存関係​

implementation 'dev.langchain4j:langchain4j-hibernate:1.23.0-beta33'

and for Milvus

implementation 'dev.langchain4j:langchain4j-hibernate-milvus:1.23.0-beta33'

APIs​

  • HibernateEmbeddingStore

Parameter Summary​

Generic store​

When using just the EmbeddingStore API without wanting to worry about Hibernate specifics, like entity class definition and the configuration of Hibernate, this kind of store is preferred.

To configure it, use either HibernateEmbeddingStore.dynamicBuilder() or HibernateEmbeddingStore.dynamicDatasourceBuilder().

Plain Java PropertyDescriptionDefault ValueRequired/Optional
datasourceThe DataSource object used for database connections. Available only in the HibernateEmbeddingStore.dynamicDatasourceBuilder() builder variant. If not provided, jdbcUrl (or host, port and database) must be provided in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneRequired if neither jdbcUrl nor host, port and database are provided.
jdbcUrlJDBC URL of the database server. Required if DataSource and host, port, database are not provided. Available only in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneRequired if DataSource or host, port, database are not provided
hostHostname of the database server. Required if neither DataSource or jdbcUrl are not provided. Available only in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneRequired if neither DataSource or jdbcUrl are not provided
portPort number of the database server. Required if neither DataSource or jdbcUrl are not provided. Available only in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneRequired if neither DataSource or jdbcUrl are not provided
databaseName of the database to connect to. Required if neither DataSource or jdbcUrl are not provided. Available only in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneRequired if neither DataSource or jdbcUrl are not provided
databaseKindThe database kind. Required if DataSource is provided or the kind can't be inferred from the jdbcUrl.NoneRequired if DataSource is provided or the kind can't be inferred from the jdbcUrl
userUsername for database authentication. Only applied when set, so it can be left out for a database that does not require authentication. Available only in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneOptional
passwordPassword for database authentication. Only applied when set, so it can be left out for a database that does not require authentication. Available only in the HibernateEmbeddingStore.dynamicBuilder() builder variant.NoneOptional
tableThe name of the database table used for storing embeddings.NoneRequired
dimensionThe dimensionality of the embedding vectors. This should match the embedding model being used. Use embeddingModel.dimension() to dynamically set it.NoneRequired
createIndexSpecifies whether to automatically create an index for the vector embedding.falseOptional
indexTypeThe database specific type of index to use e.g. ivfflat, hnsw. An IVFFlat index divides vectors into lists, and then searches a subset of those lists closest to the query vector. It has faster build times and uses less memory than HNSW but has lower query performance (in terms of speed-recall tradeoff). Should use IVFFlat index.NoneOptional. Defaults to the preferred index type e.g. ivfflat on PostgreSQL
indexOptionsThe options to configure on the index for the vector embedding.NoneWhen Required: If createIndex is true and the index type is ivfflat, on PostgreSQL the lists = 1 option must be provided and must be greater than zero. Otherwise, the program will throw an exception during table initialization. When Optional: If createIndex is false, this property is ignored and doesn’t need to be set.
createTableSpecifies whether to automatically create the embeddings table.falseOptional
dropTableFirstSpecifies whether to drop the table before recreating it (useful for tests).falseOptional
distanceFunctionThe distance function to use for vector search. Supports varies based on database:
  • COSINE
  • EUCLIDEAN
  • EUCLIDEAN_SQUARED
  • MANHATTAN
  • INNER_PRODUCT
  • NEGATIVE_INNER_PRODUCT
  • HAMMING
  • JACCARD
COSINEOptional. If not set, a default configuration is used with COSINE.
queryHintsHibernate query hints applied to every search, for example a consistency level for Milvus. They are not applied when embeddings are added or removed. A hint set here replaces the default hint of the database kind with the same name. See the Milvus section below.None (Milvus: session consistency level)Optional

Entity store​

To make use of an existing Hibernate entity model in the EmbeddingStore API, or to apply data model customizations, the entity store is preferred.

To configure it, use either HibernateEmbeddingStore.builder().

Plain Java PropertyDescriptionDefault ValueRequired/Optional
sessionFactoryThe SessionFactory object where the entityClass is part of.NoneRequired
databaseKindThe database kind. Required if kind can't be inferred from the Hibernate ORM dialect.NoneRequired if kind can't be inferred from the Hibernate ORM dialect
entityClassSpecifies the entity class of the SessionFactory to use for the EmbeddingStore.NoneRequired
embeddingAttributeNameSpecifies the name of the entity attribute that represents the vector embedding.NoneOptional. If not set, the entity is scanned for an attribute annotated with @EmbeddingVector
embeddedTextAttributeNameSpecifies the name of the entity attribute that represents the source text of the vector embedding.NoneOptional. If not set, the entity is scanned for an attribute annotated with @EmbeddedText
unmappedMetadataAttributeNameSpecifies the name of the entity attribute that represents the JSON column where unmapped metadata is stored.NoneOptional. If not set, the entity is scanned for an attribute annotated with @UnmappedMetadata
metadataAttributeNamesSpecifies the names of the entity attributes that are explicitly mapped to text metadata.NoneOptional. If not set, the entity is scanned for an attribute annotated with @MetadataAttribute
distanceFunctionThe distance function to use for vector search. Supports varies based on database:
  • COSINE
  • EUCLIDEAN
  • EUCLIDEAN_SQUARED
  • MANHATTAN
  • INNER_PRODUCT
  • NEGATIVE_INNER_PRODUCT
  • HAMMING
  • JACCARD
COSINEOptional. If not set, the entity is scanned for an attribute annotated with @EmbeddingVector and the distance value is used, or if that is missing, the default configuration is used with COSINE.
queryHintsHibernate query hints applied to every search, for example a consistency level for Milvus. They are not applied when embeddings are added or removed. A hint set here replaces the default hint of the database kind with the same name. See the Milvus section below.None (Milvus: session consistency level)Optional

Examples​

To demonstrate the capabilities, you can e.g. use a Dockerized PostgreSQL setup. It leverages Testcontainers to run PostgreSQL with PGVector.

Quick Start with Docker​

To quickly set up a PostgreSQL instance with the PGVector extension, you can use the following Docker command:

docker run --rm --name langchain4j-postgres-test-container -p 5432:5432 -e POSTGRES_USER=my_user -e POSTGRES_PASSWORD=my_password pgvector/pgvector

Explanation of the Command:​

  • docker run: Runs a new container.
  • --rm: Automatically removes the container after it stops, ensuring no residual data.
  • --name langchain4j-postgres-test-container: Names the container langchain4j-postgres-test-container for easy identification.
  • -p 5432:5432: Maps port 5432 on your local machine to port 5432 in the container.
  • -e POSTGRES_USER=my_user: Sets the PostgreSQL username to my_user.
  • -e POSTGRES_PASSWORD=my_password: Sets the PostgreSQL password to my_password.
  • pgvector/pgvector: Specifies the Docker image to use, pre-configured with the PGVector extension.

Here are two code examples showing how to create a HibernateEmbeddingStore. The first uses only the required parameters, while the second configures all available parameters.

  1. Only Required Parameters
HibernateEmbeddingStore embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
.databaseKind(DatabaseKind.POSTGRESQL) // Required: The database kind
.host("localhost") // Required: Host of the database server
.port(5432) // Required: Port of the database server
.database("postgres") // Required: Database name
.user("my_user") // Database user, if the database requires authentication
.password("my_password") // Database password, if the database requires authentication
.table("my_embeddings") // Required: Table name to store embeddings
.dimension(embeddingModel.dimension()) // Required: Dimension of embeddings
.build();
  1. すべてのパラメータを設定

このバリアントでは、createIndex、indexOptions、 createTable、dropTableFirst、distanceFunction など、よく使われる任意パラメータをすべて含めています。必要に応じてこれらの値を調整してください:

HibernateEmbeddingStore embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
// Required parameters
.databaseKind(DatabaseKind.POSTGRESQL)
.host("localhost")
.port(5432)
.database("postgres")
.user("my_user")
.password("my_password")
.table("my_embeddings")
.dimension(embeddingModel.dimension())

// Optional parameters
.createIndex(true) // Enable vector index creation
.indexType("ivfflat") // Index type IVFFlat
.indexOptions("lists = 100") // Number of lists for IVFFlat index
.createTable(true) // Automatically create the table if it doesn’t exist
.dropTableFirst(false) // Don’t drop the table first (set to true if you want a fresh start)
.distanceFunction(DistanceFunction.MANHATTEN) // Use MANHATTAN distance function for vector search

.build();

すばやく始めるための最小構成が必要な場合は、最初の例を使用してください。 2 つ目の例は、利用可能なすべてのビルダーパラメータを活用して、より多くの制御とカスタマイズを行う方法を示します。

不要になったら HibernateEmbeddingStore を閉じることを忘れないでください。これにより、基盤となる Hibernate リソースが閉じられます。

カスタム Hibernate エンティティ​

データモデルをカスタマイズしたい場合、または既存のエンティティを EmbeddingStore のソースとして再利用したい場合は、 アノテーション @EmbeddingVector、@EmbeddedText、@UnmappedMetadata、@MetadataAttribute を使用して、 Hibernate EmbeddingStore 実装が使用するエンティティ属性をマークできます。

@Entity
public class MyEmbeddingEntity {
@Id
UUID id;
@EmbeddingVector
@Array(length = 384) // The dimension of the embedding vector based on the embedding model
float[] embedding;
@EmbeddedText
String text;
@UnmappedMetadata
Map<String, Object> metadata; // Can be either a Map<String, Object> or a String

@MetadataAttribute
String mimeType; // Explicitly mapped. Synchronizes TextSegment#metadata with this attribute
@MetadataAttribute
String fileName; // Explicitly mapped. Synchronizes TextSegment#metadata with this attribute
}

ビルダーはこれらのアノテーションを探し、属性名を導出します。

HibernateEmbeddingStore embeddingStore = HibernateEmbeddingStore.builder()
.sessionFactory(sessionFactory) // Required: The SessionFactory containing your entity class
.entityClass(MyEmbeddingEntity.class) // Required: The embedding entity class
.build();

あるいは、エンティティモデルにアノテーションを付けたくない場合は、属性名を明示的に提供することもできます。

HibernateEmbeddingStore embeddingStore = HibernateEmbeddingStore.builder()
.sessionFactory(sessionFactory)
.entityClass(MyEmbeddingEntity.class)
.embeddingAttributeName("embedding")
.embeddedTextAttributeName("text")
.unmappedMetadataAttributeName("metadata")
.metadataAttributeNames("mimeType", "fileName")
.build();

メタデータは、同様に @MetadataAttribute でアノテーションされた @OneToOne、@ManyToOne、または @Embedded 属性内にネストすることもできます。 または、.(ドット)区切りで明示的な属性パスを指定することもできます。

@Entity
public class Book {
@Id
private Long id;
private String title;
private String content;
@MetadataAttribute
@Embedded
private BookDetails details = new BookDetails();
@MetadataAttribute
@ManyToOne(fetch = FetchType.LAZY)
private Author author;

@EmbeddingVector
@Array(length = 384)
private float[] embedding;
@UnmappedMetadata
private Map<String, Object> metadata;
}
@Entity
public class Author {
@Id
@MetadataAttribute
@GeneratedValue
private Long id;
private String firstname;
private String lastname;
}
@Embeddable
public class BookDetails {
@MetadataAttribute
private String language;
private String abstractText;
}

同等の属性パスは details.language と author.id であり、これらのパスをメタデータキーとして指定することで フィルタリングに使用できます。例:

MetadataFilterBuilder.metadataKey("details.language").isEqualTo("English")

または

MetadataFilterBuilder.metadataKey("author.id").isEqualTo(2L)

フィルタ値は、サポートされている比較値の型のいずれかである必要があります。 enum や日付/時刻の属性は、値そのもの、またはそのテキスト形式でフィルタリングできます。 ストアはそれを属性の型に変換します: enum 定数の名前、または LocalDate や Instant の ISO-8601 テキストです。

new IsEqualTo("status", Status.PUBLISHED)                                         // an enum attribute
new IsGreaterThan("publishedOn", LocalDate.of(2024, 1, 1)) // a LocalDate attribute
MetadataFilterBuilder.metadataKey("status").isEqualTo(Status.PUBLISHED.name()) // an enum attribute, as text
MetadataFilterBuilder.metadataKey("updatedAt").isLessThan("2024-03-15T10:00:00Z") // an Instant attribute, as text

あるいは、HibernateEmbeddingStore API は、型安全な Hibernate ORM の Restriction API を使用できる search メソッドも提供します。

HibernateEmbeddingStore<Book> embeddingStore = embeddingStore();
embeddingStore.search(
embedding,
Path.from(Book.class)
.to(Book_.details)
.to(BookDetails_.language)
.equalTo("English"));

または

HibernateEmbeddingStore<Book> embeddingStore = embeddingStore();
embeddingStore.search(
embedding,
Path.from(Book.class)
.to(Book_.author)
.to(Author_.id)
.equalTo(2L));

Hibernate を使用した完全な RAG 例​

このセクションでは、Hibernate 統合と PGVector 拡張機能付きの PostgreSQL を使用して、 セマンティック検索のための完全な Retrieval-Augmented Generation(RAG)システムを構築する方法を示します。

概要​

RAG システムは 2 つの主要なステージで構成されます。

  1. インデックス作成ステージ(オフライン): ドキュメントを読み込み、チャンクに分割し、埋め込みを生成して pgvector に保存
  2. 検索ステージ(オンライン): ユーザークエリを埋め込み、類似チャンクを検索し、コンテキストを LLM プロンプトに注入

前提条件​

PGVector 付きの PostgreSQL インスタンスが実行中であることを確認してください(上記の Docker セットアップを参照)。

1. ドキュメント取り込み(インデックス作成ステージ)​

この例では、ドキュメントを読み込み、チャンクに分割し、埋め込みを pgvector に保存する方法を示します。

import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
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.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;

import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument;

// Load document (PDF, TXT, etc.)
Document document = loadDocument("/path/to/document.pdf", new ApachePdfBoxDocumentParser());

// Split document into smaller chunks
// 300 tokens per chunk, 50 tokens overlap for context continuity
DocumentSplitter splitter = DocumentSplitters.recursive(300, 50);

// Create embedding model (384 dimensions for AllMiniLmL6V2)
EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();

// Create pgvector embedding store
HibernateEmbeddingStore embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
.databaseKind(DatabaseKind.POSTGRESQL)
.host("localhost")
.port(5432)
.database("postgres")
.user("my_user")
.password("my_password")
.table("document_embeddings")
.dimension(embeddingModel.dimension()) // 384 for AllMiniLmL6V2
.build();

// Ingest: split document, generate embeddings, and store in pgvector
EmbeddingStoreIngestor.builder()
.documentSplitter(splitter)
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build()
.ingest(document);

System.out.println("Document ingested successfully!");

2. クエリ(検索ステージ)​

この例では、ユーザーの質問で RAG システムをクエリする方法を示します。

import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;

import java.util.List;
import java.util.stream.Collectors;

// User's question
String question = "What is the refund policy?";

// Generate embedding for the question
Embedding questionEmbedding = embeddingModel.embed(question).content();

// Search for the most similar text segments (top 3 results)
EmbeddingSearchResult<TextSegment> result = embeddingStore.search(
EmbeddingSearchRequest.builder()
.queryEmbedding(questionEmbedding)
.maxResults(3) // Retrieve top 3 most similar chunks
.build()
);

// Build context from retrieved segments
String context = result.matches().stream()
.map(match -> match.embedded().text())
.collect(Collectors.joining("\n\n"));

// Create prompt with retrieved context
String promptWithContext = String.format("""
Answer the question based on the following context.
If the context doesn't contain relevant information, say "I don't have enough information to answer."

Context:
%s

Question: %s

Answer:
""", context, question);

// Send to LLM with context
ChatModel chatModel = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-6.1-sol")
.build();

String answer = chatModel.chat(promptWithContext);
System.out.println("Answer: " + answer);

本番環境での考慮事項​

実世界での使用に基づく、本番デプロイメント向けの重要な考慮事項を以下に示します。

1. コネクションプーリング​

本番環境では、個別の接続パラメータではなく、コネクションプーリング付きの DataSource を使用してください。

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres");
config.setUsername("my_user");
config.setPassword("my_password");
config.setMaximumPoolSize(10);

HikariDataSource dataSource = new HikariDataSource(config);

EmbeddingStore<TextSegment> embeddingStore = HibernateEmbeddingStore.dynamicDatasourceBuilder()
.databaseKind(DatabaseKind.POSTGRESQL)
.datasource(dataSource)
.table("document_embeddings")
.dimension(384)
.build();

2. インデックスの最適化​

大規模データセット(埋め込み数が 10 万超)では、クエリ性能を向上させるために PostgreSQL で IVFFlat インデックスを有効にしてください。

HibernateEmbeddingStore embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
// ... other config ...
.createIndex(true)
.indexOptions("lists = 100") // Adjust based on dataset size
.build();

注意: 大規模データセットでのインデックス作成には時間がかかることがあります。クエリ速度とインデックスビルド時間のバランスを取ってください。 注意: インデックスのメンテナンスはデータ取り込みを遅くする可能性があるため、大量のデータを取り込む際はインデックスを削除して再作成することを検討してください。

3. チャンクサイズの調整​

ユースケースに基づいて異なるチャンクサイズを試してください。

  • 小さいチャンク(200〜300 トークン): より高い精度、より具体的な回答
  • 大きいチャンク(500〜800 トークン): より多くのコンテキスト、ただし関連性が低下する可能性

4. エラーハンドリング​

データベース接続の失敗は常に適切に処理してください。

try {
embeddingStore.add(embedding, textSegment);
} catch (Exception e) {
logger.error("Failed to store embedding", e);
// Implement retry logic or fallback behavior
}

5. カスタム Hibernate エンティティの DDL​

カスタム Hibernate エンティティを使用する場合、DDL の管理はあなたが担当します。 インデックスを作成するために import.sql ファイルを作成することを検討してください。例(PostgreSQL):

create index if not exists my_entity_ivfflat_index 
on my_entity using ivfflat(embedding vector_cosine_ops) with (lists = 1);

SessionFactory の設定の詳細については、Hibernate ORM ドキュメント を参照してください。

他のデータベースのベクトルインデックスは、構文とオプションが異なります。詳細については、各データベースプロバイダーのドキュメントを参照してください。

DB2​

詳細については、ベクトルインデックスの記事 を参照してください。

create vector index my_entity_vector_index 
on my_entity(embedding) with distance cosine;
MariaDB​

詳細については、create index ステートメントのドキュメント を参照してください。

create vector index if not exists my_entity_vector_index 
on my_entity(embedding) distance=cosine;
MySQL​

MySQL HeatWave はインデックスを自動作成するため、手動でのインデックス作成は不要です。

PostgreSQL​

詳細については、pgvector ドキュメント を参照してください。

create index if not exists my_entity_ivfflat_index
on my_entity using ivfflat(embedding vector_cosine_ops) with (lists = 1);
CockroachDB​

詳細については、CockroachDB ドキュメント を参照してください。

create vector index if not exists my_entity_ivfflat_index
on my_entity (embedding vector_cosine_ops);
Oracle​

詳細については、create index ステートメントのドキュメント を参照してください。

create vector index my_entity_vector_index 
on my_entity(embedding) organization neighbor partitions with distance cosine;
SQL Server​

詳細については、create vector index ステートメントのドキュメント を参照してください。

create vector index my_entity_vector_index 
on my_entity(embedding) with (metric='cosine');
SAP HANA​

詳細については、create vector index ステートメントのドキュメント を参照してください。

create hnsw vector index my_entity_vector_index 
on my_entity(embedding) with similarity function cosine_similarity;

Hibernate NoSQL のセットアップ​

Hibernate NoSQL を使用すると、Hibernate ORM で NoSQL データベースを扱えます。 データベースごとに 1 つのアーティファクトが提供されており、LangChain4j もデータベースごとに対応するアーティファクトを 1 つ提供しています。 それぞれに必要なものがすべて含まれています。

各データベースの機能と制限、および JDBC URL の形式については、 Hibernate NoSQL のドキュメントを参照してください。

NoSQL データベースのデータベース種別は自動検出されないため、常に databaseKind() ビルダーメソッドに渡してください:

  • Milvus:langchain4j-hibernate-milvus アーティファクトの MilvusDatabaseKind.INSTANCE (パッケージ dev.langchain4j.store.embedding.hibernate.milvus)

Milvus​

import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.hibernate.HibernateEmbeddingStore;
import dev.langchain4j.store.embedding.hibernate.milvus.MilvusDatabaseKind;

EmbeddingStore<TextSegment> embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
.databaseKind(MilvusDatabaseKind.INSTANCE)
.host("localhost")
.port(19530)
.database("default")
.table("my_collection")
.dimension(384)
.createTable(true)
.build();

デフォルトでは、すべての検索で Milvus のセッション一貫性レベルが使用されます。検索では、アプリケーションがそれより前に 追加または削除したすべての埋め込みが見えますが、他のアプリケーションによる変更を待つことはありません。 別の取り込みジョブなど、他のアプリケーションが追加した埋め込みは、短い遅延の後に検索可能になります。

他のアプリケーションが直前に追加した埋め込みも検索で見える必要がある場合は、強い一貫性レベルを使用してください。 これにより、すべての検索にいくらかのレイテンシが加わります:

import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.hibernate.HibernateEmbeddingStore;
import dev.langchain4j.store.embedding.hibernate.milvus.MilvusDatabaseKind;
import java.util.Map;
import org.hibernate.jpa.HibernateHints;
import org.hibernate.milvus.MilvusDatabaseHints;

EmbeddingStore<TextSegment> embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
.databaseKind(MilvusDatabaseKind.INSTANCE)
.host("localhost")
.port(19530)
.database("default")
.table("my_collection")
.dimension(384)
.createTable(true)
.queryHints(Map.of(HibernateHints.HINT_QUERY_DATABASE, MilvusDatabaseHints.CONSISTENCY_LEVEL + "=STRONG"))
.build();

設定した HibernateHints.HINT_QUERY_DATABASE ヒントはデフォルトのヒントを置き換えるため、 希望する一貫性レベルを含めておく必要があります。

Milvus サーバーは認証なしで実行できます。その場合は、上記のように user() と password() を省略してください。

代わりに JDBC URL で接続するには、databaseKind(MilvusDatabaseKind.INSTANCE) とともに jdbcUrl() に渡します。 たとえば、jdbc:milvus://my-host:19530/default?secure=true は TLS で接続します。URL の形式とそのオプションについては、 Hibernate NoSQL のドキュメントで説明されています。

Milvus は、上記のリレーショナルデータベースとは次の点で異なります:

  • ベクトルインデックスはコレクションと同時に作成されます。 ダイナミックビルダーは、createIndex(true) がなくても、 常に距離関数のメトリックでインデックスを宣言します。Milvus は、距離関数がインデックスのメトリックと一致しない検索を 拒否するためです。createIndex(true) を指定すると、indexType() で Milvus のインデックスタイプを設定し、 indexOptions() で Milvus のインデックスパラメータを追加します:

    EmbeddingStore<TextSegment> embeddingStore = HibernateEmbeddingStore.dynamicBuilder()
    .databaseKind(MilvusDatabaseKind.INSTANCE)
    .host("localhost")
    .port(19530)
    .database("default")
    .table("my_collection")
    .dimension(384)
    .createIndex(true)
    .indexType("HNSW")
    .indexOptions("M=16,efConstruction=64")
    .createTable(true)
    .build();
  • サポートされる距離関数は COSINE(デフォルト)、INNER_PRODUCT、NEGATIVE_INNER_PRODUCT、 EUCLIDEAN です。 それ以外の距離関数では、ダイナミックビルダーは build() で失敗します。Milvus は HAMMING と JACCARD をバイナリベクトルでのみサポートしており、LangChain4j の埋め込みは float ベクトルです。

  • 独自のエンティティを使用する場合は、対応するメトリックでベクトルインデックスを宣言してください。 たとえば @Table(indexes = @Index(name = "my_entity_vector_index", columnList = "embedding", options = "metric=ip")) のようにして、 そのエンティティを HibernateEmbeddingStore.builder() に渡します。COSINE には metric=cosine、 INNER_PRODUCT と NEGATIVE_INNER_PRODUCT には metric=ip、EUCLIDEAN には metric=l2 を使用します。Milvus は、 距離関数がインデックスのメトリックと一致しない検索を拒否します。