<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Mayya Sharipova - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Mayya Sharipova - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/pt/search-labs/author/mayya-sharipova</link>
    </image>
    <link>https://www.elastic.co/pt/search-labs/author/mayya-sharipova</link>
    <atom:link href="https://www.elastic.co/pt/search-labs/rss/author/mayya-sharipova.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[pt]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 19:53:53 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Indexação Vetorial Até 12x Mais Rápida no Elasticsearch com NVIDIA cuVS: Aceleração por GPU - Capítulo 2]]></title>
    <description><![CDATA[Descubra como o Elasticsearch alcança uma taxa de indexação quase 12x maior com indexação vetorial acelerada por GPU e NVIDIA cuVS.]]></description>
    <content:encoded><![CDATA[<p>No início deste ano, a Elastic anunciou a <a href="https://ir.elastic.co/news/news-details/2025/Elastic-Brings-Enterprise-Data-to-NVIDIA-AI-Factories/default.aspx">colaboração</a> com a NVIDIA para trazer aceleração de GPU ao Elasticsearch, integrando-se com a <a href="https://developer.nvidia.com/cuvs">NVIDIA cuVS</a>—conforme detalhado em uma <a href="https://www.nvidia.com/en-us/on-demand/session/gtc25-S71286/">sessão na NVIDIA GTC</a> e em vários <a href="https://www.elastic.co/search-labs/blog/gpu-accelerated-vector-search-elasticsearch-nvidia">blogs</a>. Esta postagem é uma atualização sobre o esforço de coengenharia com a equipe de busca vetorial da NVIDIA.</p><h2>Resumo</h2><p>Primeiro, vamos atualizá-lo. O Elasticsearch se estabeleceu como um poderoso banco de dados vetorial, oferecendo um rico conjunto de recursos e um forte desempenho para buscas por similaridade em larga escala. Com recursos como quantização escalar, Better Binary Quantization (<a href="https://www.elastic.co/search-labs/blog/better-binary-quantization-lucene-elasticsearch">BBQ</a>), operações vetoriais <a href="https://www.elastic.co/blog/accelerating-vector-search-simd-instructions">SIMD</a> e algoritmos mais eficientes em termos de disco, como <a href="https://www.elastic.co/search-labs/blog/diskbbq-elasticsearch-introduction">DiskBBQ</a>, ele já oferece opções eficientes e flexíveis para o gerenciamento de cargas de trabalho vetoriais.</p><p>Ao integrar o NVIDIA cuVS como um módulo chamável para tarefas de busca vetorial, buscamos entregar ganhos significativos no desempenho e eficiência da indexação vetorial para melhor suportar cargas de trabalho vetoriais em grande escala.</p><h2>O desafio</h2><p>Um dos maiores desafios na construção de um banco de dados vetorial de alto desempenho é a construção do índice vetorial - o gráfico <a href="https://arxiv.org/abs/1603.09320">HNSW</a>. Rapidamente, a construção de índices se torna dominada por milhões ou até bilhões de operações aritméticas, à medida que cada vetor é comparado com muitos outros. Além disso, operações do ciclo de vida do índice, como compactação e fusões, podem aumentar ainda mais a sobrecarga total de processamento da indexação. À medida que os volumes de dados e os embeddings vetoriais associados crescem exponencialmente, GPUs de computação acelerada, construídas para paralelismo massivo e matemática de alto rendimento, estão idealmente posicionadas para lidar com essas cargas de trabalho.</p><h2>Apresentando o plugin Elasticsearch-GPU</h2><p><a href="https://developer.nvidia.com/cuvs">NVIDIA cuVS</a> é uma biblioteca open source CUDA-X para busca vetorial acelerada por GPU e clustering de dados que permite a construção rápida de índices e recuperação de embeddings para cargas de trabalho de IA e recomendação.</p><p>O Elasticsearch utiliza o cuVS através do <a href="https://mvnrepository.com/artifact/com.nvidia.cuvs/cuvs-java">cuvs-java</a>, uma biblioteca de open source desenvolvida pela comunidade e mantida pela NVIDIA. A biblioteca cuvs-java é leve e se baseia na <a href="https://docs.rapids.ai/api/cuvs/nightly/c_api/">API C do cuVS</a>, utilizando a função estrangeira <a href="https://openjdk.org/projects/panama/">Panama</a> para expor os recursos do cuVS de uma maneira idiomática em Java, mantendo-se moderna e eficiente.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7fd7361099da05a/6a17e920be608670af00477f/5f6daa1eb07f704a6707d9e6b7ccb81d0abaa8c9-566x419.png" alt="Como o Elasticsearch funciona com NVIDIA cuVS, indexação por CPU e GPU" /><p>A biblioteca cuvs-java está integrada a um <a href="https://github.com/elastic/elasticsearch/pull/135545">novo plugin do Elasticsearch</a>; portanto, a indexação na GPU pode ocorrer no mesmo node e processo do Elasticsearch, sem a necessidade de provisionar qualquer código ou hardware externo. Durante a criação do índice, se a biblioteca cuVS estiver instalada e uma GPU estiver presente e configurada, o Elasticsearch usará a GPU para acelerar o processo de indexação vetorial. Os vetores são fornecidos à GPU, que constrói um gráfico <a href="https://arxiv.org/abs/2308.15136">CAGRA</a>. Esse gráfico é então convertido para o formato HNSW, tornando-o imediatamente disponível para busca vetorial na CPU. O formato final do gráfico construído é o mesmo que seria construído na CPU; isso permite que o Elasticsearch utilize GPUs para indexação de alto desempenho quando o hardware subjacente a suporta, liberando poder de processamento da CPU para outras tarefas (buscar, processamento de dados, etc.).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt485f55f29d6df5c4/6a17e922be6086dcf3004785/3ea255bd9bfd7983f78143c5eba999d2149d72be-671x356.png" alt="" /><h2>Aceleração de construção de índice</h2><p>Como parte da integração da aceleração de GPU no Elasticsearch, várias melhorias foram feitas no cuvs-java, focando na entrada/saída eficiente de dados e na invocação de funções. Uma melhoria importante é o uso de <a href="https://github.com/rapidsai/cuvs/blob/2cf5fa7666d703dccbe655f8214656b0952bb69b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMatrix.java">cuVSMatrix</a> para modelar vetores de forma transparente, independentemente de estarem na heap do Java, fora da heap ou na memória da GPU. Isso permite que os dados se movam eficientemente entre a memória e a GPU, evitando cópias desnecessárias de potencialmente bilhões de vetores.</p><p>Graças a essa abstração subjacente de cópia zero, tanto a transferência para a memória da GPU quanto a recuperação do gráfico podem ocorrer diretamente. Durante a indexação, os vetores são primeiro armazenados em buffer na memória do heap Java e depois enviados para a GPU para construir o gráfico CAGRA. O gráfico é posteriormente recuperado da GPU, convertido para o formato HNSW e persistido no disco.</p><p>No momento da fusão, os vetores já estão armazenar no disco, ignorando completamente o heap Java. Os arquivos de índice são mapeados em memória, e os dados são transferidos diretamente para a memória da GPU. O projeto também acomoda facilmente diferentes larguras de bits, como float32 ou int8, e se estende naturalmente a outros esquemas de quantização.</p><h2>Drumroll... então, como funciona?</h2><p>Antes de entrarmos nos números, um pouco de contexto é útil. A fusão de segmentos no Elasticsearch normalmente é executada de forma automática em segundo plano durante a indexação, o que dificulta a realização de testes de desempenho isoladamente. Para obter resultados reprodutíveis, usamos a fusão forçada para desencadear explicitamente a fusão de segmentos em um experimento controlado. Como a fusão forçada realiza as mesmas operações subjacentes de fusão que a fusão em segundo plano, seu desempenho serve como um indicador útil das melhorias esperadas, mesmo que os ganhos exatos possam diferir nas cargas de trabalho de indexação do mundo real.</p><p>Agora, vamos ver os números.</p><p>Nossos resultados iniciais de benchmark são muito promissores. Executamos o benchmark em uma instância AWS <code>g6.4xlarge</code> com armazenamento NVMe conectado localmente. Um único node do Elasticsearch foi configurado para usar o número padrão e ideal de threads de indexação (8 - uma para cada núcleo físico) e para desativar <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/merge">a limitação de mesclagem</a> (o que é menos aplicável com discos NVMe rápidos).</p><p>Para o conjunto de dados, usamos 2,6 milhões de vetores com 1.536 dimensões da <a href="https://github.com/elastic/rally-tracks/blob/master/openai_vector/README.md">trilha vetorial do OpenAI Rally</a>, codificados como <a href="https://github.com/elastic/elasticsearch/pull/137072">strings base64</a> e indexados como float32 <em>hnsw</em>. Em todos os cenários, os gráficos construídos atingem níveis de recall de até 95%. Veja o que descobrimos:</p><ul><li><p><strong>Taxa de transferência de indexação:</strong> ao transferir a construção de gráficos para a GPU durante as descargas de buffer na memória, aumentamos a taxa de transferência em cerca de 12 vezes.</p></li><li><p><strong>Fusão forçada:</strong> após a conclusão da indexação, a GPU continua acelerando a fusão de segmentos, acelerando a fase de mesclagem forçada em aproximadamente 7x.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfea4ee13b5a3b10d/6a17e923e9ea879c6aa9c616/f60ea9ee5996e456f393ffd195ee7eada6e5a7c2-948x387.png" alt="" /><ul><li><p><strong>Uso da CPU:</strong> o descarregamento da construção de gráficos para a GPU reduz significativamente a utilização média e de pico da CPU. Os gráficos abaixo ilustram o uso da CPU durante a indexação e a fusão, destacando o quanto é menor quando essas operações são executadas na GPU. Menor utilização da CPU durante a indexação da GPU libera ciclos de CPU que podem ser redirecionados para melhorar o desempenho da busca.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80ff9c53f9b6884a/6a17e925445de9ee4b4d0187/5e680a5fc41700a877f3d8b2e5ce18ebd3f37a0b-1600x562.png" alt="" /><ul><li><p><strong>Lembrete:</strong> a precisão permanece efetivamente a mesma entre as execuções de CPU e GPU, com o gráfico construído por GPU alcançando um recall marginalmente mais alto.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5cbe084eca27b8e4/6a17e926faa913317093c8b7/48a2b7758606bd321712b7d8378cd2640e652a4e-1384x544.png" alt="" /><h2>Comparando em outra dimensão: Preço</h2><p>A comparação anterior usava intencionalmente hardware idêntico, com a única diferença sendo se a GPU era usada durante a indexação. Essa configuração é útil para isolar efeitos brutos de computação, mas também podemos olhar para a comparação dos custos.</p><p>Por aproximadamente o mesmo preço por hora da configuração acelerada por GPU, é possível provisionar uma configuração apenas CPU com aproximadamente o dobro dos recursos comparáveis de CPU e memória: 32 vCPUs (AMD EPYC) e 64 GB de RAM, permitindo dobrar o número de threads de indexação para 16.</p><p>Para manter a comparação justa e consistente, executamos esse experimento apenas com CPU em uma instância AWS g6.8xlarge, com a GPU explicitamente desativada. Isso nos permitiu manter todas as outras características de hardware constantes ao avaliar a relação custo-desempenho da aceleração da GPU em comparação  com a indexação somente da CPU.</p><p>A instância mais potente da CPU mostra desempenho melhor em comparação com os benchmarks da seção acima, como era de se esperar. No entanto, ao compararmos essa instância de CPU mais potente com os resultados originais acelerados por GPU, a GPU ainda oferece ganhos de desempenho substanciais: <strong>melhoria de aproximadamente 5 vezes</strong> na taxa de transferência de indexação e <strong>aproximadamente 6 vezes </strong>na fusão forçada, tudo isso enquanto constrói gráficos que atingem níveis de recall de até <strong>95%</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt94b5eb6f95ba307d/6a17e928abe0f255d4dfea35/8ffa58cae3ad175ef2932a351aeef4c34a1407b9-948x394.png" alt="" /><h2>Conclusão</h2><p>Em cenários de ponta a ponta, a aceleração de GPU com NVIDIA cuVS proporciona quase 12x de melhoria na taxa de indexação e uma redução de 7x na latência de fusão forçada, com uma utilização significativamente menor da CPU. Isso mostra que a indexação vetorial e as cargas de trabalho de fusão se beneficiam significativamente da aceleração da GPU. Em uma comparação ajustada ao custo, a aceleração da GPU continua a gerar ganhos substanciais de desempenho, com taxa de transferência de indexação aproximadamente 5 vezes maior e operações de fusão forçada 6 vezes mais rápidas.</p><p>A indexação de vetores acelerada por GPU está atualmente planejada para Prévia Técnica no Elasticsearch 9.3, que está programada para ser lançada no início de 2026.</p><p>Fique ligado para mais.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-gpu-accelerated-vector-indexing-nvidia</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-gpu-accelerated-vector-indexing-nvidia</guid>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <dc:creator><![CDATA[Chris Hegarty,Hemant Malik,Corey Nolet,Manas Singh,Mithun Radhakrishnan,Mayya Sharipova,Lorenzo Dematte,Ben Frederickson]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1248d51633bd75d9/6a17e92ae9ea8714b3a9c61a/08f7469a4daaf67b7c5999585aae179b6680c78d-896x746.png" length="0" type="image/png"/>
    <pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Acelerando a fusão de gráficos HNSW]]></title>
    <description><![CDATA[Explore o trabalho que temos feito para reduzir a sobrecarga de construção de vários gráficos HNSW, particularmente reduzindo o custo de mesclagem de gráficos.]]></description>
    <content:encoded><![CDATA[<p>No passado, <a href="https://www.elastic.co/pt/search-labs/blog/multi-graph-vector-search">discutimos</a> alguns dos desafios de ter que pesquisar em vários <a href="https://www.elastic.co/pt/search-labs/blog/hnsw-graph">grafos HNSW</a> e como conseguimos mitigá-los. Naquela ocasião, mencionamos algumas melhorias adicionais que tínhamos planejado. Este post é o culminar desse trabalho.</p><p>Você pode perguntar: por que usar vários gráficos? Este é um efeito colateral de uma escolha arquitetônica no Lucene: segmentos imutáveis. Como acontece com a maioria das escolhas arquitetônicas, há prós e contras. Por exemplo, recentemente disponibilizamos o Elasticsearch sem servidor. Nesse contexto, obtivemos benefícios muito significativos de segmentos imutáveis, incluindo replicação de índice eficiente e a capacidade de desacoplar índice e computação de consulta e dimensioná-los automaticamente de forma independente. Para quantização vetorial, as fusões de segmentos nos dão a oportunidade de atualizar parâmetros para adaptá-los às características dos dados. Nessa linha, acreditamos que há outras vantagens proporcionadas pela oportunidade de medir características de dados e revisitar opções de indexação.</p><p>Nesta postagem, discutiremos o trabalho que temos feito para reduzir significativamente a sobrecarga de construção de vários gráficos HNSW e, em particular, para reduzir o custo de mesclagem de gráficos.</p><h3>Histórico</h3><p>Para manter um número gerenciável de segmentos, o Lucene verifica periodicamente se deve mesclar segmentos. Isso equivale a verificar se a contagem de segmentos atual excede uma contagem de segmentos de destino, que é determinada pelo tamanho do segmento base e pela política de mesclagem. Se a contagem for excedida, o Lucene mescla grupos de segmentos enquanto a restrição for violada. Este processo foi descrito em detalhes <a href="https://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html">em outro lugar</a>.</p><p>Lucene opta por mesclar segmentos de tamanhos semelhantes porque isso atinge um crescimento logarítmico na amplificação de gravação. No caso de um índice vetorial, a amplificação de escrita é o número de vezes que um vetor será inserido em um gráfico. O Lucene tentará mesclar segmentos em grupos de aproximadamente 10. Consequentemente, os vetores são inseridos em um gráfico aproximadamente vezes, onde  é a contagem do vetor de índice e  é a contagem do vetor de segmento base esperado. Devido ao crescimento logarítmico, a amplificação da gravação é de um dígito, mesmo para índices grandes. Entretanto, o tempo total gasto na fusão de gráficos é linearmente proporcional à amplificação da gravação.</p><p>Ao mesclar gráficos HNSW, já fazemos uma pequena otimização: mantendo o gráfico do maior segmento e inserindo vetores dos outros segmentos nele. Esta é a razão do fator 9/10 acima. Abaixo mostramos como podemos melhorar significativamente usando informações de todos os gráficos que estamos mesclando.</p><h3>Fusão de gráficos HNSW</h3><p>Anteriormente, mantínhamos o grafo maior e inseríamos vetores dos demais, ignorando os grafos que os continham. A principal conclusão que utilizamos a seguir é que cada grafo HNSW descartado contém informações importantes sobre a proximidade dos vetores que ele contém. Gostaríamos de usar essas informações para acelerar a inserção, pelo menos de alguns, dos vetores.</p><p>Nós nos concentramos no problema de inserir um gráfico menor  em um gráfico maior , já que esta é uma operação atômica que podemos usar para construir qualquer política de mesclagem.</p><p>A estratégia é encontrar um subconjunto de vértices de  para inserir no gráfico grande. Em seguida, usamos a conectividade desses vértices no pequeno gráfico para acelerar a inserção dos vértices restantes . A seguir, usamos  e  para denotar os vizinhos de um vértice  no gráfico pequeno e grande, respectivamente. Esquematicamente o processo é o seguinte.</p><p><code>MERGE-HNSW</code></p><p><code>Inputs </code><code> and </code></p><p><code>1</code><code>Find </code><code> to insert into </code><code> using COMPUTE-JOIN-SET</code>
<code>2</code><code>Insert each vertex </code><code> into </code>
<code>3</code><code>for </code><code> do</code>
<code>4</code>
<code>5</code>
<code>6</code><code>FAST-SEARCH-LAYER</code>
<code>7</code><code>SELECT-NEIGHBORS-HEURISTIC</code>
<code>8</code></p><p>Calculamos o conjunto  usando um procedimento que discutiremos abaixo (linha 1). Em seguida, inserimos cada vértice em  no gráfico grande usando o procedimento de inserção padrão HNSW (linha 2). Para cada vértice que não inserimos, encontramos seus vizinhos que inserimos e seus vizinhos no gráfico grande (linhas 4 e 5). Usamos um procedimento <code>FAST-SEARCH-LAYER</code> semeado com este conjunto (linha 6) para encontrar os candidatos para o <code>SELECT-NEIGHBORS-HEURISTIC</code> do <a href="https://arxiv.org/pdf/1603.09320">artigo</a> HNSW (linha 7). Na verdade, estamos substituindo <code>SEARCH-LAYER</code> para encontrar o conjunto de candidatos no método <code>INSERT</code> (Algoritmo 1 do artigo), que de outra forma não será alterado. Por fim, adicionamos o vértice que acabamos de inserir em  (linha 8).</p><p>É claro que para que isso funcione, cada vértice em  deve ter pelo menos um vizinho em . Na verdade, exigimos que para cada vértice em  que  para algum , a conectividade máxima da camada. Observamos que em gráficos HNSW reais vemos uma grande dispersão de graus de vértices. A figura abaixo mostra uma função de densidade cumulativa típica do grau do vértice para a camada inferior de um gráfico Lucene HNSW.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc815e1a9c3bb0d06/6a17e178ec0f89308a5a6564/44f001b3a1bc6627e172fed5c52a02cfdcb4cd66-1324x898.png" alt="Gráfico HNSW: Exemplo de distribuição de graus dos vértices" /><p>Exploramos o uso de um valor fixo para  e também o tornamos uma função do grau do vértice. Esta segunda opção leva a maiores acelerações com impacto mínimo na qualidade do gráfico, então optei pela seguinte opção</p><p>Observe que | é igual ao grau do vértice  no gráfico pequeno por definição. Ter um limite inferior de dois significa que inseriremos todos os vértices cujo grau seja menor que dois.</p><p>Um argumento de contagem simples sugere que se escolhermos  cuidadosamente, precisamos apenas inserir em torno de  em  diretamente. Especificamente, colorimos uma aresta do gráfico se inserirmos exatamente um de seus vértices finais em . Então sabemos que para cada vértice em  ter pelo menos  vizinhos em  precisamos colorir pelo menos  arestas. Além disso, esperamos que</p><p>Aqui,  é o grau médio do vértice no pequeno gráfico. Para cada vértice  colorimos no máximo  arestas. Portanto, o número total de arestas que esperamos colorir é no máximo . Esperamos que, ao escolher  cuidadosamente, possamos colorir perto desse número de arestas e, portanto, para cobrir todos os vértices,  precisa satisfazer</p><p>Isso implica que .</p><p>Se <code>SEARCH-LAYER</code> dominar o tempo de execução, isso sugere que poderíamos atingir uma velocidade de até  maior no tempo de mesclagem. Dado o crescimento logarítmico da amplificação de gravação, isso significa que mesmo para índices muito grandes, normalmente dobraríamos apenas o tempo de construção em comparação à construção de um gráfico.</p><p>O risco dessa estratégia é que prejudicamos a qualidade do gráfico. Inicialmente tentamos com um no-op <code>FAST-SEARCH-LAYER</code>. Descobrimos que isso degrada a qualidade do gráfico a ponto de a recuperação como função da latência ser impactada, principalmente ao mesclar em um único segmento. Em seguida, exploramos várias alternativas usando uma busca limitada do gráfico. No final, a escolha mais eficaz foi a mais simples. Use <code>SEARCH-LAYER</code> mas com um <code>ef_construction</code> baixo. Com essa parametrização conseguimos obter gráficos de excelente qualidade e ainda diminuir o tempo de mesclagem em pouco mais de 30% em média.</p><h3>Calculando o conjunto de junção</h3><p>Encontrar um bom conjunto de junção pode ser formulado como um problema de cobertura de grafos HNSW. Uma heurística gulosa é uma heurística simples e eficaz para aproximar coberturas ótimas de grafos. A abordagem que adotamos seleciona os vértices um de cada vez para adicionar a  em ordem decrescente de ganho. O ganho é definido da seguinte forma:</p><p>Aqui,  denota a contagem de vizinhos de um vetor  em  e  é a função indicadora. O ganho inclui a mudança na contagem do vértice que adicionamos a , ou seja, , pois nos aproximamos do nosso objetivo adicionando um vértice menos coberto. O cálculo do ganho é ilustrado na figura abaixo para o vértice central laranja.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7a353d56fa09af5f/6a17e17a2f4a5c33f7fa8825/fe11cd55a7d94d9e0b0f4d47ea309a99075c355d-540x474.png" alt="Ganho de vértice a ser adicionado para unir o conjunto J no grafo HNSW" /><p>Mantemos o seguinte estado para cada vértice :</p><ol><li><p>Seja velho,</p></li><li><p>Seu ganho ,</p></li><li><p>A contagem de vértices adjacentes em  denotada por ,</p></li><li><p>Um número aleatório no intervalo [0,1] que é usado para desempate.</p></li></ol><p>O pseudocódigo para calcular o conjunto de junções é o seguinte.</p><p><code>COMPUTE-JOIN-SET</code></p><p><code>Inputs </code></p><p><code>1</code>
<code>2</code>
<code>3</code><code>for </code><code> do</code>
<code>4</code>
<code>5</code>
<code>6</code>
<code>7</code><code>while </code><code> do
8</code><code> maximum gain vertex in </code>
<code>9</code><code>Remove the state for </code><code> from </code>
<code>10</code><code>if </code><code> is not stale then</code>
<code>11</code>
<code>12</code>
<code>13</code><code>for </code><code> do</code>
<code>14</code><code>mark </code><code> as stale if </code>
<code>15</code><code>mark neighbors of </code><code> stale if </code><code>
16</code><code>
17</code><code>else
18</code><code>
19</code><code>if </code><code> then
20</code><code>
21</code><code>return </code></p><p>Primeiro inicializamos o estado nas linhas 1-5.</p><p>Em cada iteração do loop principal, extraímos inicialmente o vértice de ganho máximo (linha 8), desfazendo empates aleatoriamente. Antes de fazer qualquer alteração, precisamos verificar se o ganho do vértice está obsoleto. Em particular, cada vez que adicionamos um vértice em  , afetamos o ganho de outros vértices:</p><ol><li><p>Como todos os seus vizinhos têm um vizinho adicional em  seus ganhos podem mudar (linha 14)</p></li><li><p>Se algum dos seus vizinhos estiver agora totalmente coberto, os ganhos de todos os seus vizinhos podem mudar (linhas 14-16)</p></li></ol><p>Nós recalculamos os ganhos de forma lenta, então só recalculamos o ganho de um vértice se quisermos inseri-lo em  (linhas 18-20). Como os ganhos sempre diminuem, nunca podemos perder um vértice que devemos inserir.</p><p>Observe que precisamos apenas monitorar o ganho total de vértices que adicionamos a  para determinar quando sair. Além disso, enquanto  pelo menos um vértice terá ganho diferente de zero, então sempre progredimos.</p><h3>Resultados</h3><p>Realizamos experimentos em quatro conjuntos de dados que juntos abrangem nossas três métricas de distância suportadas (euclidiana, cosseno e produto interno):</p><ol><li><p>quora-E5-small: 522931 documentos, 384 dimensões e usa similaridade de cosseno,</p></li><li><p>cohere-wikipedia-v2: 1 milhão de documentos, 768 dimensões e usa similaridade de cosseno,</p></li><li><p>gist: 1M documentos, 960 dimensões e utiliza distância euclidiana e</p></li><li><p>cohere-wikipedia-v3: 1 milhão de documentos, 1.024 dimensões e usa o produto interno máximo.</p></li></ol><p>Para cada conjunto de dados, avaliamos dois níveis de quantização:</p><ol><li><p>int8 – que usa um inteiro de 1 byte por dimensão e</p></li><li><p>Churrasco – que usa um único bit por dimensão.</p></li></ol><p>Por fim, para cada experimento, avaliamos a qualidade da pesquisa em duas profundidades de recuperação e examinamos depois da construção do índice e depois da fusão forçada em um único segmento.</p><p>Em resumo, alcançamos acelerações substanciais e consistentes na indexação e mesclagem, mantendo a qualidade do gráfico e, consequentemente, o desempenho da pesquisa em todos os casos.</p><h4>Experimento 1: quantização int8</h4><p>As acelerações médias da linha de base até o candidato, as mudanças propostas, são:</p><p>Aceleração do tempo de índice: <strong>1,28</strong></p><p>Forçar aceleração de fusão: <strong>1,72</strong></p><p>Isso corresponde à seguinte repartição nos tempos de execução</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8422be122ef1a9c9/6a17e17bbe6086522e00467d/5f9f6d487b4c74c4998aa47465912c1a9743e928-734x479.png" alt="Tempos de indexação e mesclagem para as estratégias de mesclagem de base e candidatas" /><p>Para completar, os horários exatos são</p><p></p><p>Índice</p><p></p><p>Mesclar</p><p></p><p>Conjunto de dados</p><p>linha de base</p><p>candidato</p><p>Criar</p><p>candidato</p><p>quora-E5-pequeno</p><p>112,41s</p><p>81,55s</p><p>113,81s</p><p>70,87s</p><p>wiki-cohere-v2</p><p>158,1s</p><p>122,95s</p><p>425,20s</p><p>239,28s</p><p>essência</p><p>141,82s</p><p>119,26s</p><p>536,07s</p><p>279,05s</p><p>wiki-cohere-v3</p><p>211,86s</p><p>168,22s</p><p>654,97s</p><p>414,12s</p><p>Abaixo, mostramos os gráficos de recall versus latência que comparam o candidato (linhas tracejadas) à linha de base em duas profundidades de recuperação: recall@10 e recall@100 para índices com vários segmentos (o resultado final da nossa estratégia de mesclagem padrão após indexar todos os vetores) e após a mesclagem forçada para um único segmento. Uma curva mais alta e mais à esquerda é melhor, o que significa maior recuperação com menor latência.</p><p>Como você pode ver, para índices de múltiplos segmentos, o candidato é melhor para o conjunto de dados Cohere v3 e um pouco pior, mas quase comparável, para todos os outros conjuntos de dados. Após a fusão em um único segmento, as curvas de recall são quase idênticas para todos os casos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf674622469bf6a90/6a17e17dfbc5f874a84919c9/9195297f19f90b172d832ba56bdada7b0d8a768b-985x392.png" alt="Lembre-se de @10 e @100 vs latência após a construção do índice" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltde89f7e94ac823f4/6a17e17fe9ea876429a9c507/c866f32d579ae2b841e92ca733dd29c0e214ac6b-986x386.png" alt="Lembre-se de @10 e @100 vs latência após a fusão em um único segmento" /><h4>Experimento 2: quantização BBQ</h4><p>As acelerações médias da linha de base até o candidato são:</p><p>Aceleração do tempo de índice: <strong>1,33</strong></p><p>Forçar aceleração de fusão: <strong>1,34</strong></p><p>Isso corresponde à seguinte repartição nos tempos de execução</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5b0eb305222fa5c2/6a17e18125daab514f08a18c/11be0cf6b63480dc703409329357ea4847b55051-740x415.png" alt="Índice e tempo de mesclagem para as estratégias de mesclagem de base e candidatas" /><p>Para completar, os horários exatos são</p><p></p><p>Índice</p><p></p><p>Mesclar</p><p></p><p>Conjunto de dados</p><p>linha de base</p><p>candidato</p><p>Criar</p><p>candidato</p><p>quora-E5-pequeno</p><p>70,71s</p><p>58,25s</p><p>59,38s</p><p>40,15s</p><p>wiki-cohere-v2</p><p>203,08s</p><p>142,27s</p><p>107,27s</p><p>85,68s</p><p>essência</p><p>110,35s</p><p>105,52s</p><p>323,66s</p><p>202,2s</p><p>wiki-cohere-v3</p><p>313,43s</p><p>190,63s</p><p>165,98s</p><p>159,95s</p><p>Para índices de múltiplos segmentos, o candidato é melhor para quase todos os conjuntos de dados, exceto o Cohere v2, onde a linha de base é ligeiramente melhor. Para os índices de segmento único, as curvas de recall são quase idênticas para todos os casos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb12174abeadbcdd1/6a17e1822f4a5c4cc2fa8829/7da1be27bab5a7f5f9c9a1882ea35761a4a0ba5c-973x383.png" alt="Lembre-se de @10 e @100 vs latência após a construção do índice" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf1b88d4f7fec9905/6a17e184414c64a8de9450b4/a26af30a56c55a12addee7e4fb7e8f606f366668-979x386.png" alt="Lembre-se de @10 e @100 vs latência tendo sido mesclados em um único segmento" /><h3>Conclusão</h3><p>O algoritmo discutido neste blog estará disponível no próximo Lucene 10.2 e na versão do Elasticsearch baseada nele. Os usuários poderão aproveitar o desempenho de mesclagem aprimorado e o tempo reduzido de criação de índice nessas novas versões. Essa mudança faz parte do nosso esforço contínuo para tornar o Lucene e o Elasticsearch rápidos e eficientes para pesquisas vetoriais e híbridas.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hnsw-graphs-speed-up-merging</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hnsw-graphs-speed-up-merging</guid>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <category><![CDATA[Lucene]]></category>
    <dc:creator><![CDATA[Thomas Veasey,Mayya Sharipova]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9fca6a01d0541cfb/6a17e187033c8d46486bb0e1/49a6c880f5dedd0fa502ece5be124824ee218cc0-1792x1024.png" length="0" type="image/png"/>
    <pubDate>Mon, 07 Apr 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>