🚀 Experimente o Zilliz Cloud, o Milvus totalmente gerenciado, gratuitamente—experimente um desempenho 10x mais rápido! Experimente Agora>>

milvus-logo
LFAI

Utilização

  • Engineering
February 07, 2022
Lichen Wang

Com um processamento unificado de batch e stream e uma arquitetura nativa da nuvem, o Milvus 2.0 representa um desafio maior do que o seu antecessor durante o desenvolvimento da função DELETE. Graças ao seu design avançado de desagregação de armazenamento-computação e ao mecanismo flexível de publicação/assinatura, temos o orgulho de anunciar que conseguimos. No Milvus 2.0, é possível apagar uma entidade de uma determinada coleção com a sua chave primária, de modo a que a entidade apagada deixe de ser listada no resultado de uma pesquisa ou consulta.

Note-se que a operação DELETE no Milvus refere-se à eliminação lógica, enquanto que a limpeza física dos dados ocorre durante a Compactação de Dados. A eliminação lógica não só aumenta consideravelmente o desempenho da pesquisa limitada pela velocidade de I/O, mas também facilita a recuperação de dados. Os dados eliminados logicamente podem ainda ser recuperados com a ajuda da função Time Travel.

Utilização

Vamos experimentar primeiro a função DELETE no Milvus 2.0. (O exemplo a seguir usa PyMilvus 2.0.0 em Milvus 2.0.0).

from pymilvus import connections, utility, Collection, DataType, FieldSchema, CollectionSchema
# Connect to Milvus
connections.connect(
    alias="default", 
    host='x.x.x.x', 
    port='19530'
)
# Create a collection with Strong Consistency level
pk_field = FieldSchema(
    name="id", 
    dtype=DataType.INT64, 
    is_primary=True, 
)
vector_field = FieldSchema(
    name="vector", 
    dtype=DataType.FLOAT_VECTOR, 
    dim=2
)
schema = CollectionSchema(
    fields=[pk_field, vector_field], 
    description="Test delete"
)
collection_name = "test_delete"
collection = Collection(
    name=collection_name, 
    schema=schema, 
    using='default', 
    shards_num=2,
    consistency_level="Strong"
)
# Insert randomly generated vectors
import random
data = [
    [i for i in range(100)],
    [[random.random() for _ in range(2)] for _ in range(100)],
]
collection.insert(data)
# Query to make sure the entities to delete exist
collection.load()
expr = "id in [2,4,6,8,10]"
pre_del_res = collection.query(
    expr,
    output_fields = ["id", "vector"]
)
print(pre_del_res)
# Delete the entities with the previous expression
collection.delete(expr)
# Query again to check if the deleted entities exist
post_del_res = collection.query(
    expr,
    output_fields = ["id", "vector"]
)
print(post_del_res)

Implementação

Em uma instância do Milvus, um nó de dados é responsável principalmente pelo empacotamento de dados de streaming (logs no corretor de logs) como dados históricos (instantâneos de logs) e pela descarga automática deles para o armazenamento de objetos. Um nó de consulta executa pedidos de pesquisa em dados completos, ou seja, tanto dados de fluxo contínuo como dados históricos.

Para tirar o máximo partido da capacidade de escrita de dados dos nós paralelos de um cluster, o Milvus adopta uma estratégia de sharding baseada no hashing de chaves primárias para distribuir uniformemente as operações de escrita pelos diferentes nós de trabalho. Ou seja, o proxy encaminha as mensagens (ou seja, os pedidos) da Linguagem de Manipulação de Dados (DML) de uma entidade para o mesmo nó de dados e nó de consulta. Estas mensagens são publicadas através do canal DML e consumidas pelo nó de dados e pelo nó de consulta separadamente para fornecer serviços de pesquisa e consulta em conjunto.

Nó de dados

Depois de receber as mensagens INSERT de dados, o nó de dados insere os dados num segmento crescente, que é um novo segmento criado para receber dados em fluxo contínuo na memória. Se a contagem de linhas de dados ou a duração do segmento crescente atingir o limiar, o nó de dados sela-o para impedir a entrada de quaisquer dados. O nó de dados então libera o segmento selado, que contém os dados históricos, para o armazenamento de objeto. Entretanto, o nó de dados gera um filtro bloom baseado nas chaves primárias dos novos dados e descarrega-o para o armazenamento de objectos juntamente com o segmento selado, guardando o filtro bloom como uma parte do registo binário de estatísticas (binlog), que contém a informação estatística do segmento.

Um filtro bloom é uma estrutura de dados probabilística que consiste em um vetor binário longo e uma série de funções de mapeamento aleatório. Pode ser utilizado para testar se um elemento é um membro de um conjunto, mas pode devolver falsos positivos. -- Wikipedia

Quando as mensagens DELETE de dados chegam, o nó de dados armazena em buffer todos os filtros bloom no fragmento correspondente, e combina-os com as chaves primárias fornecidas nas mensagens para recuperar todos os segmentos (tanto dos crescentes como dos selados) que possivelmente incluem as entidades a eliminar. Tendo identificado os segmentos correspondentes, o nó de dados armazena-os em memória para gerar os binlogs Delta para registar as operações de eliminação e, em seguida, descarrega esses binlogs juntamente com os segmentos de volta para o armazenamento de objectos.

Data Node Nó de dados

Como um fragmento é atribuído apenas a um canal DML, nós de consulta extras adicionados ao cluster não poderão assinar o canal DML. Para garantir que todos os nós de consulta podem receber as mensagens DELETE, os nós de dados filtram as mensagens DELETE do canal DML e encaminham-nas para o canal Delta para notificar todos os nós de consulta das operações de eliminação.

Nó de consulta

Ao carregar uma coleção a partir do armazenamento de objectos, o nó de consulta obtém primeiro o ponto de controlo de cada fragmento, que marca as operações DML desde a última operação de descarga. Com base no ponto de controlo, o nó de consulta carrega todos os segmentos selados juntamente com os seus filtros Delta binlog e bloom. Com todos os dados carregados, o nó de consulta então se inscreve no DML-Channel, Delta-Channel e Query-Channel.

Se mais mensagens INSERT de dados chegarem depois que a coleção for carregada na memória, o nó de consulta primeiro identifica os segmentos crescentes de acordo com as mensagens e atualiza os filtros bloom correspondentes na memória apenas para fins de consulta. Esses filtros bloom dedicados à consulta não serão descarregados para o armazenamento de objectos depois de a consulta estar concluída.

Query Node Nó de consulta

Tal como referido anteriormente, apenas um determinado número de nós de consulta pode receber mensagens DELETE do canal DML, o que significa que apenas estes podem executar os pedidos DELETE em segmentos crescentes. Para os nós de consulta que subscreveram o canal DML, filtram primeiro as mensagens DELETE nos segmentos crescentes, localizam as entidades fazendo corresponder as chaves primárias fornecidas com os filtros bloom dedicados à consulta dos segmentos crescentes e, em seguida, registam as operações de eliminação nos segmentos correspondentes.

Os nós de consulta que não podem subscrever o canal DML só estão autorizados a processar pedidos de pesquisa ou consulta em segmentos selados porque só podem subscrever o canal Delta e receber as mensagens DELETE encaminhadas pelos nós de dados. Tendo recolhido todas as mensagens DELETE nos segmentos selados do Delta-Channel, os nós de consulta localizam as entidades fazendo corresponder as chaves primárias fornecidas com os filtros bloom dos segmentos selados e, em seguida, registam as operações de eliminação nos segmentos correspondentes.

Eventualmente, numa pesquisa ou consulta, os nós de consulta geram um conjunto de bits com base nos registos de eliminação para omitir as entidades eliminadas e pesquisar entre as entidades restantes de todos os segmentos, independentemente do estado do segmento. Por último, mas não menos importante, o nível de consistência afecta a visibilidade dos dados eliminados. Sob Strong Consistency Level (como mostrado no exemplo de código anterior), as entidades excluídas são imediatamente invisíveis após a exclusão. Enquanto o Nível de consistência limitado é adotado, haverá vários segundos de latência antes de as entidades eliminadas se tornarem invisíveis.

O que vem a seguir?

No blogue da série de novas funcionalidades 2.0, pretendemos explicar a conceção das novas funcionalidades. Leia mais nesta série de blogues!

Try Managed Milvus for Free

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

Get Started

Like the article? Spread the word

Continue Lendo