Desain Model Data untuk Pencarian

Sistem Pencarian Informasi, yang juga dikenal sebagai mesin pencari, sangat penting untuk berbagai aplikasi AI seperti Retrieval-augmented generation (RAG), pencarian visual, dan rekomendasi produk. Inti dari sistem ini adalah model data yang dirancang dengan cermat untuk mengatur, mengindeks, dan mengambil informasi.

Milvus memungkinkan Anda untuk menentukan model data pencarian melalui skema koleksi, mengatur data yang tidak terstruktur, representasi vektor yang padat atau jarang, dan metadata terstruktur. Baik Anda bekerja dengan teks, gambar, atau tipe data lainnya, panduan praktis ini akan membantu Anda memahami dan menerapkan konsep-konsep skema utama untuk mendesain model data pencarian dalam praktiknya.

Data Model Anatomy Anatomi Model Data

Model Data

Desain model data sistem pencarian melibatkan analisis kebutuhan bisnis dan abstraksi informasi ke dalam model data yang diekspresikan dengan skema. Skema yang terdefinisi dengan baik penting untuk menyelaraskan model data dengan tujuan bisnis, memastikan konsistensi data dan kualitas layanan. Selain itu, memilih tipe data dan indeks yang tepat juga penting dalam mencapai tujuan bisnis secara ekonomis.

Menganalisis Kebutuhan Bisnis

Mengatasi kebutuhan bisnis secara efektif dimulai dengan menganalisis jenis pertanyaan yang akan dilakukan pengguna dan menentukan metode pencarian yang paling sesuai.

  • Pertanyaan Pengguna: Identifikasi jenis kueri yang diharapkan dilakukan pengguna. Hal ini membantu memastikan skema Anda mendukung kasus penggunaan di dunia nyata dan mengoptimalkan kinerja penelusuran. Hal ini mungkin termasuk:

    • Mengambil dokumen yang cocok dengan kueri bahasa alami

    • Menemukan gambar yang mirip dengan gambar referensi atau mencocokkan deskripsi teks

    • Mencari produk berdasarkan atribut seperti nama, kategori, atau merek

    • Memfilter item berdasarkan metadata terstruktur (misalnya, tanggal publikasi, tag, peringkat)

    • Menggabungkan beberapa kriteria dalam kueri hibrida (misalnya, dalam penelusuran visual, dengan mempertimbangkan kemiripan semantik gambar dan keterangannya)

  • Metode Pencarian: Pilih teknik penelusuran yang sesuai dengan jenis kueri yang akan dilakukan pengguna. Metode yang berbeda memiliki tujuan yang berbeda dan sering kali dapat digabungkan untuk mendapatkan hasil yang lebih baik:

    • Pencarian semantik: Menggunakan kemiripan vektor yang padat untuk menemukan item dengan makna yang sama, ideal untuk data yang tidak terstruktur seperti teks atau gambar.

    • Pencarian teks lengkap: Melengkapi pencarian semantik dengan pencocokan kata kunci. Pencarian teks lengkap dapat menggunakan analisis leksikal untuk menghindari pemecahan kata yang panjang menjadi token-token yang terfragmentasi, dan memahami istilah-istilah khusus selama pencarian.

    • Penyaringan metadata: Di atas pencarian vektor, menerapkan batasan seperti rentang tanggal, kategori, atau tag.

Menerjemahkan Persyaratan Bisnis ke dalam Model Data Pencarian

Langkah berikutnya adalah menerjemahkan kebutuhan bisnis Anda ke dalam model data konkret, dengan mengidentifikasi komponen inti informasi Anda dan metode pencariannya:

  • Tentukan data yang perlu Anda simpan, seperti konten mentah (teks, gambar, audio), metadata terkait (judul, tag, kepengarangan), dan atribut kontekstual (stempel waktu, perilaku pengguna, dll.)

  • Tentukan jenis dan format data yang sesuai untuk setiap elemen. Sebagai contoh:

    • Deskripsi teks → string

    • Penyematan gambar atau dokumen → vektor padat atau jarang

    • Kategori, tag, atau bendera → string, larik, dan bool

    • Atribut numerik seperti harga atau peringkat → bilangan bulat atau float

    • Informasi terstruktur seperti detail penulis -> json

Definisi yang jelas dari elemen-elemen ini memastikan konsistensi data, hasil pencarian yang akurat, dan kemudahan integrasi dengan logika aplikasi hilir.

Desain Skema

Di Milvus, model data diekspresikan melalui skema koleksi. Merancang bidang yang tepat dalam skema koleksi adalah kunci untuk memungkinkan pengambilan yang efektif. Setiap bidang mendefinisikan jenis data tertentu yang disimpan dalam koleksi dan memainkan peran yang berbeda dalam proses pencarian. Pada tingkat tinggi, Milvus mendukung dua jenis field utama: field vektor dan field skalar.

Sekarang, Anda dapat memetakan model data Anda ke dalam skema bidang, termasuk vektor dan bidang skalar tambahan. Pastikan bahwa setiap field berkorelasi dengan atribut dari model data Anda, terutama memperhatikan tipe vektor (dense atau spase) dan dimensinya.

Bidang Vektor

Bidang vektor menyimpan penyematan untuk tipe data yang tidak terstruktur seperti teks, gambar, dan audio. Penyematan ini dapat berupa padat, jarang, atau biner, tergantung pada tipe data dan metode pengambilan yang digunakan. Biasanya, vektor padat digunakan untuk pencarian semantik, sedangkan vektor jarang lebih cocok untuk pencocokan teks atau leksikal. Vektor biner berguna ketika penyimpanan dan sumber daya komputasi terbatas. Sebuah koleksi dapat berisi beberapa bidang vektor untuk memungkinkan strategi pencarian multi-modal atau hibrida. Untuk panduan terperinci tentang topik ini, silakan lihat Pencarian Hibrida Multi-Vektor.

Milvus mendukung tipe data vektor: FLOAT_VECTOR untuk Dense Vector, SPARSE_FLOAT_VECTOR untuk Sparse Vector, dan BINARY_VECTOR untuk Binary Vector

Bidang Skalar

Bidang skalar menyimpan nilai primitif dan terstruktur - biasanya disebut sebagai metadata - seperti angka, string, atau tanggal. Nilai-nilai ini dapat dikembalikan bersama hasil pencarian vektor dan sangat penting untuk pemfilteran dan penyortiran. Nilai ini memungkinkan Anda mempersempit hasil pencarian berdasarkan atribut tertentu, seperti membatasi dokumen pada kategori tertentu atau rentang waktu tertentu.

Milvus mendukung tipe skalar seperti BOOL, INT8/16/32/64, FLOAT, DOUBLE, VARCHAR, JSON, dan ARRAY untuk menyimpan dan memfilter data non-vektor. Tipe-tipe ini meningkatkan ketepatan dan penyesuaian operasi pencarian.

Memanfaatkan Fitur Canggih dalam Desain Skema

Ketika mendesain skema, hanya memetakan data Anda ke bidang menggunakan tipe data yang didukung tidaklah cukup. Sangat penting untuk memiliki pemahaman menyeluruh tentang hubungan antar bidang dan strategi yang tersedia untuk konfigurasi. Dengan mengingat fitur-fitur utama selama fase desain, memastikan bahwa skema tidak hanya memenuhi persyaratan penanganan data langsung, tetapi juga dapat diskalakan dan diadaptasi untuk kebutuhan di masa depan. Dengan mengintegrasikan fitur-fitur ini secara hati-hati, Anda dapat membangun arsitektur data yang kuat yang memaksimalkan kemampuan Milvus dan mendukung strategi dan tujuan data Anda yang lebih luas. Berikut ini adalah ikhtisar fitur-fitur utama yang membuat skema koleksi:

Kunci Utama

Field kunci utama adalah komponen fundamental dari skema, karena secara unik mengidentifikasi setiap entitas dalam koleksi. Mendefinisikan kunci primer adalah wajib. Ini harus berupa bidang skalar dengan tipe integer atau string dan ditandai sebagai is_primary=True. Secara opsional, Anda dapat mengaktifkan auto_id untuk kunci primer, yang secara otomatis diberi nomor integer yang secara monolitik bertambah seiring dengan bertambahnya data yang dimasukkan ke dalam koleksi.

Untuk rincian lebih lanjut, lihat Bidang Utama & AutoID.

Pemilahan

Untuk mempercepat pencarian, Anda dapat mengaktifkan partisi secara opsional. Dengan menetapkan bidang skalar tertentu untuk pemartisian dan menentukan kriteria pemfilteran berdasarkan bidang ini selama pencarian, cakupan pencarian dapat secara efektif dibatasi hanya pada partisi yang relevan. Metode ini secara signifikan meningkatkan efisiensi operasi pengambilan dengan mengurangi domain pencarian.

Untuk rincian lebih lanjut, lihat Menggunakan Kunci Partisi.

Penganalisis

Penganalisis adalah alat penting untuk memproses dan mengubah data teks. Fungsi utamanya adalah mengubah teks mentah menjadi token dan menyusunnya untuk pengindeksan dan pengambilan. Hal ini dilakukan dengan melakukan tokenisasi string, membuang kata-kata yang tidak perlu, dan membendung kata-kata individual menjadi token.

Untuk detail lebih lanjut, lihat Tinjauan Umum Penganalisis.

Fungsi

Milvus memungkinkan Anda untuk mendefinisikan fungsi bawaan sebagai bagian dari skema untuk secara otomatis mendapatkan bidang tertentu. Sebagai contoh, Anda dapat menambahkan fungsi BM25 bawaan yang menghasilkan vektor jarang dari bidang VARCHAR untuk mendukung pencarian teks lengkap. Bidang yang diturunkan dari fungsi ini menyederhanakan prapemrosesan dan memastikan bahwa koleksi tetap berdiri sendiri dan siap untuk kueri.

Untuk rincian lebih lanjut, lihat Pencarian Teks Lengkap.

Contoh Dunia Nyata

Pada bagian ini, kami akan menguraikan desain skema dan contoh kode untuk aplikasi pencarian dokumen multimedia yang ditunjukkan pada diagram di atas. Skema ini dirancang untuk mengelola kumpulan data yang berisi artikel dengan pemetaan data ke bidang-bidang berikut:

Bidang

Sumber Data

Digunakan Oleh Metode Pencarian

Primary Key

Kunci Partisi

Penganalisis

Fungsi Masukan / Keluaran

article_id (INT64)

dibuat secara otomatis dengan diaktifkan auto_id

Kueri menggunakan Get

Y

N

N

N

judul (VARCHAR)

judul artikel

Pencocokan Teks

N

N

Y

N

stempel waktu (INT32)

tanggal penerbitan

Filter berdasarkan Kunci Partisi

N

Y

N

N

teks (VARCHAR)

teks mentah dari artikel

Pencarian Hibrida Multi-Vektor

N

N

Y

masukan

text_dense_vector (FLOAT_VECTOR)

vektor padat yang dihasilkan oleh model penyematan teks

Pencarian Vektor Dasar

N

N

N

N

text_sparse_vector (SPARSE_FLOAT_VECTOR)

vektor jarang yang dihasilkan secara otomatis oleh fungsi BM25 bawaan

Pencarian Teks Lengkap

N

N

N

keluaran

Untuk informasi lebih lanjut tentang skema dan panduan terperinci tentang cara menambahkan berbagai jenis bidang, silakan lihat Penjelasan Skema.

Menginisialisasi skema

Untuk memulai, kita perlu membuat skema kosong. Langkah ini menetapkan struktur dasar untuk mendefinisikan model data.

from pymilvus import MilvusClient

schema = MilvusClient.create_schema()
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

// 1. Connect to Milvus server
ConnectConfig connectConfig = ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build();

MilvusClientV2 client = new MilvusClientV2(connectConfig);

// 2. Create an empty schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

//Skip this step using JavaScript
import "github.com/milvus-io/milvus/client/v2/entity"

schema := entity.NewSchema()
# Skip this step using cURL

Menambahkan bidang

Setelah skema dibuat, langkah selanjutnya adalah menentukan bidang yang akan menjadi bagian dari data Anda. Setiap field diasosiasikan dengan tipe data dan atributnya masing-masing.

from pymilvus import DataType

schema.add_field(field_name="article_id", datatype=DataType.INT64, is_primary=True, auto_id=True, description="article id")
schema.add_field(field_name="title", datatype=DataType.VARCHAR, enable_analyzer=True, enable_match=True, max_length=200, description="article title")
schema.add_field(field_name="timestamp", datatype=DataType.INT32, description="publish date")
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=2000, enable_analyzer=True, description="article text content")
schema.add_field(field_name="text_dense_vector", datatype=DataType.FLOAT_VECTOR, dim=768, description="text dense vector")
schema.add_field(field_name="text_sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR, description="text sparse vector")
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;

schema.addField(AddFieldReq.builder()
        .fieldName("article_id")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .autoID(true)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("title")
        .dataType(DataType.VarChar)
        .maxLength(200)
        .enableAnalyzer(true)
        .enableMatch(true)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("timestamp")
        .dataType(DataType.Int32)
        .build())
schema.addField(AddFieldReq.builder()
        .fieldName("text")
        .dataType(DataType.VarChar)
        .maxLength(2000)
        .enableAnalyzer(true)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("text_dense_vector")
        .dataType(DataType.FloatVector)
        .dimension(768)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("text_sparse_vector")
        .dataType(DataType.SparseFloatVector)
        .build());
const fields = [
    {
        name: "article_id",
        data_type: DataType.Int64,
        is_primary_key: true,
        auto_id: true
    },
    {
        name: "title",
        data_type: DataType.VarChar,
        max_length: 200,
        enable_analyzer: true,
        enable_match: true
    },
    {
        name: "timestamp",
        data_type: DataType.Int32
    },
    {
        name: "text",
        data_type: DataType.VarChar,
        max_length: 2000,
        enable_analyzer: true
    },
    {
        name: "text_dense_vector",
        data_type: DataType.FloatVector,
        dim: 768
    },
    {
        name: "text_sparse_vector",
        data_type: DataType.SparseFloatVector
    }
]
schema.WithField(entity.NewField().
    WithName("article_id").
    WithDataType(entity.FieldTypeInt64).
    WithIsPrimaryKey(true).
    WithIsAutoID(true).
    WithDescription("article id"),
).WithField(entity.NewField().
    WithName("title").
    WithDataType(entity.FieldTypeVarChar).
    WithMaxLength(200).
    WithEnableAnalyzer(true).
    WithEnableMatch(true).
    WithDescription("article title"),
).WithField(entity.NewField().
    WithName("timestamp").
    WithDataType(entity.FieldTypeInt32).
    WithDescription("publish date"),
).WithField(entity.NewField().
    WithName("text").
    WithDataType(entity.FieldTypeVarChar).
    WithMaxLength(2000).
    WithEnableAnalyzer(true).
    WithDescription("article text content"),
).WithField(entity.NewField().
    WithName("text_dense_vector").
    WithDataType(entity.FieldTypeFloatVector).
    WithDim(768).
    WithDescription("text dense vector"),
).WithField(entity.NewField().
    WithName("text_sparse_vector").
    WithDataType(entity.FieldTypeSparseVector).
    WithDescription("text sparse vector"),
)
export fields='[
    {
        "fieldName": "article_id",
        "dataType": "Int64",
        "isPrimary": true
    },
    {
        "fieldName": "title",
        "dataType": "VarChar",
        "elementTypeParams": {
            "max_length": 200,
            "enable_analyzer": true,
            "enable_match": true
        }
    },
    {
        "fieldName": "timestamp",
        "dataType": "Int32"
    },
    {
       "fieldName": "text",
       "dataType": "VarChar",
       "elementTypeParams": {
            "max_length": 2000,
            "enable_analyzer": true
        }
    },
    {
       "fieldName": "text_dense_vector",
       "dataType": "FloatVector",
       "elementTypeParams": {
            "dim": 768
        }
    },
    {
       "fieldName": "text_sparse_vector",
       "dataType": "SparseFloatVector",
    }
]'

export schema="{
    \"autoID\": true,
    \"fields\": $fields
}"

Dalam contoh ini, atribut-atribut berikut ini ditentukan untuk field:

  • Primary key: article_id digunakan sebagai primary key yang memungkinkan pengalokasian primary key secara otomatis untuk entitas yang masuk.

  • Kunci partisi: timestamp ditetapkan sebagai kunci partisi yang memungkinkan pemfilteran berdasarkan partisi. Hal ini dapat berupa

  • Penganalisis teks: penganalisis teks diterapkan pada 2 bidang string title dan text untuk mendukung pencocokan teks dan pencarian teks lengkap.

(Opsional) Menambahkan fungsi

Untuk meningkatkan kemampuan kueri data, fungsi dapat dimasukkan ke dalam skema. Sebagai contoh, sebuah fungsi dapat dibuat untuk memproses yang terkait dengan bidang tertentu.

from pymilvus import Function, FunctionType

bm25_function = Function(
    name="text_bm25",
    input_field_names=["text"],
    output_field_names=["text_sparse_vector"],
    function_type=FunctionType.BM25,
)

schema.add_function(bm25_function)
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.service.collection.request.CreateCollectionReq.Function;

import java.util.*;

schema.addFunction(Function.builder()
        .functionType(FunctionType.BM25)
        .name("text_bm25")
        .inputFieldNames(Collections.singletonList("text"))
        .outputFieldNames(Collections.singletonList("text_sparse_vector"))
        .build());
import FunctionType from "@zilliz/milvus2-sdk-node";

const functions = [
    {
      name: 'text_bm25',
      description: 'bm25 function',
      type: FunctionType.BM25,
      input_field_names: ['text'],
      output_field_names: ['text_sparse_vector'],
      params: {},
    },
];
function := entity.NewFunction().
    WithName("text_bm25").
    WithInputFields("text").
    WithOutputFields("text_sparse_vector").
    WithType(entity.FunctionTypeBM25)
schema.WithFunction(function)
export myFunctions='[
    {
        "name": "text_bm25",
        "type": "BM25",
        "inputFieldNames": ["text"],
        "outputFieldNames": ["text_sparse_vector"],
        "params": {}
    }
]'

export schema="{
    \"autoID\": true,
    \"fields\": $fields
    \"functions\": $myFunctions
}"

Contoh ini menambahkan fungsi BM25 bawaan di dalam skema, memanfaatkan bidang text sebagai masukan dan menyimpan vektor jarang yang dihasilkan di bidang text_sparse_vector.

Langkah selanjutnya