Christy Bergman: Perché sono entrata in Zilliz
Mi chiamo Christy Bergman e di recente sono entrata in Zilliz come Developer Advocate con sede a San Francisco. Mi occuperò di organizzare, partecipare e parlare a eventi, scrivere blog e tutorial di codice, migliorare la documentazione e, in generale, aiutare le persone (come te, spero!) a imparare a usare Milvus, il database vettoriale open-source più popolare al mondo (misurato in base alle stelle su GitHub).
Prima di Zilliz, sono stata Developer Advocate presso Anyscale, il creatore open-source di Ray, che rende il calcolo distribuito facile per tutti gli sviluppatori. Prima ancora, sono stata AWS AI/ML Specialist Solutions Architect focalizzata sulle previsioni con deep learning.
Allora perché ho scelto di entrare in Zilliz? È iniziato con la mia curiosità su come migliorare gli output delle chat di ChatGPT inserendo contesto nel prompt. Poi ho iniziato un percorso per sperimentare con gli embedding e, da lì, ho cominciato a cercare un database vettoriale facile da usare e veloce. In questo post del blog, ti guiderò attraverso i passaggi che mi hanno portata qui.
Il dubbio: ho davvero bisogno di un database vettoriale?
All’inizio, mi sono chiesta se un database vettoriale fosse davvero necessario. Tuttavia, alcuni tentativi di inserire testo sotto forma di embedding in una variabile Python, fare il pickling e l’unpickling, mi hanno convinta che gli embedding dovessero essere memorizzati nella cache o persistiti da qualche parte meglio che in pickle.
Milvus è un database completo progettato da zero appositamente per i vettori. Migliaia di sviluppatori in tutto il mondo usano Milvus, che include il supporto per molti diversi algoritmi di ricerca vettoriale, metriche di distanza nello spazio vettoriale e altre funzionalità come Insert/upsert, TopK e Range Search, supporto GPU e altro ancora. La versione commerciale si chiama Zilliz Cloud e offre disponibilità con SLA del 99,9%, scalabilità automatica, funziona su AWS e GCP (Azure in arrivo) e puoi eseguirla sul tuo account cloud con piena conformità SOC2.
Esplorare le opzioni: provare diversi database vettoriali
Per inserire embedding in un database vettoriale, ti servono: 1) dati non strutturati, 2) un piano su come suddividere quei dati in chunk, 3) un modello di embedding e 4) un database vettoriale.
Per i dati, ho usato il dataset IMDB di grandi dimensioni di recensioni di film dello Stanford AI Lab. È un dataset da 50.000 elementi comodamente elaborato (rapporto di campionamento 50:50 tra recensioni positive/negative). Questi dati hanno le colonne: movie_index, testo grezzo della recensione e valutazione del film.
Per la suddivisione in chunk, ho scelto di mantenere intatte le recensioni dei film intere, a meno che non fossero molto lunghe. Per le recensioni molto lunghe, ho usato i tipici chunk predefiniti di lunghezza 512. Ciò significa che le recensioni lunghe sono state divise in diversi pezzi da 512 caratteri. Nel gergo degli LLM, questo si chiama “chunk size”.
Per il modello di embedding, ho provato vari modelli, inclusi gli onnipresenti embedding di OpenAI. Finché ho capito che la cosa più semplice è semplicemente selezionare il bersaglio sempre mobile del modello più piccolo e meglio classificato nella scheda Retriever dalla classifica MTEB di HuggingFace. All’epoca, ho scelto “e5-base-v2”. In realtà è un bene che la scelta del modello di embedding sia indipendente dal database vettoriale stesso.
Per i database, ho provato FAISS, Qdrant, Chroma, Weaviate, Pinecone e, naturalmente, Milvus. Li ho sottoposti tutti alle stesse prove: 1) Quanto è facile e veloce caricare direttamente da pandas nel database vettoriale? 2) Quanto è facile, veloce e configurabile ottenere buoni risultati di query dal database vettoriale? 3) Quanto è facile e configurabile eseguire RAG usando LangChain (futuro post del blog!).
Milvus si distingue
Tra tutti i database che ho esplorato, Milvus ha attirato la mia attenzione per diversi motivi. Innanzitutto, offriva un'esperienza intuitiva, soprattutto quando si inserivano dati direttamente da pandas con metadati, dato che questo è il primo approccio che un Data Scientist potrebbe provare.
Milvus ha attirato la mia attenzione anche per la sua velocità nel caricamento dei vettori e nelle query. Milvus era notevolmente più scattante rispetto ad altri approcci, alcuni dei quali erano lenti, persino su questa piccola scala. Ho anche notato le funzionalità e ho scelto le impostazioni predefinite per altri database (ricerca esaustiva IVF-flat con metrica L2), anche se Milvus supporta altre opzioni.
Di seguito è riportato un gist per inserire un data frame pandas in Milvus. Il codice completo è su il mio GitHub.
# Complete code is at: https://github.com/christy/ZillizDemos/blob/main/milvus_onboarding/hello_world_milvus.ipynb
###########
# 1. Download to use locally, a sentence transformer from HuggingFace Hub.
###########
import os
from dotenv import load_dotenv, find_dotenv
from huggingface_hub import login
_ = load_dotenv(find_dotenv())
hub_token = os.getenv("HUGGINGFACEHUB_API_TOKEN")
login(token=hub_token);
from sentence_transformers import SentenceTransformer
model_name = "BAAI/bge-base-en-v1.5"
retriever = SentenceTransformer(model_name, device="cuda")
# Get the model parameters and save for later.
MAX_SEQ_LENGTH = retriever.get_max_seq_length()
HF_EOS_TOKEN_LENGTH = 1
EMBEDDING_LENGTH = retriever.get_sentence_embedding_dimension()
###########
# 2. Choose a chunking function from LangChain for convenience.
###########
from langchain.text_splitter import RecursiveCharacterTextSplitter
chunk_size = MAX_SEQ_LENGTH - HF_TOKEN_EOS_LENGTH
chunk_overlap = np.round(chunk_size * 0.10, 0)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
length_function=len,
)
def chunk_text(text):
chunks = text_splitter.split_text(text)
return [chunk for chunk in chunks if chunk]
###########
# 3. Manipulate a pandas dataframe.
# Download: https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
###########
# 1. Batch of data from pandas DataFrame.
batch = df.head(100).copy()
# 2. Change primary key type to string.
batch["movie_index"] = batch["movie_index"].apply(lambda x: str(x))
# 3. Truncate reviews to 512 characters.
batch['chunk'] = batch['text'].apply(chunk_text)
batch = batch.explode('chunk', ignore_index=True)
# 4. Add embeddings as new column in df.
review_embeddings = torch.tensor(retriever.encode(batch['chunk']))
# Normalize embeddings to unit length.
review_embeddings = F.normalize(review_embeddings, p=2, dim=1)
# 5. Convert embeddings to list of `numpy.ndarray`, each containing `numpy.float32` numbers.
converted_values = list(map(np.float32, review_embeddings))
batch['embeddings'] = converted_values
# 6. Reorder columns for conveneince, so index first, labels at end.
new_order = ["movie_index", "text", "chunk", "embeddings", "label_int", "label"]
batch = batch[new_order]
###########
# 4. Install and import milvus.
###########
!pip install milvus pymilvus
import milvus, pymilvus
###########
# 5. Define schema for data loading into Milvus.
###########
# Set the Milvus collection name.
COLLECTION_NAME = "movies"
fields = [
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="movie_index", dtype=DataType.VARCHAR, max_length=8),
FieldSchema(name="chunk", dtype=DataType.VARCHAR, max_length=MAX_SEQ_LENGTH),
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=EMBEDDING_LENGTH),
FieldSchema(name="label_int", dtype=DataType.INT64),
FieldSchema(name="label", dtype=DataType.VARCHAR, max_length=8),
]
schema = CollectionSchema(fields, "Search imdb movie reviews")
mc = Collection(COLLECTION_NAME, schema, consistency_level="Eventually")
###########
6. Avvia un server Milvus locale (lite).
###########
default_server.start()
connections.connect(host='127.0.0.1',
port=default_server.listen_port,
show_startup_banner=True)
###########
# 7. Inserisci i dati in Milvus.
###########
# Mostra come modificare i parametri dell’indice, invece di usare quelli predefiniti.
index_params = {
"index_type": "HNSW",
"metric_type": "COSINE",
"params": {'M': 16, # int. 4~64, num_layers
"efConstruction": 32} # int. 8~512, num_nearest_neighbors
}
mc.create_index("embeddings", index_params)
insert_result = mc.insert(batch)
# Dopo l’inserimento dell’entità finale, chiama flush per fermare i segmenti in crescita rimasti in memoria.
mc.flush()
###########
# 8. Interroga il database.
###########
# Prima di condurre una ricerca o una query, devi caricare i dati in memoria.
mc.load()
# Definisci una domanda di esempio sui tuoi dati.
query = "Sono un medico, quale film dovrei guardare?"
# Incorpora la query usando lo stesso modello di embedding usato per creare la raccolta Milvus.
query_embeddings = torch.tensor(retriever.encode([query]))
# Normalizza gli embedding alla lunghezza unitaria.
query_embeddings = torch.nn.functional.normalize(query_embeddings, p=2, dim=1)
# Converti gli embedding in una lista di liste di np.float32.
query_embeddings = list(map(np.float32, query_embeddings))
# Esegui una ricerca vettoriale con indice HNSW.
TOP_K = 3
search_params = {
"M": 16,
"ef": 32,
}
results = mc.search(
data=query_embeddings,
anns_field="embeddings",
param=search_params,
output_fields=["movie_index", "chunk", "label"],
limit=TOP_K,
consistency_level="Eventually"
)
Dopo i miei test (rapidi, non ufficiali), ho compilato un modulo online per candidarmi a una posizione di Developer Advocate presso Zilliz. Dopo aver sostenuto il mio ultimo colloquio, il team di Zilliz è stato rapido nel farmi un’offerta. Quindi, senza esitazione, ho accettato!
Ho colleghi fantastici. Vedi i blog di Yujian Tang e Frank Liu sul perché si sono uniti a Zilliz. La mia responsabile, Chris Churilo, è il collante segreto del motivo per cui lavoriamo tutti insieme in modo così efficiente. Usa le sue conoscenze e la sua esperienza per farci brillare tutti. Il mio collega Filip Haltmayer è eccezionalmente paziente e bravo a spiegarmi tutto ciò che riguarda Milvus e Zilliz durante il mio onboarding. Il nostro CEO, Charles Xie, ha avuto la visione originale nel 2017 di costruire un database, soprattutto per dati non strutturati.
Cosa c’è dopo
Mentre inizio a svolgere attività di evangelism per Milvus, non vedo l’ora di conoscere tutti voi nella community degli sviluppatori AI! Organizzerò il Meetup Unstructured Data a San Francisco, dove cerco sempre ottimi speaker, location e co-host (contattatemi pure!). Scriverò più post sul blog e parlerò di più in pubblico (contattatemi pure!). Se volete provare Milvus open-source nel vostro progetto di dati non strutturati, fatemi sapere come posso aiutare!
Sono coinvolta in diverse organizzazioni di data science for good, tra cui DataKind, Women in Data Science e le San Francisco Civil Hack nights di Code for America (che mi hanno fatto conoscere la mia organizzazione locale Sonoma Safe Agriculture, dove ho creato una mappa interattiva dei pesticidi). Unitevi a me mentre porto le mie nuove conoscenze sui database vettoriali anche alla più ampia community della data-science-for-good.
Continua a leggere

How to Install and Run OpenClaw (Previously Clawdbot/Moltbot) on Mac
Turn your Mac into an AI gateway for WhatsApp, Telegram, Discord, iMessage, and more — in under 5 minutes.

Zilliz Cloud Delivers Better Performance and Lower Costs with Arm Neoverse-based AWS Graviton
Zilliz Cloud adopts Arm-based AWS Graviton3 CPUs to cut costs, speed up AI vector search, and power billion-scale RAG and semantic search workloads.

Milvus WebUI: A Visual Management Tool for Your Vector Database
Explore Milvus WebUI to monitor, manage, and optimize your vector database with real-time insights, performance tracking, and system health monitoring.



