[nodejs] milvus nodejs实践

388 阅读6分钟

前言

最近我在学习向量数据库相关的知识。一开始我对向量数据库的概念并不清楚,因此开通了火山的 VikingDB。没想到在摸索了很久后,最终却等来了欠费通知,真是让人哭笑不得0v0。。。经过各种搜索,我才发现了 Milvus 这个开源的好东西,哈哈哈!

这里附上[Milvus](https://milvus.io/)的官网,有兴趣深入了解的小伙伴可以自行去官网查看文档。下面是我学习 Milvus 的一些过程和心得~

第一步

去官网下载 Milvus 的安装包,并在本机安装。我安装的是 Milvus Standalone Docker 版本。

image.png 在官网的这个地方,运行这两条命令即可进行安装并启动

# Download the installation script
curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh

# Start the Docker container
bash standalone_embed.sh start

运行安装脚本后

  • 一个名为 Milvus 的 docker 容器已在19530 端口启动。 image.png
  • 至此,milvus学习的第一步,安装milvus 已经完成✅!

虽然成功安装了 Milvus,但由于缺少可视化界面,直接操作可能会显得有些抽象和不直观。为了解决这个问题,推荐大家安装一款名为 Attu 的工具。Attu 是一个专为 Milvus 设计的开源可视化界面,能够让我们更直观地查看向量数据库的结构及其内容。

通过 Attu,你可以轻松完成以下操作:

  1. 浏览集合:查看数据库中的集合结构及其字段定义。
  2. 查看数据:直接查看存储的向量及其相关信息。
  3. 运行查询:通过界面执行搜索或查询操作,无需书写复杂的代码。
  4. 监控状态:监控 Milvus 集群的运行状态和资源使用情况。

安装和使用 Attu 可以极大提升对 Milvus 的理解和使用效率,尤其对于初学者来说,能够更快上手。推荐在搭建 Milvus 环境后立即安装 Attu,让管理和操作向量数据库更加直观、高效。 这里附上attu的下载链接,大家有需要可自行下载;

下载完成后,连接到启动在 Docker 上的 Milvus。由于我是在本地启动 Docker,因此 IP 地址为 127.0.0.1。请大家根据自己的实际情况设置相应的 IP 地址。需注意的是,我提前创建了一个名为 test 的数据库,而下载完成后默认的数据库是 default

image.png 点击连接后,即可进入到milvus的默认界面,随即,可以创建一个数据库,这里我偷个懒,我已经创建好了一个test数据库,这样就不用通过代码去创建数据库了。实际业务操作中,感觉也很少会通过代码去生成一个数据库。

image.png

至此,我们创建好了一个名为test的数据库。


接下来,让我们进入代码环节,整个流程如下:

  1. 创建集合
  2. 插入数据
  3. 对向量字段添加索引
  4. 加载集合
  5. 进行相似查询

让我们开始吧!

一、创建集合

安装 Milvus node.js SDK

npm install @zilliz/milvus2-sdk-node

通过 MilvusClient 连接 Milvus。Milvus 提供多种连接方式,例如使用用户名和密码、服务器地址等。由于我安装的是 Milvus Standalone Docker 版本,因此连接时只需提供服务器地址即可。

首先创建一个名为createCollection.js的文件,然后创建 MilvusClient。通过检查 connectStatus 字段,我们可以确认连接是否成功。

const milvusClient = new MilvusClient({
    address: '127.0.0.1:19530',
});
console.log("Connection status: " + milvusClient.connectStatus)

输出结果如下所示:

Connection status: 1

接下来通过milvusClient.use()设定使用的db, 这里写刚刚我们自己创建的db即可。

await milvusClient.use({ db_name: 'test' });

再接下来,通过milvusClient.createCollection()创建一个名为集合collection_name,代码如下:

const create = await milvusClient.createCollection({
    collection_name: 'sample_collection',
    fields: [
        {
            name: 'id',              // 字段名
            description: 'ID field', // 字段描述
            data_type: DataType.Int64, // 数据类型为 Int64
            is_primary_key: true,     // 设置为主键
            autoID: true,             // 自动生成 ID
        },
        {
            name: 'vector',
            description: 'Vector field', // 字段描述
            data_type: DataType.FloatVector, // 数据类型为浮点向量
            dim: 8,                     // 向量维度为 8
        },
        {
            name: 'height',
            description: 'int64 field', // 字段描述
            data_type: DataType.Int64,  // 数据类型为 Int64
        },
        {
            name: 'age',
            description: 'int64 field', // 字段描述
            data_type: DataType.Int32,  // 数据类型为 Int64
        },
        {
            name: 'name',
            description: 'VarChar field', // 字段描述
            data_type: DataType.VarChar,  // 数据类型为字符串
            max_length: 128,              // 最大长度为 128
        },
    ],
});
// 可以使用 describeCollection 方法来获取指定集合的详细信息
const describeCollection = await milvusClient.describeCollection({ collection_name: 'sample_collection'});

console.log('describe collection', describeCollection);

通过运行

node createCollection.js 

输出打印信息如下

image.png

至此一个名为sample_collection的集合已被创建,此时,通过attu可以看到被创建的集合,如下图所示:

image.png

二、插入数据

使用 milvusClient.insert() 方法可以将向量化数据插入到集合中。首先,我们需要准备一组向量数据,然后将其插入到指定的集合中。请注意,确保设置正确的数据库和集合。以下是完整代码示例:

import { MilvusClient } from '@zilliz/milvus2-sdk-node';

async function insertData() {
    try {
        const milvusClient = new MilvusClient({
            address: 'localhost:19530',
        });
        console.log('Connection status: ' + milvusClient.connectStatus);

        const useDb = await milvusClient.use({ db_name: 'test' });
        console.log('New Database is using:', useDb);

        const vectorsData = [
            {
                vector: [
                    0.11878310581111173, 0.9694947902934701, 0.16443679307243175,
                    0.5484226189097237, 0.9839246709011924, 0.5178387104937776,
                    0.8716926129208069, 0.5616972243831446,
                ],
                height: 20405,
                age:1,
                name: 'zlnmh',
            },
            {
                vector: [
                    0.9992090731236536, 0.8248790611809487, 0.8660083940881405,
                    0.09946359318481224, 0.6790698063908669, 0.5013786801063624,
                    0.795311915725105, 0.9183033261617566,
                ],
                height: 93773,
                age:2,
                name: '5lr9y',
            },
            {
                vector: [
                    0.8761291569818763, 0.07127366044153227, 0.775648976160332,
                    0.5619757601304878, 0.6076543120476996, 0.8373907516027586,
                    0.8556140171597648, 0.4043893119391049,
                ],
                height: 85122,
                age:3,
                name: 'nes0j',
            },
            {
                vector: [
                    0.5849602436079879, 0.5108258101682586, 0.8250884731578105,
                    0.7996354835509332, 0.8207766774911736, 0.38133662902290566,
                    0.7576720055508186, 0.4393152967662368,
                ],
                height: 92037,
                age:4,
                name: 'ct2li',
            },
            {
                vector: [
                    0.3768133716738886, 0.3823259261020866, 0.7906232829855262,
                    0.31693696726284193, 0.3731715403499176, 0.3300751870649885,
                    0.22353556137796238, 0.38062799545615444,
                ],
                height: 31400,
                age:5,
                name: '6ghrg',
            },
            {
                vector: [
                    0.0007531778212483964, 0.12941566118774994, 0.9340164428788116,
                    0.3795768837758642, 0.4532443258064389, 0.596455163143,
                    0.9529469158782906, 0.7692465408044873,
                ],
                height: 1778,
                age:6,
                name: 'sb7mt',
            },
        ];

        const params = {
            collection_name: 'sample_collection',
            fields_data: vectorsData,
        };

        // 插入数据到集合中
        const insert = await milvusClient.insert(params);
        console.log('Inserted data:', insert);
    } catch (error) {
        console.error('Error occurred:', error);
    }
}

// 调用插入数据的函数
insertData();

执行脚本后,可以看到插入的结果如下,即表示插入成功。

image.png


此时我们虽然插入了数据,但是由于向量字段vector没有添加索引,因此我们在attu中是无法看到数据的,即使我们点击加载数据时,也会提示请保证所有向量列都有索引

image.png

因此,接下来,我们需要给向量列添加索引。

三、对向量字段添加索引

通过milvusClient.createIndex()vector字段添加索引,代码如下

const createIndex = await milvusClient.createIndex({
    collection_name: 'sample_collection',
    field_name: 'vector',
    metric_type: 'L2',
});

运行代码后,我们完成了对vector字段的索引添加,接下来,我们可以进行数据的加载了。

四、加载集合

加载集合,我们可以通过attu可视化界面加载,即:

image.png

或者我们可以通过代码milvusClient.loadCollectionSync()进行集合的加载,加载完成后,我们即可在attu上看到我们刚刚插入的数据。

image.png

五、进行相似查询

通过milvusClient.search(),我们可以进行向量相似性搜索,代码如下:

const search = await milvusClient.search({
    collection_name: 'sample_collection', // 查询的集合名
    vector: [1,2,3,4,5,6,7,8],            // 查询的目标向量
    filter: 'age > 0',                    // 过滤条件
    output_fields: ['name', 'age'],       // 返回的字段
    limit: 5,                             // 返回的结果数量限制 topK K = 5
});

运行代码后,即可输出相似性结果,结果根据score升序输出,score越大表示相似度越高,结果如下:

image.png

  • 至此,milvus的相似性搜索已完成,我们可以拿到对应的数据去做下一步的处理操作啦~

代码源码milvus-demo(如果觉得写的可以的话,麻烦给个star哦)

参考文档:速看!Milvus JavaScript 客户端入门级使用指南