关键概念
在探索 Milvus Java SDK 的功能之前,我们先来了解一下 Milvus 是如何逻辑地组织数据的:
- Collection:存储向量的逻辑容器,类似传统数据库中的表
- 字段Field:集合内标量和矢量实体的属性,定义数据类型和其他属性
- 模式Schema:定义集合内数据的结构和属性
- 索引Index:通过组织向量来优化搜索过程,以实现高效检索
- 分区Partition:集合内的逻辑细分,用于更有效地管理和组织数据
先决条件
在探索 Java API 之前,我们将先了解运行示例代码的一些先决条件。
Milvus 数据库实例
首先,我们需要一个 Milvus DB 实例。最简单、最快捷的方法是获取Zilliz Cloud提供的完全托管的免费 Milvus DB 实例:
为此,我们需要注册一个 Zilliz 云帐户并按照文档创建一个免费的 DB 集群。
Maven 依赖
在开始探索 Milvus Java API 之前,我们需要导入必要的Maven 依赖项:
<dependency> |
Milvus Java 客户端 SDK
Milvus DB 服务端点是使用 gRPC 框架编写的。因此,所有使用不同编程语言(如 Python、Go 和 Java)的客户端 SDK 都在此 gRPC 框架之上提供 API。Milvus Java 客户端 SDK 像任何数据库一样全面支持 CRUD(创建、读取、更新和删除)操作。此外,它还支持管理操作,例如创建集合、索引和分区。为了执行各种 DB 操作,API 提供了相应的请求和请求构建器类。开发人员可以使用构建器类在请求对象中设置必要的参数。最后,在客户端类的帮助下将此请求对象发送到后端服务。在我们阅读完接下来的部分后,这将变得更加清晰。
创建 Milvus DB 客户端
Java 客户端 SDK 提供了MilvusClientV2类,用于 Milvus DB 中的管理和数据操作。ConnectConfigBuilder类帮助构建父类ConnectConfig ,该类保存了创建MilvusClientV2类实例所需的连接信息。
我们来看一下创建MilvusClientV2实例的方法,以进一步了解所涉及的类:
MilvusClientV2 createConnection() { |
ConnectConfig类支持用户名和密码验证,但我们使用了推荐的 API 令牌。 ConnectConfigBuilder类采用 URI 和 API 令牌来创建ConnectConfig对象。稍后将使用该对象创建MilvusClientV2对象。
创建Collection
在将数据存储到 Milvus Vector DB 之前,我们必须创建一个集合。这涉及创建字段架构和集合,然后形成创建集合请求对象。最后,客户端将请求对象发送到 DB 服务端点以在 Milvus DB 中创建集合。
创建字段架构和集合架构
我们先来了解一下 Milvus Java SDK 中的相关关键类:
FieldSchema类帮助定义集合的字段,而CollectionSchema使用FieldSchema来定义集合。此外,IndexParam中的IndexParamBuilder类在集合上创建索引。我们将通过示例代码探索其他类。首先,让我们来看看在createFieldSchema()方法中创建FieldSchema对象的步骤:
CreateCollectionReq.FieldSchema createFieldSchema(String name, String desc, DataType dataType, |
FieldSchema类中的builder ()方法返回其子FieldSchemaBuilder类的实例。此类设置集合字段的重要属性,例如名称、说明和数据类型。builder类中的方法isPrimaryKey()有助于标记主键字段,而FieldSchema类中的setDimension()方法设置向量字段的强制维度。例如,让我们在方法createFieldSchemas()中设置名为Books的集合的字段:
private static List<CreateCollectionReq.FieldSchema> createFieldSchemas() { |
该方法返回Books 集合的book_id、book_name和book_vector字段的FieldSchema对象列表。book_vector字段存储维度为5 的向量, book_id为主键。确切地说,我们将书籍的矢量化文本存储在 book_vector 字段中。每个FieldSchema对象都是使用前面定义的createFieldSchema()方法创建的。创建FieldSchema对象后,我们将在createCollectionSchema()方法中使用它们来形成Books CollectionSchema对象:
private static CreateCollectionReq.CollectionSchema createCollectionSchema( |
子CollectionSchemaBuilder设置字段模式并最终构建父CollectionSchema对象。
创建收款请求并收款
现在让我们看看创建该集合的步骤:
void whenCommandCreateCollectionInVectorDB_thenSuccess() { |
}
我们使用CreateCollectionReqBuilder类通过设置CollectionSchema对象和其他参数来构建CreateCollectionReq对象,然后将此对象传递给MilvusClientV2类的createCollection()方法创建集合,最后通过调用MilvusClientV2的hasCollection(HasCollectionReq)方法进行验证。CreateCollectionReqBuilder类还使用indexParams()方法在book_vector字段上定义索引。
IndexParam createIndexParam(String fieldName, String indexName) { |
该方法使用IndexParamBuilder类来设置Milvus DB 中索引所支持的各项属性。此外, IndexPram对象的COSINE度量类型属性对于计算向量之间的相似度得分非常重要。与关系型数据库一样,索引有助于提升 Milvus Vector DB 中频繁访问字段的查询性能。
创建分区
一旦创建了Books集合,我们就可以专注于创建分区的类,以便有效地组织数据。
子类CreatePartitionReqBuilder帮助创建父类CreateParitionReq对象,设置分区和目标集合名称。然后,将请求对象传入MilvusClientV2的createPartition()方法中。
让我们使用前面定义的类在Books集合中创建一个分区Health :
void whenCommandCreatePartitionInCollection_thenSuccess() { |
在该方法中,createPartitionReqBuilder类为Books集合创建CreatePartitionReq对象。随后,MilvusClientV2对象使用请求对象调用其createPartition()方法。这导致在Books集合中创建分区 Health 。最后,我们通过调用MilvusClientV2类的hasPartition()方法来验证分区是否存在。
将数据插入集合
在 Milvus DB 中创建好Books集合之后,我们就可以向其中插入数据了。
- 子类InsertReqBuilder通过设置collectionName和数据来帮助创建其父类InsertReq对象。
- InsertReqBuilder类的方法data()将List
中的文档块插入到 Milvus DB 中。 - 最后,我们将InsertReq对象传递给MilvusClientV2对象的insert()方法,以在集合中创建条目。
为了将数据插入到集合Books的分区Health中,我们将使用 JSON 文件book_vectors.json中的一些虚拟数据:
[ |
实际应用程序使用 BERT 和 Word2Vec 等嵌入模型来创建文本、图像、语音样本等的向量维度。让我们实际看一下之前定义的类:
void whenCommandInsertDataIntoVectorDB_thenSuccess() throws IOException { |
readJsonObjectsFromFile ()方法从 JSON 文件中读取数据并存入bookJsons对象中。如前所述,我们用数据创建了InsertReq对象,然后将其传递给MilvusClientV2对象的insert()方法。最后,InsertResp对象中的getInsertCnt()方法给出了插入的记录总数。我们也可以在 Zilliz 云端控制台中验证插入的记录:
执行向量相似性搜索
Milvus 借助一些关键类支持对集合进行向量相似性搜索
SearchRequestBuilder设置了父类SearchReq的 topK 近邻、查询嵌入和集合名称等属性。此外,我们可以在filter()方法中设置标量表达式来获取匹配的实体。最后,MilvusClientV2类使用SearchReq对象调用search ( )方法来获取记录。
和往常一样,让我们看一下示例代码以了解更多信息:
void givenSearchVector_whenCommandSearchDataFromCollection_thenSuccess() { |
首先,方法getQueryEmbedding()将查询转换为向量维度或嵌入。然后SearchReqBuilder对象使用所有与搜索相关的参数创建SearchReq对象。有趣的是,我们还可以通过在构建器类的outputFields()方法中设置来控制结果实体中的字段名称。最后,我们调用MilvusClientV2的search()方法获取查询结果:
book_id: 6, book_name: Yoga, distance: 0.8046049 |
搜索结果中的距离属性表示相似度得分。在我们的示例中,我们考虑使用余弦相似度 (COSINE) 来衡量相似度得分。因此,余弦越大,两个向量之间的角度越小,表明这两个向量彼此更相似。此外,Milvus 在浮点类型嵌入上支持更多度量类型,例如欧几里得距离 (L2) 和内积 (IP)。
删除集合中的数据
让我们从通常的类图开始,来了解从集合中删除数据所涉及的关键类.
MilvusClientV2中的 delete() 方法删除Milvus DB 中的记录。它采用DeleteReq对象,允许使用ids和filter字段指定记录。子类DeleteRequestBuilder帮助构建父类DeleteReq对象。
让我们借助一些示例代码来深入了解。让我们看看从Books集合中删除book_id等于 1 和 2 的记录的步骤:
void givenListOfIds_whenCommandDeleteDataFromCollection_thenSuccess() { |
在MilvusClientV2对象上调用delete()方法后,我们使用DeleteResp对象中的getDeleteCnt()方法来验证删除的记录数。我们还可以使用DeleteReqBuilder对象上的filter()方法与标量表达式规则结合使用来指定要删除的匹配记录:
void givenFilterCondition_whenCommandDeleteDataFromCollection_thenSuccess() { |
根据filter()方法中定义的标量条件,从集合中删除book_id大于 4的记录。
结论
在本文中,我们探索了 Milvus Java SDK。它涵盖了与管理向量数据库相关的几乎所有主要操作。这些 API 设计精良且直观易懂,因此更易于采用和构建 AI 驱动的应用程序。但是,对向量的基本了解对于有效使用 API 也同样重要。