Nexa Intelligence Docs
Data & Storage

Qdrant

Spesifikasi teknis Vector Database Qdrant di Nexa, arsitektur koleksi 'articles_dedup', metrik Cosine Similarity, HNSW indexing, integrasi deduplikasi semantik C2, dan sinkronisasi payload D1 Webhook.

Qdrant Vector Database (Semantic Engine)

Qdrant bertindak sebagai Database Vektor Terdistribusi (Vector Database) berkecepatan tinggi dalam ekosistem Nexa Intelligence Platform. Berjalan pada port REST 6333 dan gRPC 6334, Qdrant mengemban dua peran arsitektural utama:

  1. Gatekeeper Deduplikasi Semantik (nexa-c2): Memfilter berita sindikasi dan artikel duplikat secara instan menggunakan pencarian Approximate Nearest Neighbor (ANN) dengan ambang batas Cosine Similarity $\ge 0.90$, sehingga menghemat hingga 40% biaya inferensi LLM.
  2. Memori Semantik & RAG (AIOS / D1 AI Worker): Menjadi repositori vektor dense 768-dimensi yang dihubungkan secara deterministik (UUIDv5) dengan dokumen berita di PostgreSQL dan Elasticsearch, serta menerima pembaruan status inferensi dari callback Webhook AIOS.

Spesifikasi Teknis Klaster & Koleksi

Klaster Qdrant dipasang secara terdedikasi pada klaster komputasi Nexa dengan parameter konfigurasi produksi berikut:

Parameter KonfigurasiNilai ProduksiKeterangan Teknis
Cluster Endpoint (REST)http://10.43.49.184:6333Endpoint komunikasi HTTP REST API untuk query dan health check.
Cluster Endpoint (gRPC)http://10.43.49.184:6334Endpoint berkinerja tinggi untuk high-throughput bulk upsert dari C2.
Primary Collectionarticles_dedupKoleksi utama penyimpanan seluruh vektor artikel berita nasional.
Vector Dimension768 (Dense Vector)Dimensi output model embedding teks berbahasa Indonesia (bge-large-id / indobert).
Distance MetricCosineMetrik pengukuran sudut kosinus antar-vektor (skor rentang $0.0$ s.d. $1.0$).
Index TypeHNSW (Hierarchical Navigable Small World)Graf vektor terindeks untuk pencarian ANN berskala jutaan titik.
HNSW $M$16Jumlah koneksi dua-arah (bidirectional links) per simpul vektor.
HNSW $ef_construct$128Kedalaman evaluasi tetangga terdekat saat konstruksi indeks vektor.
On-Disk Vectors & PayloadtrueVektor dan payload disimpan pada media NVMe untuk menekan pemakaian RAM.

1. Alur Deduplikasi Semantik (nexa-c2)

Setiap artikel berita yang telah dibersihkan oleh worker C1 Content Sanitizer dipancarkan ke antrean Kafka queue-normalize-data. Worker C2 Semantic Deduplication mengonsumsi antrean tersebut dan mengeksekusi gatekeeping semantik ke Qdrant:

[Artikel Bersih C1] ──▶ [Text Embedding 768-D] ──▶ [Qdrant Cosine Similarity Search]
                                                              │
                              ┌───────────────────────────────┴───────────────────────────────┐
                              ▼                                                               ▼
               Skor Similarity >= 0.90                                         Skor Similarity < 0.90
               [DUPLIKAT / SINDIKASI]                                              [ARTIKEL UNIK]
                      │                                                               │
                      ├─▶ Tandai flag duplikat di PostgreSQL                          ├─▶ Upsert Point Vektor ke Qdrant
                      ├─▶ Naikkan counter trending media                              ├─▶ Ingest ke Kafka `queue-ai-inference`
                      └─▶ Buang dari pipeline LLM mahal                               └─▶ Siap diekstraksi oleh Worker D1

Logika Query Kemiripan Semantik (Python Client)

Worker C2 membatasi pemindaian kemiripan hanya pada jendela waktu 7 hari terakhir (published_at >= now-7d) untuk menghindari perbandingan dengan berita lama yang topiknya kebetulan serupa:

from qdrant_client import QdrantClient
from qdrant_client.http import models

client = QdrantClient(url="http://10.43.49.184:6333", timeout=5.0)

# Cari 1 tetangga terdekat (Nearest Neighbor) dengan threshold 0.90
search_results = client.search(
    collection_name="articles_dedup",
    query_vector=embedding_vector_768,
    limit=1,
    score_threshold=0.90,
    query_filter=models.Filter(
        must=[
            models.FieldCondition(
                key="published_at",
                range=models.DatetimeRange(
                    gte="now-7d/d"  # Jendela geser 7 hari kalender
                )
            )
        ]
    )
)

if search_results:
    duplicate_match = search_results[0]
    print(f"Artikel Duplikat! Induk: {duplicate_match.payload['article_id']}, Skor: {duplicate_match.score:.4f}")
    # Rute ke penanganan sindikasi (tanpa memanggil LLM)
else:
    # Simpan vektor artikel unik ke Qdrant dan teruskan ke D1
    client.upsert(
        collection_name="articles_dedup",
        points=[
            models.PointStruct(
                id=deterministic_point_id,
                vector=embedding_vector_768,
                payload={
                    "article_id": str(article_uuid),
                    "domain": domain_name,
                    "title": article_title,
                    "published_at": published_iso_date,
                    "status": "pending_ai"
                }
            )
        ]
    )

2. Sinkronisasi Deterministik UUIDv5 & Webhook D1

Salah satu aspek kritis arsitektur data Nexa adalah penjaminan konsistensi ID titik vektor antara worker C2 (Python/FastEmbed) dan worker D1 (Python/AIOS).

Skema ID Deterministik (UUIDv5)

Alih-alih membuat ID acak, titik vektor Qdrant dibuat menggunakan algoritma UUIDv5 berdasar DNS namespace dari document_id / article_id:

import uuid

# Formula ID Deterministik yang dipakai seragam di C2 dan D1:
point_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, str(document_id)))

Dengan mekanisme ini, worker D1 dapat langsung memperbarui (in-place update) metadata titik vektor di Qdrant tanpa perlu melakukan query pencarian ID terlebih dahulu.

Pembaruan Payload Asinkron dari Webhook D1

Setelah proses ekstraksi kognitif AIOS (klasifikasi 5 pilar taksonomi, sentimen, dan ekstraksi entitas) selesai, endpoint Webhook D1 (nexa-d1/webhook.py) mengeksekusi pembaruan payload titik vektor ke Qdrant:

import requests
from datetime import datetime

# Payload pembaruan dari Webhook nexa-d1
qdrant_payload = {
    "status": "completed",
    "job_id": job_id,
    "agent": (taxonomy_result or "umum").lower(),
    "taxonomy": taxonomy_result,
    "confidence": float(confidence_val),
    "processed_at": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
}

update_url = "http://10.43.49.184:6333/collections/articles_dedup/points/payload?wait=true"

response = requests.post(
    update_url,
    json={
        "points": [point_id],
        "payload": qdrant_payload
    },
    timeout=5
)

3. Struktur Lengkap Titik Vektor (Payload Schema)

Berikut adalah contoh utuh rekaman titik vektor di Qdrant setelah melewati tahap deduplikasi C2 dan pengayaan Webhook D1:

{
  "id": "c1f7a01e-4501-49b8-a73c-7c093a123456",
  "version": 2,
  "score": null,
  "vector": [
    0.021384,
    -0.045219,
    0.119284,
    0.008912,
    "... 768 nilai dense float32 ..."
  ],
  "payload": {
    "article_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "domain": "kompas.com",
    "title": "KPK Dalami Aliran Dana Dugaan Korupsi Proyek Pengadaan di Kemenhub",
    "published_at": "2026-09-24T08:30:00Z",
    "status": "completed",
    "job_id": "job_d1_extract_982341",
    "agent": "politik",
    "taxonomy": "Politik & Hukum / Korupsi Pengadaan",
    "confidence": 0.942,
    "processed_at": "2026-09-24T08:31:12Z"
  }
}

4. Konfigurasi Indeks Payload & Optimasi Memori

Untuk memastikan query filter berjalan sub-milidetik pada puluhan juta vektor tanpa melakukan full-scan payload:

  1. Payload Schema Indexing:

    • Kolom published_at diindeks dengan tipe data datetime untuk akselerasi rentang waktu 7 hari.
    • Kolom status dan agent diindeks dengan tipe keyword untuk pemilahan status pemrosesan.
    PUT /collections/articles_dedup/index
    Host: 10.43.49.184:6333
    Content-Type: application/json
    
    {
      "field_name": "published_at",
      "field_schema": "datetime"
    }
  2. On-Disk Vector Storage:

    • Vektor dense 768 dimensi menggunakan konfigurasi on_disk: true. Indeks HNSW tetap berada di RAM untuk pencarian kilat, sedangkan raw float array dialokasikan pada disk NVMe sehingga footprint RAM berkurang hingga 70%.
  3. Snapshots & Disaster Recovery:

    • Snapshot koleksi diambil berkala dan diunggah ke Object Storage (MinIO) pada bucket nexa-backups/qdrant/ melalui REST endpoint POST /collections/articles_dedup/snapshots.

On this page