Milvus
Zilliz
  • Home
  • Blog
  • Echte Abfrage auf Entity-Ebene: Neue Array-of-Structs und MAX_SIM-Fähigkeiten in Milvus

Echte Abfrage auf Entity-Ebene: Neue Array-of-Structs und MAX_SIM-Fähigkeiten in Milvus

  • Engineering
December 05, 2025
Jeremy Zhu, Min Tian

Wenn Sie KI-Anwendungen auf der Grundlage von Vektordatenbanken entwickelt haben, sind Sie wahrscheinlich auf denselben Schmerzpunkt gestoßen: Die Datenbank ruft die Einbettungen einzelner Chunks ab, aber Ihre Anwendung interessiert sich für Entitäten. Diese Diskrepanz macht den gesamten Abruf-Workflow komplex.

Sie haben dies wahrscheinlich schon oft erlebt:

  • RAG-Wissensdatenbanken: Artikel sind in Absatzeinbettungen unterteilt, so dass die Suchmaschine verstreute Fragmente anstelle des vollständigen Dokuments liefert.

  • E-Commerce-Empfehlung: Ein Produkt hat mehrere Bildeinbettungen, und Ihr System gibt fünf Ansichten desselben Artikels zurück, anstatt fünf einzigartige Produkte.

  • Video-Plattformen: Videos sind in Clip-Einbettungen aufgeteilt, aber die Suchergebnisse zeigen eher Ausschnitte desselben Videos als einen einzigen konsolidierten Eintrag.

  • ColBERT-/ColPali-ähnliche Abfrage: Dokumente werden in Hunderte von Token- oder Patch-Ebenen aufgeteilt, und die Ergebnisse werden in winzigen Stücken angezeigt, die noch zusammengeführt werden müssen.

Alle diese Probleme sind auf dieselbe architektonische Lücke zurückzuführen: Die meisten Vektordatenbanken behandeln jede Einbettung als isolierte Zeile, während reale Anwendungen mit Entitäten auf höherer Ebene arbeiten - Dokumente, Produkte, Videos, Objekte, Szenen. Infolgedessen sind Entwicklungsteams gezwungen, Entitäten manuell zu rekonstruieren, indem sie Deduplizierungs-, Gruppierungs-, Bucketing- und Reranking-Logik verwenden. Das funktioniert zwar, ist aber anfällig und langsam und bläht die Anwendungsschicht mit Logik auf, die dort gar nicht erst hätte untergebracht werden sollen.

Milvus 2.6.4 schließt diese Lücke mit einer neuen Funktion: Array of Structs mit dem metrischen Typ MAX_SIM. Zusammen erlauben sie es, alle Einbettungen für eine einzelne Entität in einem einzigen Datensatz zu speichern und ermöglichen es Milvus, die Entität ganzheitlich zu bewerten und zurückzugeben. Keine doppelt gefüllten Ergebnismengen mehr. Kein komplexes Post-Processing wie Reranking und Merging mehr

In diesem Artikel werden wir die Funktionsweise von Array of Structs und MAX_SIM erläutern und anhand von zwei realen Beispielen demonstrieren: Die Suche nach Wikipedia-Dokumenten und die bildbasierte ColPali-Dokumentensuche.

Was ist ein Array of Structs?

In Milvus ermöglicht ein Array of Structs Feld, dass ein einzelner Datensatz eine geordnete Liste von Struct-Elementen enthält, die alle dem gleichen vordefinierten Schema folgen. Eine Struct kann sowohl mehrere Vektoren als auch skalare Felder, Strings oder andere unterstützte Typen enthalten. Mit anderen Worten, Sie können damit alle Teile, die zu einer Entität gehören - Absatzeinbettungen, Bildansichten, Token-Vektoren, Metadaten - direkt in einer Zeile bündeln.

Hier ist ein Beispiel für eine Entität aus einer Sammlung, die ein Array of Structs-Feld enthält.

{
    'id': 0,
    'title': 'Walden',
    'title_vector': [0.1, 0.2, 0.3, 0.4, 0.5],
    'author': 'Henry David Thoreau',
    'year_of_publication': 1845,
    // highlight-start
    'chunks': [
        {
            'text': 'When I wrote the following pages, or rather the bulk of them...',
            'text_vector': [0.3, 0.2, 0.3, 0.2, 0.5],
            'chapter': 'Economy',
        },
        {
            'text': 'I would fain say something, not so much concerning the Chinese and...',
            'text_vector': [0.7, 0.4, 0.2, 0.7, 0.8],
            'chapter': 'Economy'
        }
    ]
    // hightlight-end
}

Im obigen Beispiel ist das Feld chunks ein Array of Structs-Feld, und jedes Struct-Element enthält seine eigenen Felder, nämlich text, text_vector und chapter.

Mit diesem Ansatz wird ein seit langem bestehendes Modellierungsproblem in Vektordatenbanken gelöst. Traditionell muss jede Einbettung oder jedes Attribut eine eigene Zeile werden, was dazu führt, dass Multi-Vektor-Entitäten (Dokumente, Produkte, Videos) in Dutzende, Hunderte oder sogar Tausende von Datensätzen aufgeteilt werden müssen. Mit Array of Structs können Sie mit Milvus die gesamte Multi-Vektor-Entität in einem einzigen Feld speichern, was es zu einer natürlichen Lösung für Absatzlisten, Token-Einbettungen, Clip-Sequenzen, Multi-View-Bilder oder jedes Szenario macht, in dem ein logisches Element aus vielen Vektoren besteht.

Wie funktioniert ein Array von Structs mit MAX_SIM?

Über dieser neuen Array of Structs-Struktur liegt MAX_SIM, eine neue Bewertungsstrategie, die das semantische Retrieval entitätenorientiert macht. Wenn eine Anfrage eingeht, vergleicht Milvus sie mit jedem Vektor in jedem Array of Structs und nimmt die maximale Ähnlichkeit als endgültige Punktzahl für die Entität. Die Entität wird dann auf der Grundlage dieser einzelnen Punktzahl eingestuft und zurückgegeben. Auf diese Weise wird das klassische Vektor-Datenbankproblem des Abrufs verstreuter Fragmente vermieden und die Last des Gruppierens, Dedupierens und Neueinordnens in die Anwendungsschicht verlagert. Mit MAX_SIM wird der Abruf auf Entitätsebene integriert, konsistent und effizient.

Um zu verstehen, wie MAX_SIM in der Praxis funktioniert, lassen Sie uns ein konkretes Beispiel durchgehen.

Hinweis: Alle Vektoren in diesem Beispiel werden mit demselben Einbettungsmodell erzeugt, und die Ähnlichkeit wird mit der Kosinusähnlichkeit im Bereich [0,1] gemessen.

Angenommen, ein Benutzer sucht nach "Machine Learning Beginner Course".

Die Abfrage wird in drei Token unterteilt:

  • Maschinelles Lernen

  • Anfänger

  • Kurs

Jedes dieser Token wird dann mit demselben Einbettungsmodell, das für die Dokumente verwendet wurde , in einen Einbettungsvektor umgewandelt.

Stellen Sie sich nun vor, die Vektordatenbank enthält zwei Dokumente:

  • doc_1: An Introduction Guide to Deep Neural Networks with Python

  • doc_2: Ein Leitfaden für Fortgeschrittene zum Lesen von LLM-Papieren

Beide Dokumente wurden in Vektoren eingebettet und in einem Array of Structs gespeichert.

Schritt 1: Berechnen von MAX_SIM für doc_1

Für jeden Abfragevektor berechnet Milvus seine Kosinusähnlichkeit mit jedem Vektor in doc_1:

EinführungLeitfadentiefe neuronale Netzepython
maschinelles lernen0.00.00.90.3
Anfänger0.80.10.00.3
Kurs0.30.70.10.1

Für jeden Abfragevektor wählt MAX_SIM die höchste Ähnlichkeit aus seiner Zeile aus:

  • Maschinelles Lernen → Tiefe neuronale Netze (0.9)

  • Einsteiger → Einführung (0.8)

  • Kurs → Leitfaden (0,7)

Die Summierung der besten Übereinstimmungen ergibt für doc_1 einen MAX_SIM-Wert von 2,4.

Schritt 2: Berechnen von MAX_SIM für doc_2

Nun wiederholen wir den Vorgang für doc_2:

advancedLeitfadenLLMPapierLesen
Maschinelles Lernen0.10.20.90.30.1
Anfänger0.40.60.00.20.5
Kurs0.50.80.10.40.7

Die besten Übereinstimmungen für doc_2 sind:

  • "Maschinelles Lernen" → "LLM" (0,9)

  • "Anfänger" → "Anleitung" (0.6)

  • "Kurs" → "Leitfaden" (0,8)

Die Summe dieser Werte ergibt für doc_2 eine MAX_SIM-Punktzahl von 2,3.

Schritt 3: Vergleichen Sie die Punktzahlen

Da 2,4 > 2,3, rangiert doc_1 höher als doc_2, was intuitiv Sinn macht, da doc_1 näher an einem Einführungshandbuch für maschinelles Lernen ist.

Anhand dieses Beispiels können wir drei Hauptmerkmale von MAX_SIM hervorheben:

  • Semantisch zuerst, nicht schlagwortbasiert: MAX_SIM vergleicht Einbettungen, nicht Textliterale. Obwohl "maschinelles Lernen" und "tiefe neuronale Netze" null überlappende Wörter haben, beträgt ihre semantische Ähnlichkeit 0,9. Das macht MAX_SIM robust gegenüber Synonymen, Paraphrasen, konzeptionellen Überschneidungen und modernen, einbettungsreichen Arbeitslasten.

  • Unempfindlich gegenüber Länge und Reihenfolge: MAX_SIM verlangt nicht, dass die Anfrage und das Dokument die gleiche Anzahl von Vektoren haben (z.B. doc_1 hat 4 Vektoren, doc_2 hat 5, und beide funktionieren gut). Auch die Reihenfolge der Vektoren spielt keine Rolle - wenn "Anfänger" am Anfang der Abfrage und "Einführung" am Ende des Dokuments steht, hat das keine Auswirkungen auf die Bewertung.

  • Jeder Abfragevektor ist wichtig: MAX_SIM nimmt die beste Übereinstimmung für jeden Abfragevektor und summiert diese besten Ergebnisse. Dadurch wird verhindert, dass nicht übereinstimmende Vektoren das Ergebnis verzerren, und es wird sichergestellt, dass jedes wichtige Abfrage-Token zum Endergebnis beiträgt. Zum Beispiel reduziert die minderwertige Übereinstimmung für "Anfänger" in doc_2 direkt die Gesamtpunktzahl.

Warum MAX_SIM + Array of Structs in der Vektordatenbank wichtig sind

Milvus ist eine Open-Source-Hochleistungs-Vektordatenbank und unterstützt jetzt MAX_SIM zusammen mit Array of Structs, was eine vektor-native Multi-Vektor-Suche auf Entity-Ebene ermöglicht:

  • Speichern Sie Multi-Vektor-Entitäten nativ: Mit Array of Structs können Sie Gruppen verwandter Vektoren in einem einzigen Feld speichern, ohne sie in separate Zeilen oder Hilfstabellen aufzuteilen.

  • Effiziente Best-Match-Berechnung: In Kombination mit Vektorindizes wie IVF und HNSW kann MAX_SIM die besten Übereinstimmungen berechnen, ohne jeden Vektor zu scannen, und so die Leistung auch bei großen Dokumenten hoch halten.

  • Speziell für semantiklastige Arbeitslasten entwickelt: Dieser Ansatz eignet sich hervorragend für die Suche nach langen Texten, das semantische Matching mit mehreren Facetten, den Abgleich von Dokumenten und Zusammenfassungen, Abfragen mit mehreren Schlüsselwörtern und andere KI-Szenarien, die flexible, feinkörnige semantische Schlussfolgerungen erfordern.

Wann sollte man ein Array of Structs verwenden?

Der Wert von Array of Structs wird deutlich, wenn man sich ansieht, was es ermöglicht. Im Kern bietet diese Funktion drei grundlegende Fähigkeiten:

  • Es bündelt heterogene Daten - Vektoren, Skalare, Strings, Metadaten - zu einem einzigen strukturierten Objekt.

  • Es gleicht die Speicherung an reale Entitäten an, so dass jede Datenbankzeile sauber auf ein tatsächliches Element wie einen Artikel, ein Produkt oder ein Video abgebildet wird.

  • In Kombination mit Aggregatfunktionen wie MAX_SIM ermöglicht es eine echte Multi-Vektor-Abfrage auf Entity-Ebene direkt aus der Datenbank, wodurch Deduplizierung, Gruppierung oder Neuordnung in der Anwendungsschicht vermieden werden.

Aufgrund dieser Eigenschaften eignet sich Array of Structs immer dann, wenn eine einzelne logische Entität durch mehrere Vektoren dargestellt wird. Gängige Beispiele sind Artikel, die in Absätze aufgeteilt sind, Dokumente, die in Token-Einbettungen zerlegt sind, oder Produkte, die durch mehrere Bilder dargestellt werden. Wenn Ihre Suchergebnisse unter doppelten Treffern, verstreuten Fragmenten oder dem mehrfachen Auftauchen derselben Entität in den Top-Ergebnissen leiden, löst Array of Structs diese Probleme auf der Speicher- und Abrufebene - und nicht durch nachträgliche Anpassungen im Anwendungscode.

Dieses Muster ist besonders leistungsfähig für moderne KI-Systeme, die auf die Abfrage mehrerer Vektoren angewiesen sind, z. B:

  • ColBERT stellt ein einzelnes Dokument als 100-500 Token-Einbettungen dar, um einen feinkörnigen semantischen Abgleich in Bereichen wie Rechtstexten und akademischer Forschung zu ermöglichen.

  • ColPali konvertiert jede PDF-Seite in 256-1024 Bildfelder für die cross-modale Suche in Finanzberichten, Verträgen, Rechnungen und anderen gescannten Dokumenten.

Mit einem Array von Structs kann Milvus all diese Vektoren unter einer einzigen Entität speichern und die aggregierte Ähnlichkeit (z. B. MAX_SIM) effizient und nativ berechnen. Um dies zu verdeutlichen, sind hier zwei konkrete Beispiele.

Bisher wurden Produkte mit mehreren Bildern in einem flachen Schema gespeichert - ein Bild pro Zeile. Ein Produkt mit Front-, Seiten- und Schrägaufnahmen ergab drei Zeilen. Die Suchergebnisse lieferten oft mehrere Bilder desselben Produkts, was eine manuelle Deduplizierung und Neuordnung erforderte.

Mit einem Array of Structs wird jedes Produkt zu einer Zeile. Alle Bildeinbettungen und Metadaten (Winkel, is_primary, etc.) befinden sich in einem images Feld als Array of Structs. Milvus versteht, dass sie zum selben Produkt gehören und gibt das Produkt als Ganzes zurück - nicht die einzelnen Bilder.

Zuvor war ein einzelner Wikipedia-Artikel in N Absatzzeilen aufgeteilt. Die Suchergebnisse lieferten verstreute Absätze, so dass das System gezwungen war, sie zu gruppieren und zu erraten, zu welchem Artikel sie gehörten.

Mit einem Array of Structs wird der gesamte Artikel zu einer einzigen Zeile. Alle Absätze und ihre Einbettungen werden unter einem Absatzfeld gruppiert, und die Datenbank gibt den gesamten Artikel zurück, nicht nur fragmentierte Teile.

Praktische Tutorials: Retrieval auf Dokumentenebene mit dem Array of Structs

1. Abrufen von Wikipedia-Dokumenten

In diesem Tutorial wird gezeigt, wie ein Array of Structs verwendet wird, um Daten auf Absatzebene in vollständige Dokumentendatensätze umzuwandeln - so dass Milvus eine echte Abfrage auf Dokumentebene durchführen kann, anstatt isolierte Fragmente zurückzugeben.

Viele Wissensdatenbank-Pipelines speichern Wikipedia-Artikel als Absatzabschnitte. Dies eignet sich gut für die Einbettung und Indizierung, beeinträchtigt aber die Abfrage: Eine Benutzerabfrage liefert in der Regel verstreute Absätze, so dass Sie gezwungen sind, den Artikel manuell zu gruppieren und zu rekonstruieren. Mit einem Array of Structs und MAX_SIM können wir das Speicherschema so umgestalten, dass jeder Artikel zu einer Zeile wird, und Milvus kann das gesamte Dokument nativ einordnen und zurückgeben.

In den nächsten Schritten werden wir zeigen, wie man:

  1. Laden und Vorverarbeiten von Wikipedia-Absatzdaten

  2. Bündeln aller Absätze, die zum selben Artikel gehören, in ein Array von Structs

  3. Einfügen dieser strukturierten Dokumente in Milvus

  4. MAX_SIM-Abfragen ausführen, um vollständige Artikel abzurufen - sauber, ohne Deduplizierung oder Reranking

Am Ende dieses Tutorials werden Sie eine funktionierende Pipeline haben, in der Milvus die Abfrage auf Entity-Ebene direkt durchführt, genau so, wie es die Benutzer erwarten.

Datenmodell:

{
    "wiki_id": int,                  # WIKI ID(primary key) 
    "paragraphs": ARRAY<STRUCT<      # Array of paragraph structs
        text:VARCHAR                 # Paragraph text
        emb: FLOAT_VECTOR(768)       # Embedding for each paragraph
    >>
}

Schritt 1: Gruppieren und Transformieren der Daten

Für diese Demo verwenden wir den Datensatz Simple Wikipedia Embeddings.

import pandas as pd
import pyarrow as pa

# Load the dataset and group by wiki_id df = pd.read_parquet(“train-*.parquet”) grouped = df.groupby(‘wiki_id’)

# Build the paragraph array for each article wiki_data = [] for wiki_id, group in grouped: wiki_data.append({ ‘wiki_id’: wiki_id, ‘paragraphs’: [{‘text’: row[‘text’], ‘emb’: row[‘emb’]} for _, row in group.iterrows()] })

Schritt 2: Erstellen der Milvus-Sammlung

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri=“http://localhost:19530”) schema = client.create_schema() schema.add_field(“wiki_id”, DataType.INT64, is_primary=True)

# Define the Struct schema struct_schema = client.create_struct_field_schema() struct_schema.add_field(“text”, DataType.VARCHAR, max_length=65535) struct_schema.add_field(“emb”, DataType.FLOAT_VECTOR, dim=768)

schema.add_field(“paragraphs”, DataType.ARRAY, element_type=DataType.STRUCT, struct_schema=struct_schema, max_capacity=200)

client.create_collection(“wiki_docs”, schema=schema)

Schritt 3: Daten einfügen und Index erstellen

# Batch insert documents
client.insert("wiki_docs", wiki_data)

# Create an HNSW index index_params = client.prepare_index_params() index_params.add_index( field_name="paragraphs[emb]", index_type=“HNSW”, metric_type=“MAX_SIM_COSINE”, params={“M”: 16, “efConstruction”: 200} ) client.create_index(“wiki_docs”, index_params) client.load_collection(“wiki_docs”)

Schritt 4: Dokumente suchen

# Search query
import cohere
from pymilvus.client.embedding_list import EmbeddingList

# The dataset uses Cohere’s multilingual-22-12 embedding model, so we must embed the query using the same model. co = cohere.Client(f"<>") query = ‘Who founded Youtube’ response = co.embed(texts=[query], model=‘multilingual-22-12’) query_embedding = response.embeddings query_emb_list = EmbeddingList()

for vec in query_embedding[0]: query_emb_list.add(vec)

results = client.search( collection_name=“wiki_docs”, data=[query_emb_list], anns_field="paragraphs[emb]", search_params={ “metric_type”: “MAX_SIM_COSINE”, “params”: {“ef”: 200, “retrieval_ann_ratio”: 3} }, limit=10, output_fields=[“wiki_id”] )

# Results: directly return 10 full articles! for hit in results[0]: print(f"Article {hit[‘entity’][‘wiki_id’]}: Score {hit[‘distance’]:.4f}")

Vergleich der Ergebnisse: Traditionelles Retrieval vs. Array of Structs

Die Auswirkungen von Array of Structs werden deutlich, wenn wir uns ansehen, was die Datenbank tatsächlich zurückgibt:

DimensionTraditioneller AnsatzArray von Strukturen
Datenbank-AusgabeLiefert die 100 besten Absätze (hohe Redundanz)Gibt die 10 besten vollständigen Dokumente zurück - sauber und genau
AnwendungslogikErfordert Gruppierung, Deduplizierung und Reranking (komplex)Keine Nachbearbeitung erforderlich - Ergebnisse auf Entity-Ebene kommen direkt von Milvus

Im Wikipedia-Beispiel haben wir nur den einfachsten Fall demonstriert: die Kombination von Absatzvektoren zu einer einheitlichen Dokumentendarstellung. Die eigentliche Stärke von Array of Structs ist jedoch die Verallgemeinerbarkeit für jedes Multi-Vektor-Datenmodell - sowohl für klassische Retrieval-Pipelines als auch für moderne KI-Architekturen.

Traditionelle Multi-Vektor-Retrieval-Szenarien

Viele etablierte Such- und Empfehlungssysteme arbeiten natürlich mit Entitäten, die mehrere Vektoren enthalten. Array of Structs lässt sich sauber auf diese Anwendungsfälle abbilden:

SzenarioDatenmodellVektoren pro Entität
🛍️ Produkte im elektronischen HandelEin Produkt → mehrere Bilder5-20
🎬 VideosucheEin Video → mehrere Clips20-100
📖 PapierrechercheEin Papier → mehrere Abschnitte5-15

Arbeitslasten von KI-Modellen (wichtige Anwendungsfälle mit mehreren Vektoren)

Array of Structs wird in modernen KI-Modellen, die absichtlich große Mengen von Vektoren pro Entität für feinkörnige semantische Schlussfolgerungen erzeugen, noch wichtiger.

ModellDatenmodellVektoren pro EntitätAnwendung
ColBERTEin Dokument → viele Token-Einbettungen100-500Juristische Texte, akademische Arbeiten, feinkörnige Dokumentensuche
ColPaliEine PDF-Seite → viele Patch-Einbettungen256-1024Finanzberichte, Verträge, Rechnungen, multimodale Dokumentensuche

Diese Modelle erfordern ein Multi-Vektor-Speicherschema. Vor Array of Structs mussten die Entwickler die Vektoren auf verschiedene Zeilen aufteilen und die Ergebnisse manuell wieder zusammenfügen. Mit Milvus können diese Entitäten nun nativ gespeichert und abgerufen werden, wobei MAX_SIM die Bewertung auf Dokumentenebene automatisch vornimmt.

ColPali ist ein leistungsstarkes Modell für die cross-modale PDF-Suche. Anstatt sich auf Text zu verlassen, verarbeitet es jede PDF-Seite als Bild und zerlegt es in bis zu 1024 visuelle Felder, wobei pro Feld eine Einbettung erzeugt wird. In einem herkömmlichen Datenbankschema würde dies bedeuten, dass eine einzelne Seite in Hunderten oder Tausenden von separaten Zeilen gespeichert werden müsste, was es der Datenbank unmöglich machen würde, zu erkennen, dass diese Zeilen zur selben Seite gehören. Infolgedessen wird die Suche auf Entitätsebene fragmentiert und unpraktisch.

Array of Structs löst dieses Problem sauber, indem es alle Patch-Einbettungen in einem einzigen Feld speichert, wodurch Milvus die Seite als eine zusammenhängende Multi-Vektor-Entität behandeln kann.

Die herkömmliche PDF-Suche hängt oft von OCR ab, die Seitenbilder in Text umwandelt. Dies funktioniert zwar für reinen Text, aber dabei gehen Diagramme, Tabellen, das Layout und andere visuelle Hinweise verloren. ColPali umgeht diese Einschränkung, indem es direkt mit den Seitenbildern arbeitet und alle visuellen und textlichen Informationen beibehält. Der Nachteil ist die Skalierung: Jede Seite enthält nun Hunderte von Vektoren, was eine Datenbank erfordert, die viele Einbettungen in einer Einheit zusammenfassen kann - genau das, was Array of Structs + MAX_SIM bietet.

Der häufigste Anwendungsfall ist Vision RAG, wo jede PDF-Seite zu einer Multi-Vektor-Entität wird. Typische Szenarien sind:

  • Finanzberichte: Durchsuchen von Tausenden von PDFs nach Seiten mit bestimmten Diagrammen oder Tabellen.

  • Verträge: Abrufen von Klauseln aus gescannten oder abfotografierten Rechtsdokumenten.

  • Rechnungen: Auffinden von Rechnungen nach Lieferant, Betrag oder Layout.

  • Präsentationen: Auffinden von Folien, die eine bestimmte Abbildung oder ein bestimmtes Diagramm enthalten.

Datenmodell:

{
    "page_id": int,                     # Page ID (primary key) 
    "page_number": int,                 # Page number within the document 
    "doc_name": VARCHAR,                # Document name
    "patches": ARRAY<STRUCT<            # Array of patch objects
        patch_embedding: FLOAT_VECTOR(128)  # Embedding for each patch
    >>
}

Schritt 1: Vorbereiten der DatenWie ColPali Bilder oder Texte in Multivektordarstellungen umwandelt, können Sie in der Dokumentation nachlesen.

import torch
from PIL import Image

from colpali_engine.models import ColPali, ColPaliProcessor

model_name = “vidore/colpali-v1.3”

model = ColPali.from_pretrained( model_name, torch_dtype=torch.bfloat16, device_map=“cuda:0”, # or “mps” if on Apple Silicon ).eval()

processor = ColPaliProcessor.from_pretrained(model_name) # Example: 2 documents, 5 pages each, total 10 images images = [ Image.open(“path/to/your/image1.png”), Image.open(“path/to/your/image2.png”), … Image.open(“path/to/your/image10.png”) ] # Convert each image into multiple patch embeddings batch_images = processor.process_images(images).to(model.device) with torch.no_grad(): image_embeddings = model(**batch_images)

Schritt 2: Erstellen der Milvus-Sammlung

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri=“http://localhost:19530”) schema = client.create_schema() schema.add_field(“page_id”, DataType.INT64, is_primary=True) schema.add_field(“page_number”, DataType.INT64) schema.add_field(“doc_name”, DataType.VARCHAR, max_length=500)

# Struct Array for patches struct_schema = client.create_struct_field_schema() struct_schema.add_field(“patch_embedding”, DataType.FLOAT_VECTOR, dim=128)

schema.add_field(“patches”, DataType.ARRAY, element_type=DataType.STRUCT, struct_schema=struct_schema, max_capacity=2048)

client.create_collection(“doc_pages”, schema=schema)

Schritt 3: Daten einfügen und Index erstellen

# Prepare data for insertion
page_data=[
    {
        "page_id": 0,
        "page_number": 0,
        "doc_name": "Q1_Financial_Report.pdf",
        "patches": [
            {"patch_embedding": emb} for emb in image_embeddings[0]
        ],
    },
    ...,
    {
        "page_id": 9,
        "page_number": 4,
        "doc_name": "Product_Manual.pdf",
        "patches": [
            {"patch_embedding": emb} for emb in image_embeddings[9]
        ],
    },
]

client.insert(“doc_pages”, page_data)

# Create index index_params = client.prepare_index_params() index_params.add_index( field_name="patches[patch_embedding]", index_type=“HNSW”, metric_type=“MAX_SIM_IP”, params={“M”: 32, “efConstruction”: 200} ) client.create_index(“doc_pages”, index_params) client.load_collection(“doc_pages”)

Schritt 4: Modalübergreifende Suche: Textabfrage → Bildergebnisse

# Run the search
from pymilvus.client.embedding_list import EmbeddingList

queries = [ “quarterly revenue growth chart”
] # Convert the text query into a multi-vector representation batch_queries = processor.process_queries(queries).to(model.device) with torch.no_grad(): query_embeddings = model(**batch_queries)

query_emb_list = EmbeddingList() for vec in query_embeddings[0]: query_emb_list.add(vec) results = client.search( collection_name=“doc_pages”, data=[query_emb_list], anns_field="patches[patch_embedding]", search_params={ “metric_type”: “MAX_SIM_IP”, “params”: {“ef”: 100, “retrieval_ann_ratio”: 3} }, limit=3, output_fields=[“page_id”, “doc_name”, “page_number”] )

print(f"Query: '{queries[0]}'") for i, hit in enumerate(results, 1): entity = hit[‘entity’] print(f"{i}. {entity[‘doc_name’]} - Page {entity[‘page_number’]}") print(f" Score: {hit[‘distance’]:.4f}\n")

Beispielhafte Ausgabe:

Query: 'quarterly revenue growth chart'
1. Q1_Financial_Report.pdf - Page 2
   Score: 0.9123

2. Q1_Financial_Report.pdf - Page 1 Score: 0.7654

3. Product_Manual.pdf - Page 1 Score: 0.5231

Hier geben die Ergebnisse direkt vollständige PDF-Seiten zurück. Wir müssen uns nicht um die zugrundeliegenden 1024 Patch-Einbettungen kümmern - Milvus erledigt die gesamte Aggregation automatisch.

Schlussfolgerung

Die meisten Vektordatenbanken speichern jedes Fragment als unabhängigen Datensatz, was bedeutet, dass Anwendungen diese Fragmente neu zusammensetzen müssen, wenn sie ein vollständiges Dokument, ein Produkt oder eine Seite benötigen. Ein Array von Structs ändert dies. Durch die Kombination von Skalaren, Vektoren, Text und anderen Feldern in einem einzigen strukturierten Objekt kann eine Datenbankzeile eine vollständige Entität von Anfang bis Ende darstellen.

Das Ergebnis ist einfach, aber wirkungsvoll: Arbeiten, die früher komplexe Gruppierung, Deduplizierung und Neuordnung in der Anwendungsschicht erforderten, werden zu einer nativen Datenbankfunktion. Und genau darauf zielt die Zukunft der Vektordatenbanken ab - sicherere Strukturen, intelligentere Abfragen und einfachere Pipelines.

Weitere Informationen über Array of Structs und MAX_SIM finden Sie in der unten stehenden Dokumentation:

Haben Sie Fragen oder möchten Sie einen tieferen Einblick in eine Funktion des neuesten Milvus? Treten Sie unserem Discord-Kanal bei oder stellen Sie Fragen auf GitHub. Sie können auch eine 20-minütige persönliche Sitzung buchen, um Einblicke, Anleitungen und Antworten auf Ihre Fragen über Milvus Office Hours zu erhalten.

    Try Managed Milvus for Free

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

    Get Started

    Like the article? Spread the word

    Weiterlesen