O que é Pymilvus?
Introdução
Pymilvus é o SDK Python criado para Milvus e Zilliz Cloud. É um cliente baseado em gRPC que usa um protobuf Milvus comum compartilhado entre todos os SDKs. Tanto para usuários novos quanto avançados, ele fornece acesso a todos os recursos oferecidos pelo Milvus e é um dos nossos SDKs mais populares.
Problemas que estávamos encontrando
A ideia principal em torno do banco de dados vetorial Milvus é dar aos usuários o máximo possível de alavancas para ajudar a ajustar o sistema ao seu caso de uso específico. No entanto, a busca aproximada é, em sua essência, aproximada; não há um algoritmo único que sirva para todos. Cada um dos algoritmos se destaca em computação vs. velocidade vs. recall/precisão. Indo além, cada um dos algoritmos pode ser configurado para alcançar um equilíbrio diferente das categorias anteriores. Por exemplo, HNSW vs. IVF-PQ. O IVF-PQ é otimizado para computação e velocidade, reduzindo significativamente a carga de memória e os tempos de busca ao custo de uma redução significativa do recall. O HNSW é o oposto; o HNSW sacrifica computação em prol de velocidade e recall. O interessante é que seus pontos fortes podem ser trocados por meio de configuração. Toda essa configuração está apenas no nível do índice. No nível do cluster, há equilíbrios que precisam ser feitos em termos de custo vs. velocidade, o que é único para cada usuário. Alguns usuários podem não se importar com alta disponibilidade e não querem replicação. Alguns usuários podem não se importar com consistência e prefeririam ser menos consistentes em benefício da velocidade. Alguns usuários podem querer anexar um TTL aos seus dados para reduzir custos de armazenamento, enquanto outros desejam ter cada operação com backup. Embora essa personalização seja excelente para usuários grandes, nos quais extrair ao máximo o equilíbrio é benéfico em conjuntos de dados de tamanho bilionário, para usuários menores, todas essas alavancas apenas acrescentam confusão demais.
Além de essas alavancas serem um problema, no momento, Zilliz Cloud e Milvus não são intercambiáveis devido a índices e parâmetros de conexão.
O que é MilvusClient
MilvusClient é uma tentativa de simplificar a API para a maioria dos usuários. Muitos usuários não querem lidar com conexões, esquemas, indexação, carregamento, parâmetros etc. MilvusClient oculta todos esses aspectos ao envolver o SDK Pymilvus com uma API simples que é idêntica tanto para Milvus quanto para Zilliz. No momento, ele oferece:
- insert_data()
- upsert_data()
- search_data()
- query_data()
- get_vectors_by_pk()
- delete_by_pk()
- add_partition()
- remove_partition()
Essas funções foram consideradas as funções-chave de que qualquer usuário básico precisaria. No momento atual, as operações são oferecidas pelo Pymilvus, mas há muitas coisas extras que precisam ser feitas para garantir que elas funcionem corretamente.
insert_data:
Usando MilvusClient, não há necessidade de criar um esquema para uma coleção. Em vez disso, o esquema é gerado automaticamente a partir dos dados inseridos. Isso envolve determinar o FieldSchema necessário e como organizá-lo. Muitos usuários consideravam a criação desse esquema um ponto problemático, e é por isso que estamos fazendo isso nos bastidores. Assim que o esquema dinâmico for compatível, poderemos alterar a implementação sem mudanças para o usuário.
def _infer_fields(self, data):
"""Infer all the fields based on the input data."""
# TODO: Assuming ordered dict for 3.7
fields = {}
# Figure out each datatype of the input.
for key, value in data.items():
# Infer the corresponding datatype of the metadata
dtype = infer_dtype_bydata(value)
# Datatype isnt compatible
if dtype in (DataType.UNKNOWN, DataType.NONE):
logger.error(
"Failed to parse schema for collection %s, unrecognized dtype for key: %s",
self.collection_name,
key,
)
raise ValueError(f"Unrecognized datatype for {key}.")
# Create an entry under the field name
fields[key] = {}
fields[key]["name"] = key
fields[key]["dtype"] = dtype
# Area for attaching kwargs for certain datatypes
if dtype == DataType.VARCHAR:
fields[key]["max_length"] = 65_535
return fields
Para o MilvusClient, queríamos manter um formato de dados semelhante ao de outros projetos na área — uma lista de dicionários. Esse formato é fácil de entender e trabalhar e é equivalente aos Documents encontrados no LlamaIndex e no LangChain. No entanto, esse formato é incompatível com o pymilvus, pois a inserção do pymilvus recebe dados colunares como uma lista de listas. Esse formato de dados colunar não é fácil de trabalhar, pois envolve ordenar suas listas exatamente na mesma ordem em que seu esquema foi feito e não oferecia nenhuma flexibilidade. Além disso, as mensagens de erro recebidas para dados formatados incorretamente poderiam ser melhores.
for k in data:
for key, value in k.items():
if key in self.fields:
insert_dict.setdefault(key, []).append(value)
for i in self.tqdm(range(0, len(data), batch_size), disable=not progress_bar):
# Convert dict to list of lists batch for insertion
try:
insert_batch = [
insert_dict[key][i : i + batch_size]
for key in self.fields
if key != ignore_pk
]
Com todas as mudanças que virão no futuro para schema, JSONs, etc., ter um wrapper em torno de uma inserção simples nos permitirá fazer o trabalho pesado e deixar uma API simples para o usuário.
upsert_data:
Na versão 2.2, upsert não existe no Milvus. Para realizar um upsert, é necessário executar um delete -> insert. Como muitos usuários estão procurando esse recurso, decidimos incluí-lo no cliente. Assim que o recurso for adicionado ao pymilvus, poderemos alterá-lo facilmente sem exigir mudanças no código do usuário.
pks = [x[self.pk_field] for x in data]
self.delete_by_pk(pks, timeout)
ret = self.insert_data(
data=data,
timeout=timeout,
batch_size=batch_size,
partition=partition,
progress_bar=progress_bar,
)
search_data:
As principais modificações no comando de busca foram parâmetros de busca padrão e a conversão das saídas em uma lista de dicionários.
ret = []
for hits in res:
query_result = []
for hit in hits:
ret_dict = {x: hit.entity.get(x) for x in return_fields}
query_result.append({"score": hit.score, "data": ret_dict})
ret.append(query_result)
query_data:
As principais modificações no comando de consulta foram a conversão das saídas em uma lista de dicionários.
get_vectors_by_pk:
Extrair vetores no pymilvus é feito por meio de consultas. O que muitos usuários não sabem é que a consulta precisa ser feita com base em um filtro de chave primária. Além disso, se estiver usando uma chave primária varchar, a expressão na consulta precisaria ter aspas escapadas, algo tedioso e desconhecido para os usuários.
# Varchar pks need double quotes around the values
if self.fields[self.pk_field] == DataType.VARCHAR:
ids = ['"' + str(entry) + '"' for entry in pks]
expr = f"""{self.pk_field} in [{','.join(ids)}]"""
else:
ids = [str(entry) for entry in pks]
expr = f"{self.pk_field} in [{','.join(ids)}]"
delete_by_pk:
Semelhante ao get_vectors_by_pk.
add_partition e delete_partition:
Para a lógica de partition, os usuários precisam saber que alterar partitions requer descarregar e carregar uma collection. Isso agora é tratado nos bastidores.
Conclusão:
No geral, o principal objetivo deste cliente é adicionar operações fáceis de usar que não existem ou não são otimizadas no lado do pymilvus. À medida que o pymilvus melhorar, poderemos otimizar essas operações nos bastidores e manter uma API simples de usar.
Continue lendo

What Is a Vector Lakebase?
A Vector Lakebase is a unified, lake-native data architecture for AI that combines vector-database-grade serving with open lake storage, reusable lake-level indexes, and a shared semantic layer.

Zilliz Cloud Enterprise Vector Search Powers High-Performance AI on AWS
Zilliz Cloud on AWS powers secure, scalable, ultra-fast vector search for enterprise AI apps, with BYOC, sub-10ms latency, and zero-DevOps simplicity.

Vector Databases vs. Time Series Databases
Use a vector database for similarity search and semantic relationships; use a time series database for tracking value changes over time.



