PostgreSQL [Aplicativo 01] usa o plug-in Vector para implementar consulta de similaridade vetorial (Instruções para instalação do plug-in pgvector para PostgreSQL implantado pelo Docker) e comparação com a biblioteca de vetores Milvus

Ferramenta de consulta de similaridade

1. Fundo

Caso queira implementar uma função de busca por similaridade de vetores de características, o projeto é desenvolvido em Java e o banco de dados é PostgreSQL. As opções disponíveis são:

  • Banco de dados vetorial - Milvus é fácil de implantar, com interface visual Attu e JavaSDK (mas requer implantação especial).
  • Plug-in PostgreSQL (Cube suporta 100 dimensões, Pase suporta 512 dimensões e Vector suporta 16.000 dimensões).

Como o vetor de características da imagem extraída tem 1024 dimensões, apenas o Milvus e o plug-in Vector do PostgreSQL podem ser usados.

2.Aplicação

2.1 pipa

O site oficial do Milvus tem um processo de instalação detalhado e um código que não entrarei em detalhes aqui. Use o Docker para instalá-lo. A versão é. 2.2.9Aqui fornecemos uma classe de ferramenta simples. Os parâmetros de conexão do banco de dados não são parametrizados. Os amigos podem otimizar e simplificar os dados do resultado. Formatação:

Encapsulamento de resultado:

@Data
@Builder
public class MilvusRes {
    
    
    public float score;
    public String imagePath;
}

Ferramentas:

@Slf4j
@Component
public class MilvusUtil {
    
    
    public MilvusServiceClient milvusServiceClient;
    @PostConstruct
    private void connectToServer() {
    
    
        milvusServiceClient = new MilvusServiceClient(
                ConnectParam.newBuilder()
                        .withHost("your service host")
                        .withPort(19530)
                        .build());
        // 加载数据
        LoadCollectionParam faceSearchNewLoad = LoadCollectionParam.newBuilder().withCollectionName("CollectionName").build();
        R<RpcStatus> rpcStatusR = milvusServiceClient.loadCollection(faceSearchNewLoad);
        log.info("Milvus LoadCollection [{}]", rpcStatusR.getStatus());

    }

    public int insertDataToMilvus(String id, String path, float[] feature) {
    
    
        List<InsertParam.Field> fields = new ArrayList<>();
        List<Float> featureList = new ArrayList<>(feature.length);
        for (float v : feature) {
    
    
            featureList.add(v);
        }
        fields.add(new InsertParam.Field("field1", Collections.singletonList(id)));
        fields.add(new InsertParam.Field("field2", Collections.singletonList(path)));
        fields.add(new InsertParam.Field("field3", Collections.singletonList(featureList)));

        InsertParam insertParam = InsertParam.newBuilder()
                .withCollectionName("CollectionName")
                //.withPartitionName("novel")
                .withFields(fields)
                .build();
        R<MutationResult> insert = milvusServiceClient.insert(insertParam);
        return insert.getStatus();
    }

    public List<MilvusRes> searchImageByFeature(float[] feature) {
    
    
        List<Float> featureList = new ArrayList<>(feature.length);
        for (float v : feature) {
    
    
            featureList.add(v);
        }
        List<String> queryOutputFields = Arrays.asList("field");
        SearchParam faceSearch = SearchParam.newBuilder()
                .withCollectionName("CollectionName")
                .withMetricType(MetricType.IP)
                .withVectorFieldName("VectorFieldName")
                .withVectors(Collections.singletonList(featureList))
                .withOutFields(queryOutputFields)
                .withTopK(10).build();
        // 执行搜索
        long l = System.currentTimeMillis();
        R<SearchResults> respSearch = milvusServiceClient.search(faceSearch);
        log.info("MilvusServiceClient.search cost [{}]", System.currentTimeMillis() - l);
        // 解析结果数据
        SearchResultData results = respSearch.getData().getResults();
        int scoresCount = results.getScoresCount();
        SearchResultsWrapper wrapperSearch = new SearchResultsWrapper(results);
        List<MilvusRes> milvusResList = new ArrayList<>();
        for (int i = 0; i < scoresCount; i++) {
    
    
            float score = wrapperSearch.getIDScore(0).get(i).getScore();
            Object imagePath = wrapperSearch.getFieldData("field1", 0).get(i);
            MilvusRes milvusRes = MilvusRes.builder().score(score).imagePath(imagePath.toString()).build();
            milvusResList.add(milvusRes);
        }
        return milvusResList;
    }
}

A quantidade é conforme mostrado na imagem:

Insira a descrição da imagem aqui

Os resultados do teste de desempenho são os seguintes:

MilvusServiceClient.search cost [24]

2.2 Vetor

As informações básicas são explicadas nos sites a seguir, por isso não entrarei em detalhes aqui.

O banco de dados PostgreSQL é implantado usando Docker e a versão é 12.12. O processo de instalação do plug-in é o seguinte:

# 进入容器
docker exec -it CONTAINER ID /bin/bash

# 1.更新 apt-get 
apt-get update
# 未更新直接安装会报错
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package postgresql-12-postgis-3
E: Unable to locate package postgresql-12-postgis-3-dbgsym
E: Unable to locate package postgresql-12-postgis-3-scripts

# 2.安装插件
apt-get install postgresql-12-pgvector

Operações de banco de dados:

-- 添加 vector 扩展
CREATE EXTENSION vector;

-- 查询可使用的扩展
SELECT * FROM pg_available_extensions;

-- 创建表
CREATE TABLE "public"."test" ( 
  "field1" VARCHAR ( 64 ), 
  "field2" VARCHAR ( 128 ), 
  "field3" vector ( 1024 ), 
  CONSTRAINT "test_pkey" PRIMARY KEY ( "field1" ) 
);

Ao criar um índice, siga o algoritmo utilizado:

-- 创建索引
CREATE INDEX ON test USING ivfflat ( field3);
CREATE INDEX ON test USING ivfflat ( field3 vector_ip_ops) WITH (lists = 50);
CREATE INDEX ON test USING ivfflat ( field3 vector_ip_ops) WITH (lists = 500);
CREATE INDEX ON test USING ivfflat ( field3 vector_ip_ops) WITH (lists = 1024);

Aqui está um método para escrever SQL em um arquivo mapeador [consultar as dez principais semelhanças]:

    <select id="queryId" resultType="map">
        SELECT
        field1,
        field2,
        field3 <![CDATA[ <#> ]]> CAST ( #{featrue}  AS vector ) AS "score"
        FROM test
        ORDER BY field1 <![CDATA[ <#> ]]> CAST ( #{featrue}  AS vector )
        LIMIT 10;
    </select>

Descrição do símbolo:

  1. Distância L2 (<->): A distância L2, também conhecida como distância euclidiana ou distância euclidiana, é usada para medir a distância em linha reta entre dois vetores. A distância L2 é calculada somando os quadrados das diferenças entre os elementos correspondentes de dois vetores e, em seguida, extraindo a raiz quadrada. Uma distância L2 menor indica que os vetores estão mais próximos uns dos outros.
  2. Produto interno (<#>): A distância do produto interno, também conhecida como distância do cosseno ou similaridade do produto interno, é usada para medir o valor do cosseno do ângulo entre dois vetores. A distância do produto interno é calculada como o produto escalar de dois vetores dividido pelo produto das normas dos dois vetores. Quanto maior for a distância do produto interno, menor será o ângulo entre os vetores e maior será a similaridade.
  3. Distância do cosseno (<=>): Distância do cosseno, também conhecida como complemento da similaridade do cosseno. A distância cosseno é um índice de distância que mede o ângulo entre dois vetores. O valor varia de 0 a 2, onde 0 significa completamente semelhante e 2 significa completamente diferente. A distância do cosseno é calculada como o produto escalar de dois vetores dividido pelo complemento do produto das normas dos dois vetores.

O teste de desempenho é o seguinte:

PostgreSQL.vector.search cost [30]

3. Resumo

Cada um tem suas próprias vantagens: Milvus não precisa reconstruir o índice e a velocidade de consulta é mais rápida; Vector não requer implantação especial e é fácil de manter.

Acho que você gosta

Origin blog.csdn.net/weixin_39168541/article/details/131482197
Recomendado
Clasificación