当前位置 : 首页 » 文章分类 :  开发  »  Milvus

Milvus

Milvus 开源向量相似度检索引擎,向量数据库

https://github.com/milvus-io/milvus


向量索引

https://milvus.io/cn/docs/v2.0.x/index.md

FLAT 无索引100%召回

FLAT 是指对向量进行原始文件存储,是唯一可以保证精确的检索结果的索引。FLAT 的结果也可以用于对照其他召回率低于 100% 的索引产生的结果。
对于每个查询,目标输入都要与数据集中的每个向量进行比较。

FLAT 是对向量的暴力搜索(brute-force search),速度最慢,但召回率最高(100%),磁盘空间占用最小。

IVF_FLAT 聚类

IVF_FLAT 索引通过聚类方法把空间里的点划分至 nlist 个单元,然后比较目标向量与所有单元中心的距离,选出 nprobe 个最近单元。然后比较这些被选中单元里的所有向量,得到最终的结果,极大地缩短了查询时间。
IVF_FLAT 索引不会对原始向量进行压缩,IVF_FLAT 索引文件的大小与原始数据文件大小相当。

建索引参数
nlist 聚类单元数,取值范围 [1, 65536]

查询参数
nq 输入向量个数
nprobe 查询取的单元数,取值范围 [1, 65536]

IVF_SQ8 聚类+压缩

IVF_SQ8 索引在 IVF_FLAT 基础上进行向量压缩。
IVF_SQ8 通过对向量进行标量量化(scalar quantization),能把原始向量中每个FLOAT(4 字节)转为UINT8(1 字节),从而可以把磁盘及内存、显存资源的消耗量减少为原来的 1/4 至 1/3。同样以 sift-1b 数据集为例,生成的 IVF_SQ8 索引文件只有 140 GB。


性能测试报告

https://milvus.io/docs/benchmark.md

100 万 128 维 SIFT 向量,建立 IVF_FLAT 索引,nlist=2048,1比n检索返回top1,入参 nprobe=16,并发检索,可达 440 qps、120 ms 平响
5000 万 128 维 SIFT 向量,建立 IVF_FLAT 索引,nlist=4096,1比n检索返回top1,入参 nprobe=16,并发检索,10个 query nodes 可达 90qps,216 ms 平响

百万512维,falt,(16c16g)*2,tp99 200ms,240qps
千万512维,flat,(16c32g)*2,tp99 2s,20qps
https://www.51cto.com/article/740699.html


距离计算方式

public enum MetricType {
    INVALID,
    // Only for float vectors
    L2,
    IP,
    COSINE,

    // Only for binary vectors
    HAMMING,
    JACCARD,
    ;
}

Milvus 使用示例

https://milvus.io/docs/manage-collections.md
https://milvus.io/docs/single-vector-search.md

@Test
public void test() {
    MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder().uri("http://localhost:19530").build());

    // 1.1、创建schema
    CreateCollectionReq.CollectionSchema schema = client.createSchema();
    // 1.2、向schema中添加字段
    schema.addField(AddFieldReq.builder()
                                .fieldName("my_id")
                                .dataType(DataType.Int64)
                                .isPrimaryKey(true)
                                .autoID(false)
                                .build());
    schema.addField(AddFieldReq.builder()
                                .fieldName("my_vector")
                                .dataType(DataType.FloatVector)
                                .dimension(1024)
                                .build());
    schema.addField(AddFieldReq.builder()
                                .fieldName("my_vector2")
                                .dataType(DataType.FloatVector)
                                .dimension(1024)
                                .build());

    // 2、创建collection
    // 可以同步创建collection和索引,创建后collection就是已加载状态。
    // 也可以分别创建collection和索引,创建后collection是未加载状态
    CreateCollectionReq customizedSetupReq1 = CreateCollectionReq.builder()
                                                                    .collectionName("customized_setup_1")
                                                                    .collectionSchema(schema)
                                                                    .numPartitions(3)
                                                                    .build();
    client.createCollection(customizedSetupReq1);

    // 3、创建索引
    IndexParam indexParamForIdField = IndexParam.builder()
                                                .fieldName("my_id")
                                                .indexType(IndexParam.IndexType.STL_SORT)
                                                .build();
    IndexParam indexParamForVectorField = IndexParam.builder()
                                                    .fieldName("my_vector")
                                                    .indexType(IndexParam.IndexType.FLAT)
                                                    .metricType(IndexParam.MetricType.COSINE)
                                                    .extraParams(Map.of("nlist", 1024))
                                                    .build();
    IndexParam indexParamForVectorField2 = IndexParam.builder()
                                                    .fieldName("my_vector2")
                                                    .indexType(IndexParam.IndexType.FLAT)
                                                    .metricType(IndexParam.MetricType.COSINE)
                                                    .extraParams(Map.of("nlist", 1024))
                                                    .build();
    List<IndexParam> indexParams = List.of(
            indexParamForIdField,
            indexParamForVectorField,
            indexParamForVectorField2
    );
    CreateIndexReq createIndexReq = CreateIndexReq.builder()
                                                    .collectionName("customized_setup_1")
                                                    .indexParams(indexParams)
                                                    .build();
    client.createIndex(createIndexReq);

    // 4、加载collection到内存
    LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
                                                            .collectionName("customized_setup_1")
                                                            .build();
    client.loadCollection(loadCollectionReq);
    // 获取collection的加载状态
    Boolean res = client.getLoadState(GetLoadStateReq.builder().collectionName("customized_setup_1").build());
    System.out.println("customized_setup_1 已加载: " + res);

    // 5、插入数据
    List<JSONObject> data = Arrays.asList(
            new JSONObject(Map.of("my_id", 0L, "my_vector", Arrays.asList(0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f), "color", "pink_8682")),
            new JSONObject(Map.of("my_id", 1L, "my_vector", Arrays.asList(0.19886812562848388f, 0.06023560599112088f, 0.6976963061752597f, 0.2614474506242501f, 0.838729485096104f), "color", "red_7025")),
            new JSONObject(Map.of("my_id", 2L, "my_vector", Arrays.asList(0.5718280481994695f, 0.24070317428066512f, -0.3737913482606834f, -0.06726932177492717f, -0.6980531615588608f), "color", "purple_4976"))
    );
    InsertReq insertReq = InsertReq.builder()
                                    .collectionName("customized_setup_1")
                                    .data(data)
                                    .build();
    InsertResp insertResp = client.insert(insertReq);

    // 6.1、1:N 向量搜索
    List<List<Float>> query_vectors = Arrays.asList(
            Arrays.asList(0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f));
    SearchReq searchReq = SearchReq.builder()
                                    .collectionName("customized_setup_1")
                                    .data(query_vectors)
                                    .topK(3) // The number of results to return
                                    .build();
    SearchResp searchResp = client.search(searchReq);

    // 6.2 M:N 向量搜索
    query_vectors = Arrays.asList(
            Arrays.asList(0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f),
            Arrays.asList(0.19886812562848388f, 0.06023560599112088f, 0.6976963061752597f, 0.2614474506242501f, 0.838729485096104f)
    );
    searchReq = SearchReq.builder()
                            .collectionName("customized_setup_1")
                            .data(query_vectors)
                            .topK(2)
                            .build();
    searchResp = client.search(searchReq);

    // 6.3 带标量过滤的向量搜索
    searchReq = SearchReq.builder()
                            .collectionName("customized_setup_1")
                            .data(query_vectors)
                            .outputFields(Arrays.asList("my_id", "my_vector"))
                            .filter("color_tag like \"red%\"") // like前缀匹配
                            .topK(5)
                            .build();

    searchResp = client.search(searchReq);

    // 7、从内存中释放collection
    ReleaseCollectionReq releaseCollectionReq = ReleaseCollectionReq.builder()
                                                                    .collectionName("customized_setup_2")
                                                                    .build();
    // 获取collection的加载状态
    res = client.getLoadState(GetLoadStateReq.builder().collectionName("customized_setup_1").build());
    System.out.println("customized_setup_1 已加载: " + res);
}

上一篇 2022年7月装机

下一篇 Arthas

阅读
评论
1.2k
阅读预计5分钟
创建日期 2022-07-08
修改日期 2024-07-08
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论