Pular para o conteúdo principal
O conjunto de dados Laion-400M contém 400 milhões de imagens com legendas em inglês. Atualmente, a Laion disponibiliza um conjunto de dados ainda maior, mas trabalhar com ele é semelhante. O conjunto de dados contém a URL da imagem, embeddings da imagem e da legenda, uma pontuação de similaridade entre a imagem e a legenda, além de metadados, como a largura/altura da imagem, a licença e um indicador NSFW. Podemos usar o conjunto de dados para demonstrar a busca aproximada por vizinhos mais próximos no ClickHouse.

Preparação dos dados

Os embeddings e os metadados são armazenados em arquivos separados nos dados brutos. Uma etapa de preparação dos dados baixa os dados, combina os arquivos, converte-os para CSV e os importa para o ClickHouse. Você pode usar o script download.sh abaixo para isso:
O script process.py é definido da seguinte maneira:
Para iniciar o pipeline de preparação de dados, execute:
O conjunto de dados está dividido em 410 arquivos; cada arquivo contém cerca de 1 milhão de linhas. Se você quiser trabalhar com um subconjunto menor dos dados, basta ajustar os limites, por exemplo, seq 0 9 | .... (O script em Python acima é muito lento (~2 a 10 minutos por arquivo), consome muita memória (41 GB por arquivo), e os arquivos CSV resultantes são grandes (10 GB cada), então tenha cuidado. Se você tiver RAM suficiente, aumente o valor de -P1 para obter mais paralelismo. Se isso ainda for muito lento, considere adotar um processo de ingestão melhor — talvez convertendo os arquivos .npy para Parquet e depois fazendo todo o restante do processamento com ClickHouse.)

Criar tabela

Para criar inicialmente uma tabela sem índices, execute:
Para importar os arquivos CSV no ClickHouse:
Observe que a coluna id é apenas ilustrativa e é preenchida pelo script com valores repetidos. Para fazer uma busca vetorial aproximada por força bruta, execute:
target é um array de 512 elementos e um parâmetro fornecido pelo cliente. Uma forma conveniente de obter arrays desse tipo será apresentada no final do artigo. Por enquanto, podemos usar o embedding de uma imagem aleatória de um conjunto LEGO como target. Resultado

Execute uma busca vetorial aproximada por similaridade com um índice de similaridade vetorial

Agora, vamos definir dois índices de similaridade vetorial na tabela.
Os parâmetros e as considerações de desempenho para a criação de índices e a busca são descritos na documentação. A definição de índice acima especifica um índice HNSW usando a “distância de cosseno” como métrica de distância, com o parâmetro “hnsw_max_connections_per_layer” definido como 64 e o parâmetro “hnsw_candidate_list_size_for_construction” definido como 256. O índice usa números de ponto flutuante brain de meia precisão (bfloat16) como quantização para otimizar o uso de memória. Para compilar e materializar o índice, execute estas instruções:
A criação e o salvamento do índice podem levar alguns minutos ou até horas, dependendo da quantidade de linhas e dos parâmetros do índice HNSW. Para realizar uma busca vetorial, basta executar a mesma consulta novamente:
Resultado
A latência da consulta diminuiu significativamente porque os vizinhos mais próximos foram recuperados usando o índice vetorial. A busca por similaridade vetorial usando um índice de similaridade vetorial pode retornar resultados ligeiramente diferentes dos da busca por força bruta. Um índice HNSW pode atingir um recall próximo de 1 (a mesma acurácia da busca por força bruta) com uma seleção cuidadosa dos parâmetros do HNSW e com a avaliação da qualidade do índice.

Criando embeddings com UDFs

Em geral, é desejável criar embeddings para novas imagens ou novas legendas de imagens e buscar pares semelhantes de imagem/legenda nos dados. Podemos usar UDF para criar o vetor target sem sair do cliente. É importante usar o mesmo modelo para criar os dados e os novos embeddings usados nas buscas. Os scripts a seguir utilizam o modelo ViT-B/32, que também é a base do conjunto de dados.

Embeddings de texto

Primeiro, salve o script Python abaixo no diretório user_scripts/ do caminho de dados do ClickHouse e torne-o executável (chmod +x encode_text.py). encode_text.py:
Em seguida, crie encode_text_function.xml em um local indicado por <user_defined_executable_functions_config>/path/to/*_function.xml</user_defined_executable_functions_config> no arquivo de configuração do servidor ClickHouse.
Agora, basta usar:
A primeira execução será lenta porque carrega o modelo, mas as execuções subsequentes serão rápidas. Depois, podemos copiar a saída para SET param_target=... e escrever consultas com facilidade. Como alternativa, a função encode_text() pode ser usada diretamente como argumento da função cosineDistance :
Observe que a própria UDF encode_text() pode levar alguns segundos para calcular e gerar o vetor de embedding.

Embeddings de imagem

Embeddings de imagem podem ser criados de forma semelhante, e fornecemos um script em Python capaz de gerar o embedding de uma imagem armazenada localmente em um arquivo. encode_image.py
encode_image_function.xml
Baixe uma imagem de exemplo para a busca:
Em seguida, execute esta consulta para gerar o embedding da imagem acima:
A consulta de pesquisa completa é:
Última modificação em 1 de julho de 2026