Usando Seu Banco de Dados Vetorial como um Armazenamento de Dados JSON (ou Relacional)
TL;DR: Bancos de dados vetoriais oferecem suporte a CRUD sobre formatos de dados "tradicionais", como JSON. Se você é um desenvolvedor solo ou uma equipe pequena e não quer gerenciar muitas peças diferentes de infraestrutura de dados, pode usar Milvus ou Zilliz Cloud (o Milvus gerenciado) como seu único datastore e migrar facilmente coleções sem vetores para bancos de dados diferentes conforme escala.
Impulsionada pela popularidade do ChatGPT e de outros modelos de linguagem autorregressivos, a busca vetorial explodiu em popularidade no ano passado. Como resultado, vimos muitas empresas e organizações entrarem na onda da busca vetorial, desde provedores de bancos de dados NoSQL, como MongoDB (via Atlas Vector Search), até bancos de dados relacionais tradicionais, como Postgres (via pgvector). A mensagem geral que ouço em torno desses plugins de busca vetorial é, em grande parte, a mesma e soa mais ou menos assim: os desenvolvedores devem continuar conosco, já que você pode armazenar tabelas/JSON além de vetores, então não há necessidade de gerenciar várias peças de infraestrutura!
Esse tipo de declaração sempre me faz rir, pois claramente foi elaborada por equipes de marketing pouco sofisticadas. Não só a tecnologia por trás da busca vetorial é muito diferente das estratégias de armazenamento e consulta em bancos de dados relacionais e NoSQL, como também já é bastante conhecido que bancos de dados vetoriais podem armazenar relações, documentos JSON e outras fontes de dados estruturados. O primeiro ponto é difícil de ilustrar de forma concisa sem conhecimento prévio profundo de sistemas de gerenciamento de bancos de dados, mas o segundo ponto é bastante fácil de mostrar por meio de alguns pequenos trechos de código de exemplo. É a isso que este post do blog é dedicado.
Configuração
O Milvus armazena dados em unidades conhecidas como coleções, análogas a tabelas em bancos de dados relacionais. Cada coleção pode ter seu próprio esquema, e os esquemas têm um campo vetorial de dimensionalidade fixa, por exemplo, 768 para embeddings vetoriais baseados em e5-base. Vamos criar uma coleção para armazenar documentos JSON em vez de dados vetoriais. Para ilustrar melhor esse ponto, deixei de fora algumas das etapas anteriores e posteriores, como chamar collections.connect:
from pymilvus import Collection, CollectionSchema, DataType, FieldSchema
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True, max_length=100),
FieldSchema(name="_unused", dtype=DataType.FLOAT_VECTOR, dim=1)
]
schema = CollectionSchema(fields, "NoSQL data", enable_dynamic_field=True)
collection = Collection("json_data", schema)
collection.load()
Aqui, especificamos que esta coleção use os recursos de esquema dinâmico do Milvus, permitindo que a coleção aceite payloads JSON como dados "extras" associados a cada linha.
Espero que você não estivesse esperando mais, porque é só isso - é realmente simples assim.
Operações CRUD
Você pode interagir com a coleção que criamos acima como faria com qualquer outro banco de dados. Como exemplo, vamos baixar a lista de senadores atuais dos EUA (em formato JSON) do govtrack:
import requests
r = requests.get("https://www.govtrack.us/api/v2/role?current=true&role_type=senator")
data = r.json()["objects"]
len(data)
100
Podemos armazenar esses documentos diretamente no Milvus com apenas um pouquinho de manipulação de dados:
rows = [{"_unused": [0]} | d for d in data]
collection.insert(rows)
(insert count: 100, delete count: 0, upsert count: 0, ...
A partir daqui, podemos realizar consultas diretamente sobre esses dados:
collection.query(
expr="party like 'Dem%'",
limit=1,
output_fields=["person"]
)
[{'person': {'bioguideid': 'C000127',
'birthday': '1958-10-13',
'cspanid': 26137,
'fediverse_webfinger': None,
'firstname': 'Maria',
'gender': 'female',
'gender_label': 'Female',
'lastname': 'Cantwell',
'link': 'https://www.govtrack.us/congress/members/maria_cantwell/300018',
'middlename': '',
'name': 'Sen. Maria Cantwell [D-WA]',
'namemod': '',
'nickname': '',
'osid': 'N00007836',
'pvsid': None,
'sortname': 'Cantwell, Maria (Sen.) [D-WA]',
'twitterid': 'SenatorCantwell',
'youtubeid': 'SenatorCantwell'},
'id': 447376465724036249}]
Sem especificar nenhum campo vetorial, consultamos nosso banco de dados para obter o primeiro resultado em que o campo party no payload JSON associado tem "Dem" (Democrata) como prefixo.
Esperamos que esta etapa demonstre a capacidade de realizar buscas de dados estruturados no Milvus, mas não é uma consulta particularmente útil. Vamos encontrar todos os senadores do meu estado natal, Oregon:
collection.query(
expr="state in ['OR']",
limit=10,
output_fields=["person"]
)
[{'person': {'bioguideid': 'M001176',
'birthday': '1956-10-24',
'cspanid': 1029842,
'fediverse_webfinger': None,
'firstname': 'Jeff',
'gender': 'male',
'gender_label': 'Male',
'lastname': 'Merkley',
'link': 'https://www.govtrack.us/congress/members/jeff_merkley/412325',
'middlename': '',
'name': 'Sen. Jeff Merkley [D-OR]',
'namemod': '',
'nickname': '',
'osid': 'N00029303',
'pvsid': None,
'sortname': 'Merkley, Jeff (Sen.) [D-OR]',
'twitterid': 'SenJeffMerkley',
'youtubeid': 'SenatorJeffMerkley'},
'id': 447376465724036286},
{'person': {'bioguideid': 'W000779',
'birthday': '1949-05-03',
'cspanid': 1962,
'fediverse_webfinger': None,
'firstname': 'Ron',
'gender': 'male',
'gender_label': 'Male',
'lastname': 'Wyden',
'link': 'https://www.govtrack.us/congress/members/ron_wyden/300100',
'middlename': '',
'name': 'Sen. Ron Wyden [D-OR]',
'namemod': '',
'nickname': '',
'osid': 'N00007724',
'pvsid': None,
'sortname': 'Wyden, Ron (Sen.) [D-OR]',
'twitterid': 'RonWyden',
'youtubeid': 'senronwyden'},
'id': 447376465724036331}]
Embora tenhamos especificado limit=10, apenas dois documentos foram retornados (já que cada estado tem apenas dois senadores). Vamos restringir ainda mais nossa consulta para obter apenas o senador sênior:
collection.query(
expr="state in ['OR'] and senator_rank in ['senior']",
limit=10,
output_fields=["person"]
)
[{'person': {'bioguideid': 'W000779',
'birthday': '1949-05-03',
'cspanid': 1962,
'fediverse_webfinger': None,
'firstname': 'Ron',
'gender': 'male',
'gender_label': 'Male',
'lastname': 'Wyden',
'link': 'https://www.govtrack.us/congress/members/ron_wyden/300100',
'middlename': '',
'name': 'Sen. Ron Wyden [D-OR]',
'namemod': '',
'nickname': '',
'osid': 'N00007724',
'pvsid': None,
'sortname': 'Wyden, Ron (Sen.) [D-OR]',
'twitterid': 'RonWyden',
'youtubeid': 'senronwyden'},
'id': 447376465724036331}]
Talvez eu queira atualizar o perfil do senador Ron Wyden com um pouco mais de informação. Podemos fazer isso facilmente recuperando o documento inteiro com output_fields=["*"], atualizando o documento resultante e inserindo-o de volta em nosso banco de dados sem a chave primária antiga:
expr = "state in ['OR'] and senator_rank in ['senior']"
res = collection.query(
expr=expr,
limit=10,
output_fields=["*"]
)
res[0].update({
"elected_in": "1996",
"college": "Stanford University",
"college_major": "Political Science"
})
del res[0]["id"]
(contagem de inserções: 1, contagem de exclusões: 0, contagem de upserts: 0, ...
collection.delete(expr)
collection.insert(res)
Vamos ver se isso funcionou como esperado.
collection.query(
expr=expr,
limit=10,
output_fields=["elected_in", "college", "college_major"]
)
[{'elected_in': '1996',
'college': 'Stanford University',
'college_major': 'Political Science',
'id': 447376465724036353}]
Os dados de fato correspondem às atualizações que fizemos.
O Script Completo
Aqui está o script inteiro, do começo ao fim, por conveniência, sem as consultas extras. Usei nosso plano gratuito do Zilliz Cloud em vez do milvus-lite:
from milvus import default_server
from pymilvus import connections
from pymilvus import Collection, CollectionSchema, DataType, FieldSchema
import requests
# Uncomment this if you're using `milvus-lite`
#default_server.start()
#connections.connect(host="127.0.0.1", port=default_server.listen_port)
# Uncomment this if you're using Zilliz Cloud
connections.connect(
uri=os.environ["ZILLIZ_URI"],
token=os.environ["ZILLIZ_TOKEN"]
)
# Create the schema for our new collection. We set turn on Milvus' dynamic
# schema capability in order to store arbitratily large (or small) JSON blogs
# in each row.
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True, max_length=100),
FieldSchema(name="_unused", dtype=DataType.FLOAT_VECTOR, dim=1)
]
schema = CollectionSchema(fields, "Milvus as a JSON datastore", enable_dynamic_field=True)
# Now let's creat the collection.
collection = Collection("json_data", schema)
index_params = {
"index_type": "AUTOINDEX",
"metric_type": "L2",
"params": {}
}
collection.create_index(
field_name="_unused",
index_params=index_params
)
collection.load()
# Insert US senator JSON data into our newly formed collection.
r = requests.get("https://www.govtrack.us/api/v2/role?current=true&role_type=senator")
data = r.json()["objects"]
rows = [{"_unused": [0]} | d for d in data]
collection.insert(rows)
# Fetch the first Democrat in the database
top_k = 1
collection.query(
expr="state in ['OR'] and senator_rank in ['senior']",
limit=top_k,
output_fields=["person"]
)
[{'person': {'bioguideid': 'W000779',
'birthday': '1949-05-03',
'cspanid': 1962,
'fediverse_webfinger': None,
'firstname': 'Ron',
'gender': 'male',
'gender_label': 'Male',
'lastname': 'Wyden',
'link': 'https://www.govtrack.us/congress/members/ron_wyden/300100',
'middlename': '',
'name': 'Sen. Ron Wyden [D-OR]',
'namemod': '',
'nickname': '',
'osid': 'N00007724',
'pvsid': None,
'sortname': 'Wyden, Ron (Sen.) [D-OR]',
'twitterid': 'RonWyden',
'youtubeid': 'senronwyden'},
'id': 447376465724036331}]
Experimente você mesmo!
pymongo -> milvusmongo
Uma última observação antes de encerrar - criei um pequeno pacote Python chamado milvusmongo que implementa a funcionalidade CRUD mais básica do pymongo em coleções. Ele usa Milvus como o banco de dados subjacente em vez do MongoDB. Assim como pymongo, milvusmongo oferece suporte tanto a acesso no estilo dicionário quanto no estilo atributo, e abstrai a lógica extra necessária para chamadas CRUD (ou seja, insert_one, update_one e delete_one). Você pode instalá-lo com pip install milvusmongo:
% pip install milvus
% pip install milvusmongo
Depois disso, você pode iniciar uma instância incorporada do Milvus e usá-la em conjunto com milvusmongo para realizar consultas em dados JSON. Por exemplo:
from milvus import default_server
default_server.start()
from milvusmongo import MongoClient
client = MongoClient("127.0.0.1", 19530)
client.insert_one(my_document)
Observe que esta biblioteca tem como objetivo demonstrar a flexibilidade do Milvus como um armazenamento de dados, em vez de servir como algo que você deva usar em ambientes de produção em larga escala.
Palavras Finais
O Milvus não está aqui para substituir bancos de dados NoSQL ou mecanismos de busca textual lexical; estamos aqui para fornecer a você a melhor experiência possível de busca vetorial/filtrada. Mais importante ainda, estamos aqui para ajudar a acelerar a adoção da busca vetorial como tecnologia — é por isso que o open source é uma parte tão central do nosso ethos.
Mas isso não significa que não oferecemos suporte a outros tipos de dados. Como desenvolvedor solo ou uma pequena startup, você é livre para usar o Milvus como seu único armazenamento de dados. Você sempre pode otimizar o uso da sua infraestrutura mais tarde, conforme cresce. O Milvus fornecerá a você recursos de busca vetorial líderes da categoria, enquanto outros bancos de dados existem para armazenar, indexar e pesquisar outras formas de dados. Quando sua aplicação começar a exigir cargas de trabalho mais complexas (como joins ou agregações), é aí que você deverá considerar o uso de diferentes armazenamentos de dados.
Continue lendo

From Vector Database to Vector Lakebase
Zilliz offers a fully managed Vector Lakebase powered by Milvus, unifying real-time vector search, lake-scale discovery, and Al data operations.

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 BYOC Now Available Across AWS, GCP, and Azure
Zilliz Cloud BYOC is now generally available on all three major clouds. Deploy fully managed vector search in your own AWS, GCP, or Azure account — your data never leaves your VPC.



