Milvus
Zilliz
Home
  • Benutzerhandbuch
  • Home
  • Docs
  • Benutzerhandbuch

  • Schema & Datenfelder

  • Binärer Vektor

Binärer Vektor

Binäre Vektoren sind eine besondere Form der Datendarstellung, bei der herkömmliche hochdimensionale Fließkomma-Vektoren in binäre Vektoren umgewandelt werden, die nur 0en und 1en enthalten. Durch diese Umwandlung wird nicht nur die Größe des Vektors komprimiert, sondern es werden auch die Speicher- und Rechenkosten reduziert, während die semantischen Informationen erhalten bleiben. Wenn die Genauigkeit für unkritische Merkmale nicht entscheidend ist, können binäre Vektoren die Integrität und den Nutzen der ursprünglichen Fließkomma-Vektoren weitgehend erhalten.

Binäre Vektoren haben ein breites Anwendungsspektrum, insbesondere in Situationen, in denen Berechnungseffizienz und Speicheroptimierung entscheidend sind. In groß angelegten KI-Systemen wie Suchmaschinen oder Empfehlungssystemen ist die Echtzeitverarbeitung großer Datenmengen von entscheidender Bedeutung. Durch die Verkleinerung der Vektoren tragen binäre Vektoren dazu bei, die Latenzzeit und die Rechenkosten zu senken, ohne die Genauigkeit wesentlich zu beeinträchtigen. Darüber hinaus sind Binärvektoren in ressourcenbeschränkten Umgebungen nützlich, wie z. B. bei mobilen Geräten und eingebetteten Systemen, wo Speicher und Verarbeitungsleistung begrenzt sind. Durch die Verwendung binärer Vektoren können komplexe KI-Funktionen in diesen eingeschränkten Umgebungen bei gleichbleibend hoher Leistung implementiert werden.

Überblick

Binäre Vektoren sind eine Methode zur Kodierung komplexer Objekte (wie Bilder, Text oder Audio) in binäre Werte fester Länge. In Milvus werden binäre Vektoren typischerweise als Bit- oder Byte-Arrays dargestellt. Zum Beispiel kann ein 8-dimensionaler Binärvektor als [1, 0, 1, 1, 0, 0, 1, 0] dargestellt werden.

Das folgende Diagramm zeigt, wie binäre Vektoren das Vorhandensein von Schlüsselwörtern in Textinhalten darstellen. In diesem Beispiel wird ein 10-dimensionaler Binärvektor verwendet, um zwei verschiedene Texte(Text 1 und Text 2) darzustellen, wobei jede Dimension einem Wort des Vokabulars entspricht: 1 bedeutet, dass das Wort im Text vorhanden ist, während 0 sein Fehlen anzeigt.

Binary Vector Binärer Vektor

Binäre Vektoren haben die folgenden Eigenschaften:

  • Effiziente Speicherung: Jede Dimension benötigt nur 1 Bit Speicherplatz, was den Speicherplatz erheblich reduziert.

  • Schnelle Berechnung: Die Ähnlichkeit zwischen Vektoren kann mit bitweisen Operationen wie XOR schnell berechnet werden.

  • Feste Länge: Die Länge des Vektors bleibt unabhängig von der ursprünglichen Textlänge konstant, was die Indizierung und das Auffinden erleichtert.

  • Einfach und intuitiv: Spiegelt direkt das Vorhandensein von Schlüsselwörtern wider und eignet sich daher für bestimmte spezialisierte Suchaufgaben.

Binäre Vektoren können durch verschiedene Methoden erzeugt werden. Bei der Textverarbeitung können vordefinierte Vokabulare verwendet werden, um entsprechende Bits auf der Grundlage des Vorhandenseins von Wörtern zu setzen. Bei der Bildverarbeitung können Wahrnehmungs-Hashing-Algorithmen (wie pHash) binäre Merkmale von Bildern erzeugen. Bei Anwendungen des maschinellen Lernens können die Modellausgaben binarisiert werden, um binäre Vektordarstellungen zu erhalten.

Nach der binären Vektorisierung können die Daten in Milvus zur Verwaltung und zum Abruf der Vektoren gespeichert werden. Das folgende Diagramm zeigt den grundlegenden Prozess.

Use Binary Vector Binäre Vektoren verwenden

Obwohl sich binäre Vektoren in bestimmten Szenarien hervorragend eignen, sind sie in ihrer Aussagekraft eingeschränkt, so dass es schwierig ist, komplexe semantische Beziehungen zu erfassen. Daher werden in realen Szenarien häufig binäre Vektoren zusammen mit anderen Vektortypen verwendet, um ein Gleichgewicht zwischen Effizienz und Aussagekraft zu erreichen. Weitere Informationen finden Sie unter Dense Vector und Sparse Vector.

Binäre Vektoren verwenden

Vektorfeld hinzufügen

Um binäre Vektoren in Milvus zu verwenden, definieren Sie zunächst ein Vektorfeld zum Speichern von binären Vektoren, wenn Sie eine Sammlung erstellen. Dieser Prozess beinhaltet:

  1. Einstellung von datatype auf den unterstützten binären Vektordatentyp, d.h. BINARY_VECTOR.

  2. Angeben der Dimensionen des Vektors mit dem Parameter dim. Beachten Sie, dass dim ein Vielfaches von 8 sein muss, da binäre Vektoren beim Einfügen in ein Byte-Array umgewandelt werden müssen. Alle 8 booleschen Werte (0 oder 1) werden in 1 Byte gepackt. Wenn zum Beispiel dim=128 verwendet wird, ist ein 16-Byte-Array für das Einfügen erforderlich.

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema(
    auto_id=True,
    enable_dynamic_fields=True,
)

schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
schema.add_field(field_name="binary_vector", datatype=DataType.BINARY_VECTOR, dim=128)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);
schema.addField(AddFieldReq.builder()
        .fieldName("pk")
        .dataType(DataType.VarChar)
        .isPrimaryKey(true)
        .autoID(true)
        .maxLength(100)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("binary_vector")
        .dataType(DataType.BinaryVector)
        .dimension(128)
        .build());
import { DataType } from "@zilliz/milvus2-sdk-node";

schema.push({
  name: "binary vector",
  data_type: DataType.BinaryVector,
  dim: 128,
});
import (
    "context"
    "fmt"

    "github.com/milvus-io/milvus/client/v2/column"
    "github.com/milvus-io/milvus/client/v2/entity"
    "github.com/milvus-io/milvus/client/v2/index"
    "github.com/milvus-io/milvus/client/v2/milvusclient"
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

milvusAddr := "localhost:19530"
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
    Address: milvusAddr,
})
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
defer client.Close(ctx)

schema := entity.NewSchema()
schema.WithField(entity.NewField().
    WithName("pk").
    WithDataType(entity.FieldTypeVarChar).
    WithIsAutoID(true).
    WithIsPrimaryKey(true).
    WithMaxLength(100),
).WithField(entity.NewField().
    WithName("binary_vector").
    WithDataType(entity.FieldTypeBinaryVector).
    WithDim(128),
)
export primaryField='{
    "fieldName": "pk",
    "dataType": "VarChar",
    "isPrimary": true,
    "elementTypeParams": {
        "max_length": 100
    }
}'

export vectorField='{
    "fieldName": "binary_vector",
    "dataType": "BinaryVector",
    "elementTypeParams": {
        "dim": 128
    }
}'

export schema="{
    \"autoID\": true,
    \"fields\": [
        $primaryField,
        $vectorField
    ],
    \"enableDynamicField\": true
}"

In diesem Beispiel wird ein Vektorfeld mit dem Namen binary_vector zum Speichern von binären Vektoren hinzugefügt. Der Datentyp dieses Feldes ist BINARY_VECTOR, mit einer Dimension von 128.

Setzen von Indexparametern für das Vektorfeld

Um die Suche zu beschleunigen, muss ein Index für das binäre Vektorfeld erstellt werden. Die Indexierung kann die Abfrageeffizienz von großen Vektordaten erheblich verbessern.

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="binary_vector",
    index_name="binary_vector_index",
    index_type="AUTOINDEX",
    metric_type="HAMMING"
)
import io.milvus.v2.common.IndexParam;
import java.util.*;

List<IndexParam> indexParams = new ArrayList<>();
Map<String,Object> extraParams = new HashMap<>();

indexParams.add(IndexParam.builder()
        .fieldName("binary_vector")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.HAMMING)
        .build());
import { MetricType, IndexType } from "@zilliz/milvus2-sdk-node";

const indexParams = {
  indexName: "binary_vector_index",
  field_name: "binary_vector",
  metric_type: MetricType.HAMMING,
  index_type: IndexType.AUTOINDEX
};
idx := index.NewAutoIndex(entity.HAMMING)
indexOption := milvusclient.NewCreateIndexOption("my_collection", "binary_vector", idx)
export indexParams='[
        {
            "fieldName": "binary_vector",
            "metricType": "HAMMING",
            "indexName": "binary_vector_index",
            "indexType": "AUTOINDEX"
        }
    ]'

Im obigen Beispiel wird ein Index mit dem Namen binary_vector_index für das Feld binary_vector erstellt, wobei der Indextyp AUTOINDEX verwendet wird. metric_type ist auf HAMMING gesetzt, was anzeigt, dass die Hamming-Distanz für die Ähnlichkeitsmessung verwendet wird.

Milvus bietet verschiedene Indexarten für eine bessere Vektorsuche. AUTOINDEX ist ein spezieller Indextyp, der entwickelt wurde, um die Lernkurve der Vektorsuche zu glätten. Sie können aus einer Vielzahl von Index-Typen wählen. Einzelheiten finden Sie unter Index erklärt.

Außerdem unterstützt Milvus andere Ähnlichkeitsmetriken für binäre Vektoren. Weitere Informationen finden Sie unter Metrik-Typen.

Sammlung erstellen

Sobald die Einstellungen für binäre Vektoren und Indizes abgeschlossen sind, erstellen Sie eine Sammlung, die binäre Vektoren enthält. Das folgende Beispiel verwendet die Methode create_collection, um eine Sammlung mit dem Namen my_collection zu erstellen.

client.create_collection(
    collection_name="my_collection",
    schema=schema,
    index_params=index_params
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_collection")
        .collectionSchema(schema)
        .indexParams(indexParams)
        .build();
client.createCollection(requestCreate);
import { MilvusClient } from "@zilliz/milvus2-sdk-node";

const client = new MilvusClient({
    address: 'http://localhost:19530'
});

await client.createCollection({
    collection_name: 'my_collection',
    schema: schema,
    index_params: indexParams
});
err = client.CreateCollection(ctx,
    milvusclient.NewCreateCollectionOption("my_collection", schema).
        WithIndexOptions(indexOption))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"collectionName\": \"my_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

Daten einfügen

Nachdem Sie die Sammlung erstellt haben, fügen Sie mit der Methode insert Daten hinzu, die binäre Vektoren enthalten. Beachten Sie, dass binäre Vektoren in Form eines Byte-Arrays bereitgestellt werden sollten, wobei jedes Byte für 8 boolesche Werte steht.

Für einen 128-dimensionalen Binärvektor ist beispielsweise ein 16-Byte-Array erforderlich (da 128 Bits ÷ 8 Bits/Byte = 16 Bytes). Im Folgenden finden Sie einen Beispielcode zum Einfügen von Daten:

def convert_bool_list_to_bytes(bool_list):
    if len(bool_list) % 8 != 0:
        raise ValueError("The length of a boolean list must be a multiple of 8")

    byte_array = bytearray(len(bool_list) // 8)
    for i, bit in enumerate(bool_list):
        if bit == 1:
            index = i // 8
            shift = i % 8
            byte_array[index] |= (1 << shift)
    return bytes(byte_array)

bool_vectors = [
    [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0] + [0] * 112,
    [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1] + [0] * 112,
]

data = [{"binary_vector": convert_bool_list_to_bytes(bool_vector) for bool_vector in bool_vectors}]

client.insert(
    collection_name="my_collection",
    data=data
)
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

private static byte[] convertBoolArrayToBytes(boolean[] booleanArray) {
    byte[] byteArray = new byte[booleanArray.length / Byte.SIZE];
    for (int i = 0; i < booleanArray.length; i++) {
        if (booleanArray[i]) {
            int index = i / Byte.SIZE;
            int shift = i % Byte.SIZE;
            byteArray[index] |= (byte) (1 << shift);
        }
    }

    return byteArray;
}

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
{
    boolean[] boolArray = {true, false, false, true, true, false, true, true, false, true, false, false, true, true, false, true};
    JsonObject row = new JsonObject();
    row.add("binary_vector", gson.toJsonTree(convertBoolArrayToBytes(boolArray)));
    rows.add(row);
}
{
    boolean[] boolArray = {false, true, false, true, false, true, false, false, true, true, false, false, true, true, false, true};
    JsonObject row = new JsonObject();
    row.add("binary_vector", gson.toJsonTree(convertBoolArrayToBytes(boolArray)));
    rows.add(row);
}

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("my_collection")
        .data(rows)
        .build());
const data = [
  { binary_vector: [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1] },
  { binary_vector: [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1] },
];

client.insert({
  collection_name: "my_collection",
  data: data,
});
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithBinaryVectorColumn("binary_vector", 128, [][]byte{
        {0b10011011, 0b01010100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {0b10011011, 0b01010101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    }))
if err != nil {
    fmt.Println(err.Error())
    // handle err
}
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"data\": $data,
    \"collectionName\": \"my_collection\"
}"

Die Ähnlichkeitssuche ist eine der Hauptfunktionen von Milvus, die es Ihnen ermöglicht, schnell Daten zu finden, die einem Abfragevektor am ähnlichsten sind, basierend auf dem Abstand zwischen den Vektoren. Um eine Ähnlichkeitssuche mit binären Vektoren durchzuführen, bereiten Sie den Abfragevektor und die Suchparameter vor und rufen dann die Methode search auf.

Während der Suchoperationen müssen die binären Vektoren auch in Form eines Byte-Arrays bereitgestellt werden. Stellen Sie sicher, dass die Dimensionalität des Abfragevektors mit der bei der Definition von dim angegebenen Dimension übereinstimmt und dass alle 8 booleschen Werte in 1 Byte konvertiert werden.

search_params = {
    "params": {"nprobe": 10}
}

query_bool_list = [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0] + [0] * 112
query_vector = convert_bool_list_to_bytes(query_bool_list)

res = client.search(
    collection_name="my_collection",
    data=[query_vector],
    anns_field="binary_vector",
    search_params=search_params,
    limit=5,
    output_fields=["pk"]
)

print(res)

# Output
# data: ["[{'id': '453718927992172268', 'distance': 10.0, 'entity': {'pk': '453718927992172268'}}]"] 
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.BinaryVec;
import io.milvus.v2.service.vector.response.SearchResp;

Map<String,Object> searchParams = new HashMap<>();
searchParams.put("nprobe",10);

boolean[] boolArray = {true, false, false, true, true, false, true, true, false, true, false, false, true, true, false, true};
BinaryVec queryVector = new BinaryVec(convertBoolArrayToBytes(boolArray));

SearchResp searchR = client.search(SearchReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(queryVector))
        .annsField("binary_vector")
        .searchParams(searchParams)
        .topK(5)
        .outputFields(Collections.singletonList("pk"))
        .build());
        
 System.out.println(searchR.getSearchResults());
 
 // Output
 //
 // [[SearchResp.SearchResult(entity={pk=453444327741536775}, score=0.0, id=453444327741536775), SearchResp.SearchResult(entity={pk=453444327741536776}, score=7.0, id=453444327741536776)]]
query_vector = [1,0,1,0,1,1,1,1,1,1,1,1];

client.search({
    collection_name: 'my_collection',
    data: query_vector,
    limit: 5,
    output_fields: ['pk'],
    params: {
        nprobe: 10
    }
});
queryVector := []byte{0b10011011, 0b01010100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

annSearchParams := index.NewCustomAnnParam()
annSearchParams.WithExtraParam("nprobe", 10)
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "my_collection", // collectionName
    5,                      // limit
    []entity.Vector{entity.BinaryVector(queryVector)},
).WithANNSField("binary_vector").
    WithOutputFields("pk").
    WithAnnParam(annSearchParams))
if err != nil {
    fmt.Println(err.Error())
    // handle err
}

for _, resultSet := range resultSets {
    fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
    fmt.Println("Scores: ", resultSet.Scores)
    fmt.Println("Pks: ", resultSet.GetColumn("pk").FieldData().GetScalars())
}
export searchParams='{
        "params":{"nprobe":10}
    }'

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"collectionName\": \"my_collection\",
    \"data\": $data,
    \"annsField\": \"binary_vector\",
    \"limit\": 5,
    \"searchParams\":$searchParams,
    \"outputFields\": [\"pk\"]
}"

Weitere Informationen zu Parametern für die Ähnlichkeitssuche finden Sie unter Grundlegende ANN-Suche.

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

War diese Seite hilfreich?