Vektor Biner
Vektor biner adalah bentuk khusus representasi data yang mengubah vektor floating-point berdimensi tinggi tradisional menjadi vektor biner yang hanya berisi 0 dan 1. Transformasi ini tidak hanya memampatkan ukuran vektor tetapi juga mengurangi biaya penyimpanan dan komputasi dengan tetap mempertahankan informasi semantik. Ketika ketepatan untuk fitur yang tidak penting tidak diperlukan, vektor biner dapat secara efektif mempertahankan sebagian besar integritas dan kegunaan vektor floating-point asli.
Vektor biner memiliki berbagai macam aplikasi, terutama dalam situasi di mana efisiensi komputasi dan pengoptimalan penyimpanan sangat penting. Dalam sistem AI berskala besar, seperti mesin pencari atau sistem rekomendasi, pemrosesan data dalam jumlah besar secara real-time adalah kuncinya. Dengan mengurangi ukuran vektor, vektor biner membantu menurunkan latensi dan biaya komputasi tanpa mengorbankan akurasi secara signifikan. Selain itu, vektor biner berguna di lingkungan dengan sumber daya terbatas, seperti perangkat seluler dan sistem tertanam, di mana memori dan daya pemrosesan terbatas. Melalui penggunaan vektor biner, fungsi AI yang kompleks dapat diimplementasikan dalam pengaturan terbatas ini dengan tetap mempertahankan kinerja yang tinggi.
Gambaran Umum
Vektor biner adalah metode pengkodean objek kompleks (seperti gambar, teks, atau audio) ke dalam nilai biner dengan panjang tetap. Dalam Milvus, vektor biner biasanya direpresentasikan sebagai array bit atau array byte. Sebagai contoh, vektor biner 8 dimensi dapat direpresentasikan sebagai [1, 0, 1, 1, 0, 0, 1, 0].
Diagram di bawah ini menunjukkan bagaimana vektor biner merepresentasikan keberadaan kata kunci dalam konten teks. Dalam contoh ini, vektor biner 10 dimensi digunakan untuk merepresentasikan dua teks yang berbeda(Teks 1 dan Teks 2), di mana setiap dimensi sesuai dengan kata dalam kosakata: 1 menunjukkan keberadaan kata tersebut dalam teks, sedangkan 0 menunjukkan ketidakhadirannya.
Vektor Biner
Vektor biner memiliki karakteristik sebagai berikut:
Penyimpanan yang efisien: Setiap dimensi hanya membutuhkan 1 bit penyimpanan, sehingga secara signifikan mengurangi ruang penyimpanan.
Komputasi Cepat: Kemiripan antara vektor dapat dengan cepat dihitung menggunakan operasi bitwise seperti XOR.
Panjang Tetap: Panjang vektor tetap konstan terlepas dari panjang teks asli, sehingga memudahkan pengindeksan dan pengambilan.
Sederhana dan Intuitif: Secara langsung mencerminkan keberadaan kata kunci, sehingga cocok untuk tugas pengambilan khusus tertentu.
Vektor biner dapat dihasilkan melalui berbagai metode. Dalam pemrosesan teks, kosakata yang telah ditentukan sebelumnya dapat digunakan untuk mengatur bit yang sesuai berdasarkan keberadaan kata. Untuk pemrosesan gambar, algoritme hashing perseptual (seperti pHash) dapat menghasilkan fitur biner gambar. Dalam aplikasi pembelajaran mesin, keluaran model dapat dibinerisasi untuk mendapatkan representasi vektor biner.
Setelah vektorisasi biner, data dapat disimpan di Milvus untuk manajemen dan pengambilan vektor. Diagram di bawah ini menunjukkan proses dasarnya.
Menggunakan Vektor Biner
Meskipun vektor biner unggul dalam skenario tertentu, vektor biner memiliki keterbatasan dalam kemampuan ekspresifnya, sehingga sulit untuk menangkap hubungan semantik yang kompleks. Oleh karena itu, dalam skenario dunia nyata, vektor biner sering digunakan bersama jenis vektor lain untuk menyeimbangkan efisiensi dan ekspresifitas. Untuk informasi lebih lanjut, lihat Vektor Padat dan Vektor Jarang.
Menggunakan vektor biner
Menambahkan bidang vektor
Untuk menggunakan vektor biner di Milvus, pertama-tama tentukan bidang vektor untuk menyimpan vektor biner saat membuat koleksi. Proses ini meliputi:
Mengatur
datatypeke tipe data vektor biner yang didukung, misalnya,BINARY_VECTOR.Menentukan dimensi vektor menggunakan parameter
dim. Perhatikan bahwadimharus merupakan kelipatan 8 karena vektor biner harus dikonversi menjadi larik byte saat memasukkan. Setiap 8 nilai boolean (0 atau 1) akan dikemas ke dalam 1 byte. Sebagai contoh, jikadim=128, array 16 byte diperlukan untuk penyisipan.
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
}"
Pada contoh ini, sebuah bidang vektor bernama binary_vector ditambahkan untuk menyimpan vektor biner. Tipe data dari field ini adalah BINARY_VECTOR, dengan dimensi 128.
Mengatur parameter indeks untuk bidang vektor
Untuk mempercepat pencarian, indeks harus dibuat untuk bidang vektor biner. Pengindeksan dapat secara signifikan meningkatkan efisiensi pengambilan data vektor berskala besar.
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"
}
]'
Pada contoh di atas, indeks bernama binary_vector_index dibuat untuk bidang binary_vector, menggunakan jenis indeks AUTOINDEX. metric_type disetel ke HAMMING, yang menunjukkan bahwa jarak Hamming digunakan untuk pengukuran kemiripan.
Milvus menyediakan berbagai jenis indeks untuk pengalaman pencarian vektor yang lebih baik. AUTOINDEX adalah jenis indeks khusus yang dirancang untuk memperlancar kurva pembelajaran pencarian vektor. Ada banyak jenis indeks yang tersedia untuk Anda pilih. Untuk detailnya, lihat Penjelasan Indeks.
Selain itu, Milvus mendukung metrik kemiripan lainnya untuk vektor biner. Untuk informasi lebih lanjut, lihat Jenis Metrik.
Membuat koleksi
Setelah pengaturan vektor biner dan indeks selesai, buatlah sebuah koleksi yang berisi vektor-vektor biner. Contoh di bawah ini menggunakan metode create_collection untuk membuat koleksi bernama my_collection.
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" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
Menyisipkan data
Setelah membuat koleksi, gunakan metode insert untuk menambahkan data yang berisi vektor biner. Perhatikan bahwa vektor biner harus disediakan dalam bentuk larik byte, di mana setiap byte mewakili 8 nilai boolean.
Sebagai contoh, untuk vektor biner 128 dimensi, diperlukan larik 16 byte (karena 128 bit ÷ 8 bit/byte = 16 byte). Di bawah ini adalah contoh kode untuk memasukkan data:
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" \
--header "Request-Timeout: 10" \
-d "{
\"data\": $data,
\"collectionName\": \"my_collection\"
}"
Melakukan pencarian kemiripan
Pencarian kemiripan adalah salah satu fitur inti dari Milvus, yang memungkinkan Anda untuk dengan cepat menemukan data yang paling mirip dengan vektor kueri berdasarkan jarak antar vektor. Untuk melakukan pencarian kemiripan menggunakan vektor biner, siapkan vektor kueri dan parameter pencarian, lalu panggil metode search.
Selama operasi pencarian, vektor biner juga harus disediakan dalam bentuk larik byte. Pastikan dimensi vektor kueri sesuai dengan dimensi yang ditentukan saat mendefinisikan dim dan setiap 8 nilai boolean diubah menjadi 1 byte.
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" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"data\": $data,
\"annsField\": \"binary_vector\",
\"limit\": 5,
\"searchParams\":$searchParams,
\"outputFields\": [\"pk\"]
}"
Untuk informasi lebih lanjut tentang parameter pencarian kemiripan, lihat Pencarian ANN Dasar.