Ikhtisar Bidang JSON

Ketika membangun aplikasi seperti katalog produk, sistem manajemen konten, atau mesin preferensi pengguna, Anda sering kali perlu menyimpan metadata yang fleksibel di samping penyematan vektor. Atribut produk bervariasi berdasarkan kategori, preferensi pengguna berkembang dari waktu ke waktu, dan properti dokumen memiliki struktur bersarang yang kompleks. Bidang JSON di Milvus mengatasi tantangan ini dengan memungkinkan Anda menyimpan dan meminta data terstruktur yang fleksibel tanpa mengorbankan kinerja.

Apa yang dimaksud dengan bidang JSON?

Bidang JSON adalah tipe data yang ditentukan skema (DataType.JSON) di Milvus yang menyimpan data nilai-kunci terstruktur. Tidak seperti kolom basis data tradisional yang kaku, field JSON mengakomodasi objek bersarang, array, dan tipe data campuran sambil menyediakan beberapa opsi pengindeksan untuk kueri cepat.

Contoh struktur bidang JSON:

{
  "metadata": { 
    "category": "electronics",
    "brand": "BrandA",
    "in_stock": true,
    "price": 99.99,
    "string_price": "99.99",
    "tags": ["clearance", "summer_sale"],
    "supplier": {
      "name": "SupplierX",
      "country": "USA",
      "contact": {
        "email": "support@supplierx.com",
        "phone": "+1-800-555-0199"
      }
    }
  }
}

Dalam contoh ini, metadata adalah bidang JSON tunggal yang berisi campuran nilai datar (misalnya category, in_stock), larik (tags), dan objek bersarang (supplier).

Konvensi penamaan: Gunakan hanya huruf, angka, dan garis bawah pada kunci JSON. Hindari karakter khusus, spasi, atau titik karena dapat menyebabkan masalah penguraian dalam kueri.

Bidang JSON vs bidang dinamis

Hal yang sering membingungkan adalah perbedaan antara field JSON dan field dinamis. Meskipun keduanya terkait dengan JSON, keduanya memiliki tujuan yang berbeda.

Tabel di bawah ini merangkum perbedaan utama antara field JSON dan field dinamis:

Fitur

Bidang JSON

Bidang Dinamis

Definisi skema

Bidang skalar yang harus dideklarasikan secara eksplisit di dalam skema koleksi dengan tipe DataType.JSON.

Bidang JSON tersembunyi (bernama $meta) yang secara otomatis menyimpan bidang yang tidak dideklarasikan.

Kasus penggunaan

Menyimpan data terstruktur yang skemanya diketahui dan konsisten.

Menyimpan data yang fleksibel, berkembang, atau semi-terstruktur yang tidak sesuai dengan skema tetap.

Kontrol

Anda mengontrol nama dan struktur bidang.

Dikelola sistem untuk bidang yang tidak ditentukan.

Kueri

Kueri menggunakan nama bidang atau kunci target di dalam bidang JSON: metadata["key"].

Kueri secara langsung menggunakan kunci bidang dinamis: "dynamic_key" atau melalui $meta: $meta["dynamic_key"]

Operasi dasar

Alur kerja dasar untuk menggunakan bidang JSON melibatkan pendefinisiannya di dalam skema Anda, memasukkan data, dan kemudian melakukan kueri data dengan menggunakan ekspresi filter tertentu.

Mendefinisikan bidang JSON

Untuk menggunakan bidang JSON, tentukan secara eksplisit dalam skema koleksi Anda saat membuat koleksi. Contoh berikut ini menunjukkan cara membuat koleksi dengan bidang metadata bertipe DataType.JSON:

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530") # Replace with your server address 

# Create schema
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)

schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True) # Primary field
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5) # Vector field
# Define a JSON field that allows null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)

client.create_collection(
    collection_name="product_catalog",
    schema=schema
)

Dalam contoh ini, bidang JSON yang ditetapkan dalam skema koleksi memungkinkan nilai null dengan nullable=True. Untuk detailnya, lihat Nullable & Default.

Menyisipkan data

Setelah koleksi dibuat, masukkan entitas yang berisi objek JSON terstruktur di bidang JSON yang Anda tentukan. Data Anda harus diformat sebagai daftar kamus.

entities = [
    {
        "product_id": 1,
        "vector": [0.1, 0.2, 0.3, 0.4, 0.5],
        "metadata": { # JSON field
            "category": "electronics",
            "brand": "BrandA",
            "in_stock": True,
            "price": 99.99,
            "string_price": "99.99",
            "tags": ["clearance", "summer_sale"],
            "supplier": {
                "name": "SupplierX",
                "country": "USA",
                "contact": {
                    "email": "support@supplierx.com",
                    "phone": "+1-800-555-0199"
                }
            }
        }
    }
]

client.insert(collection_name="product_catalog", data=entities)

Operasi pemfilteran

Sebelum Anda dapat melakukan operasi pemfilteran pada bidang JSON, pastikan:

  • Anda telah membuat indeks pada setiap bidang vektor.

  • Koleksi dimuat ke dalam memori.

Menampilkan kode

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector",
    index_type="AUTOINDEX",
    index_name="vector_index",
    metric_type="COSINE"
)

client.create_index(collection_name="product_catalog", index_params=index_params)

client.load_collection(collection_name="product_catalog")

Setelah persyaratan ini terpenuhi, Anda dapat menggunakan ekspresi di bawah ini untuk memfilter koleksi Anda berdasarkan nilai di dalam bidang JSON. Ekspresi filter ini memanfaatkan sintaksis jalur JSON tertentu dan operator khusus.

Memfilter dengan sintaks jalur JSON

Untuk menanyakan kunci tertentu, gunakan notasi tanda kurung untuk mengakses kunci JSON: json_field_name["key"]. Untuk kunci bersarang, rangkai kunci-kunci tersebut menjadi satu: json_field_name["key1"]["key2"].

Untuk memfilter entitas di mana category adalah "electronics":

# Define filter expression
filter = 'metadata["category"] == "electronics"'

client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

Untuk memfilter entitas dengan kunci bersarang supplier["country"] adalah "USA":

# Define filter expression
filter = 'metadata["supplier"]["country"] == "USA"'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

Memfilter dengan operator khusus JSON

Milvus juga menyediakan operator khusus untuk menanyakan nilai larik pada kunci bidang JSON tertentu. Sebagai contoh:

  • json_contains(identifier, expr): Memeriksa apakah elemen atau sub-larik tertentu ada di dalam larik JSON

  • json_contains_all(identifier, expr): Memastikan bahwa semua elemen dari ekspresi JSON yang ditentukan ada di dalam field

  • json_contains_any(identifier, expr): Memfilter entitas yang setidaknya memiliki satu anggota ekspresi JSON di dalam field

Untuk menemukan produk yang memiliki nilai "summer_sale" di bawah kunci tags:

# Define filter expression
filter = 'json_contains(metadata["tags"], "summer_sale")'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

Untuk menemukan produk yang memiliki setidaknya satu dari nilai "electronics", "new", atau "clearance" di bawah kunci tags:

# Define filter expression
filter = 'json_contains_any(metadata["tags"], ["electronics", "new", "clearance"])'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

Untuk informasi lebih lanjut tentang operator khusus JSON, lihat Operator JSON.

Berikutnya: Mempercepat kueri JSON

Secara default, kueri pada bidang JSON tanpa akselerasi akan melakukan pemindaian penuh terhadap semua baris, yang dapat berjalan lambat pada kumpulan data yang besar. Untuk mempercepat kueri JSON, Milvus menyediakan fitur pengindeksan dan pengoptimalan penyimpanan tingkat lanjut.

Tabel di bawah ini merangkum perbedaan dan skenario penggunaan terbaiknya:

Teknik

Terbaik Untuk

Akselerasi Larik

Catatan

Pengindeksan JSON

Kumpulan kecil kunci yang sering diakses, larik pada kunci larik tertentu

Ya (pada kunci larik yang diindeks)

Harus memilih kunci terlebih dahulu, diperlukan pemeliharaan jika skema berkembang

Penghancuran JSON

Percepatan umum di banyak kunci, fleksibel untuk beragam kueri

Tidak (tidak mempercepat nilai di dalam larik)

Konfigurasi penyimpanan ekstra, larik masih membutuhkan indeks per kunci

Indeks NGRAM

Pencarian wildcard, pencocokan substring dalam bidang teks

N/A

Tidak untuk filter numerik/rentang

Tips: Anda dapat menggabungkan pendekatan-pendekatan ini-misalnya, menggunakan penghancuran JSON untuk akselerasi kueri yang luas, pengindeksan JSON untuk kunci larik berfrekuensi tinggi, dan pengindeksan NGRAM untuk penelusuran teks yang fleksibel.

Untuk detail implementasi, lihat:

PERTANYAAN UMUM

Apakah ada batasan pada ukuran bidang JSON?

Ya. Setiap bidang JSON dibatasi hingga 65.536 byte.

Apakah bidang JSON mendukung pengaturan nilai default?

Tidak, bidang JSON tidak mendukung nilai default. Namun, Anda dapat mengatur nullable=True saat mendefinisikan bidang untuk mengizinkan entri kosong.

Lihat Nullable & Default untuk detailnya.

Apakah ada konvensi penamaan untuk kunci bidang JSON?

Ya, untuk memastikan kompatibilitas dengan kueri dan pengindeksan:

  • Gunakan hanya huruf, angka, dan garis bawah pada kunci JSON.

  • Hindari penggunaan karakter khusus, spasi, atau titik (., /, dll.).

  • Kunci yang tidak kompatibel dapat menyebabkan masalah penguraian dalam ekspresi filter.

Bagaimana Milvus menangani nilai string dalam bidang JSON?

Milvus menyimpan nilai string persis seperti yang muncul di input JSON-tanpa transformasi semantik. String yang dikutip dengan tidak benar dapat mengakibatkan kesalahan selama penguraian.

Contoh string yang valid:

"a\"b", "a'b", "a\\b"

Contoh string yang tidak valid:

'a"b', 'a\'b'