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
页面信息
location:protocol: host: hostname: origin: pathname: href: document:referrer: navigator:platform: userAgent: