Blog

Elasticsearch BBQ vs. OpenSearch FAISS: Comparação de desempenho de pesquisa vetorial

Uma comparação de desempenho entre o Elasticsearch BBQ e o OpenSearch FAISS.

Pesquisa vetorial com quantização binária: Elasticsearch com BBQ é 5x mais rápido que OpenSearch com FAISS. A Elastic recebeu solicitações da nossa comunidade para esclarecer as diferenças de desempenho entre o Elasticsearch e o OpenSearch, particularmente no âmbito da Pesquisa Semântica/Pesquisa Vetorial, por isso conduzimos esses testes de desempenho para fornecer comparações claras e baseadas em dados.

Elasticsearch BBQ vs. OpenSearch FAISS - Comparação de velocidade e taxa de transferência (recall)

Confronto de quantização binária

Armazenar vetores de alta dimensão em sua forma original pode exigir muita memória. Técnicas de quantização comprimem esses vetores em uma representação compacta, reduzindo drasticamente o consumo de memória. A busca então opera no espaço comprimido, o que reduz a complexidade computacional e torna as buscas mais rápidas, especialmente em grandes conjuntos de dados.

A Elastic está empenhada em fazer do Lucene um mecanismo vetorial de alto desempenho. Introduzimos a Quantização Binária Aprimorada (BBQ) no Elasticsearch 8.16, com base no Lucene, e aprimoramos ainda mais nas versões 8.18 e 9.0. O BBQ é baseado em uma nova abordagem de quantização escalar que reduz as dimensões de ponto flutuante de 32 bits, proporcionando uma redução de memória de aproximadamente 95%, mantendo uma alta qualidade de classificação.

O OpenSearch, por outro lado, usa vários mecanismos de vetores: nmslib (agora obsoleto), Lucene e FAISS. Em um blog anterior, comparamos o Elasticsearch e o OpenSearch para pesquisa vetorial. Usamos três conjuntos de dados diferentes e testamos diferentes combinações de mecanismos e configurações em ambos os produtos.

Este blog se concentra nos algoritmos de quantização binária atualmente disponíveis em ambos os produtos. Testamos o Elasticsearch com BBQ e o OpenSearch com a Quantização Binária do FAISS usando a trilha Rally openai_vector .

O objetivo principal era avaliar o desempenho de ambas as soluções sob o mesmo nível de recall. O que significa recall ? Recall é uma métrica que mede quantos resultados relevantes são recuperados com sucesso por um sistema de pesquisa.

Nesta avaliação, recall@k é particularmente importante, onde k representa o número de resultados principais considerados. Recall@10, Recall@50 e Recall@100 medem, portanto, quantos dos resultados verdadeiramente relevantes aparecem nos 10, 50 e 100 principais itens recuperados, respectivamente. A recordação é expressa em uma escala de 0 a 1 (ou precisão de 0% a 100%). E isso é importante porque estamos falando de KNN Aproximado (ANN) e não de KNN Exato, onde a recordação é sempre 1 (100%).

Para cada valor de k também especificamos n, que é o número de candidatos considerados antes de aplicar a classificação final. Isso significa que para Recall@10, Recall@50 e Recall@100, o sistema primeiro recupera n candidatos usando o algoritmo de quantização binária e depois os classifica para determinar se os k principais resultados contêm os itens relevantes esperados.

Ao controlar n, podemos analisar o trade-off entre eficiência e precisão. Um n mais alto normalmente aumenta a recuperação, pois mais candidatos estão disponíveis para classificação, mas também aumenta a latência e diminui a taxa de transferência. Por outro lado, um n menor acelera a recuperação, mas pode reduzir a recordação se poucos candidatos relevantes forem incluídos no conjunto inicial.

Nesta comparação, o Elasticsearch demonstrou menor latência e maior rendimento que o OpenSearch em configurações idênticas.

Metodologia

A configuração completa, juntamente com os scripts do Terraform, os manifestos do Kubernetes e a trilha Rally específica estão disponíveis neste repositório em openai_vector_bq.

Assim como nos benchmarks anteriores, usamos um cluster Kubernetes composto por:

  • 1 pool de nós para Elasticsearch 9.0 com 3 máquinas e2-standard-32 (128 GB de RAM e 32 CPUs)

  • 1 pool de nós para OpenSearch 2.19 com 3 máquinas e2-standard-32 (128 GB de RAM e 32 CPUs)

  • 1 pool de nós para Rally com 2 máquinas e2-standard-4 (16 GB de RAM e 4 CPUs)

Configuração da metodologia Elasticsearch BBQ vs Opensearch FAISS

Configuramos um cluster Elasticsearch versão 9.0 e um cluster OpenSearch versão 2.19.

Tanto o Elasticsearch quanto o OpenSearch foram testados com exatamente a mesma configuração: usamos o Rally track openai_vector com algumas modificações , que usa 2,5 milhões de documentos do conjunto de dados NQ enriquecidos com embeddings gerados usando o modelo text-embedding-ada-002 do OpenAI.

{
  "source-file": "open_ai_corpus-initial-indexing.json.bz2",
  "document-count": 2580961,
  "compressed-bytes": 32076749416,
  "uncompressed-bytes": 90263571686
}

Os resultados relatam a latência e a taxa de transferência medidas em diferentes níveis de recall (recall@10, recall@50 e recall@100) usando 8 clientes simultâneos para executar operações de pesquisa. Usamos um único fragmento e nenhuma réplica.

Executamos as seguintes combinações de kn-rescore, por exemplo 10-2000-2000, ou k:10, n:2000 e rescore:2000 recuperariam os k (10) principais sobre n candidatos (2000) aplicando uma rescore sobre 2000 resultados (o que é equivalente a um “fator de sobreamostragem” de 1). Cada pesquisa foi executada 10.000 vezes, com 1.000 pesquisas como aquecimento:

Recall@10

  • 10-40-40

  • 10-50-50

  • 10-100-100

  • 10-200-200

  • 10-500-500

  • 10-750-750

  • 10-1000-1000

  • 10-1500-1500

  • 10-2000-2000

Recall@50

  • 50-150-150

  • 50-200-200

  • 50-250-250

  • 50-500-500

  • 50-750-750

  • 50-1000-1000

  • 50-1200-1200

  • 50-1500-1500

  • 50-2000-2000

Lembre-se @100

  • 100-200-200

  • 100-250-250

  • 100-300-300

  • 100-500-500

  • 100-750-750

  • 100-1000-1000

  • 100-1200-1200

  • 100-1500-1500

  • 100-2000-2000

Para replicar o benchmark, os manifestos do Kubernetes para rally-elasticsearch e rally-opensearch têm todas as variáveis relevantes externalizadas em um ConfigMap, disponível aqui (ES) e aqui (OS). O parâmetro search_ops pode ser personalizado para testar qualquer combinação de k, n e rescore.

Configuração do OpenSearch Rally

/k8s/rally-openai_vector-os-bq.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: rally-params-os
  labels:
    app: rally-opensearch
data:
  user-tags.json: |
    {
      "product": "OpenSearch",
      "product-version": "OpenSearch-2.19.0",
      "product-label": "OpenSearch-2.19-faiss",
      "benchmark-run": "19-feb-recall@100"
    }
  track-params.json: |
    {
      "mapping_type": "vectors-only-mapping-with-docid",
      "standalone_search_clients": 8,
      "standalone_search_iterations": 5000,
      "ann_threshold": 0,
      "vector_mode": "on_disk",
      "compression_level": "32x",
      "vector_method_name": "hnsw",
      "vector_method_engine": "faiss",
      "search_ops": [
        [100, 200, 200],
        [100, 250, 250],
        [100, 300, 300],
        [100, 500, 500],
        [100, 750, 750],
        [100, 1000, 1000],
        [100, 1200, 1200],
        [100, 1500, 1500],
        [100, 2000, 2000]
      ]
    }

Configuração do índice Opensearch

As variáveis do ConfigMap são então usadas na configuração do índice, alguns parâmetros são deixados inalterados. A quantização de 1 bit no OpenSearch é configurada definindo o nível de compressão como “32x”.

index-vectors-only-mapping-with-docid-mapping.json

{
  "settings": {
    {% if preload_pagecache %}
    "index.store.preload": [
      "vec", "vex", "vem", "veq", "veqm", "veb", "vebm"
    ],
    {% endif %}
    "index.number_of_shards": {{ number_of_shards | default(1) }},
    "index.number_of_replicas": {{ number_of_replicas | default(0) }},
    "index.knn": true,
    "index.knn.advanced.approximate_threshold": {{ ann_threshold | default(15000) }}
  },
  "mappings": {
    "dynamic": false,
    "properties": {
      "docid": {
        "type": "keyword"
      },
      "emb": {
        "type": "knn_vector",
        "dimension": 1536,
        "space_type": "innerproduct",
        "data_type": "float",
        "mode": {{ vector_mode | default("in_memory") | tojson }},
        "compression_level": {{ compression_level | default("32x") | tojson }},
        "method": {
          "name": {{ vector_method_name | default("hnsw") | tojson }},
          "engine": {{ vector_method_engine | default("faiss") | tojson }},
          "parameters": {
            "ef_construction": 100,
            "m": 16
          }
        }
      }
    }
  }
}

Configuração do Elasticsearch Rally

/k8s/rally-openai_vector-es-bq.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: rally-params-es
  labels:
    app: rally-elasticsearch
data:
  user-tags.json: |
    {
      "product": "Elasticsearch",
      "product-version": "Elasticsearch-9.0.0-ade01164",
      "product-label": "Elasticsearch-9.0-BBQ",
      "benchmark-run": "19-feb-recall@100"
    }
  track-params.json: |
    {
      "mapping_type": "vectors-only-mapping-with-docid",
      "standalone_search_clients": 8,
      "standalone_search_iterations": 5000,
      "vector_index_type": "bbq_hnsw",
      "search_ops": [
        [100, 200, 200],
        [100, 250, 250],
        [100, 300, 300],
        [100, 500, 500],
        [100, 750, 750],
        [100, 1000, 1000],
        [100, 1200, 1200],
        [100, 1500, 1500],
        [100, 2000, 2000]
      ]
    }

Configuração do índice do Elasticsearch

index-vectors-only-mapping-with-docid-mapping.json

{
  "settings": {
    {# non-serverless-index-settings-marker-start #}
    {%- if build_flavor != "serverless" or serverless_operator == true -%}
    {% if preload_pagecache %}
    "index.store.preload": [ "vec", "vex", "vem", "veq", "veqm", "veb", "vebm" ],
    {% endif %}
    "index.number_of_shards": {{ number_of_shards | default(1) }},
    "index.number_of_replicas": {{ number_of_replicas | default(0) }}
    {%- endif -%}
    {# non-serverless-index-settings-marker-end #}
  },
  "mappings": {
    "dynamic": false,
    "properties": {
      "docid": {
        "type": "keyword"
      },
      "emb": {
        "type": "dense_vector",
        "element_type": "float",
        "dims": 1536,
        "index": true,
        "similarity": "dot_product",
        "index_options": {
          "type": {{ vector_index_type | default("bbq_hnsw") | tojson }},
          "ef_construction": 100,
          "m": 16
        }
      }
    }
  }
}

Resultados

Há várias maneiras de interpretar os resultados. Tanto para latência quanto para taxa de transferência, criamos um gráfico simplificado e detalhado em cada nível de recall. É fácil ver diferenças se considerarmos “quanto maior, melhor” para cada métrica. No entanto, a latência é negativa (quanto menor, melhor), enquanto a taxa de transferência é positiva. Para os gráficos simplificados, usamos (recall / latência) * 10000 (chamado simplesmente de “velocidade”) e recall * throughput, então ambas as métricas significam que mais velocidade e mais throughput são melhores. Vamos lá.

Recall @ 10 - simplificado

Nesse nível de recall, o Elasticsearch BBQ é até 5x mais rápido (3,9x mais rápido em média) e tem 3,2x mais taxa de transferência em média do que o OpenSearch FAISS.

O Elasticsearch BBQ é até 5 vezes mais rápido (3,9 vezes mais rápido em média) e tem 3,2 vezes mais capacidade de processamento em média do que o OpenSearch FAISS em termos de velocidade e capacidade de processamento (Recall@10).
O Elasticsearch BBQ é até 5 vezes mais rápido (3,9 vezes mais rápido em média) e tem 3,2 vezes mais capacidade de processamento em média do que o OpenSearch FAISS.

Recall @ 10 - Detalhado

Comparação detalhada da latência recall@10 entre Elasticsearch BBQ e Opensearch FAISS
Comparação detalhada do desempenho de recall@10 entre Elasticsearch BBQ e Opensearch FAISS.

tarefa

latência.média

rendimento.média

recuperação média

Elasticsearch-9.0-BBQ

10-100-100

11,70

513,58

0,89

Elasticsearch-9.0-BBQ

10-1000-100

27,33

250,55

0,95

Elasticsearch-9.0-BBQ

10-1500-1500

35,93

197,26

0,95

Elasticsearch-9.0-BBQ

10-200-200

13,33

456,16

0,92

Elasticsearch-9.0-BBQ

10-2000-2000

44,27

161,40

0,95

Elasticsearch-9.0-BBQ

10-40-40

10,97

539,94

0,84

Elasticsearch-9.0-BBQ

10-50-50

11h00

535,73

0,85

Elasticsearch-9.0-BBQ

10-500-500

19,52

341,45

0,93

Elasticsearch-9.0-BBQ

10-750-750

22,94

295,19

0,94

OpenSearch-2.19-faiss

10-100-100

35,59

200,61

0,94

OpenSearch-2.19-faiss

10-1000-1000

156,81

58,30

0,96

OpenSearch-2.19-faiss

10-1500-1500

181,79

42,97

0,96

OpenSearch-2.19-faiss

10-200-200

47,91

155,16

0,95

OpenSearch-2.19-faiss

10-2000-2000

232,14

31,84

0,96

OpenSearch-2.19-faiss

10-40-40

27,55

249,25

0,92

OpenSearch-2.19-faiss

10-50-50

28,78

245,14

0,92

OpenSearch-2.19-faiss

10-500-500

79,44

97,06

0,96

OpenSearch-2.19-faiss

10-750-750

104,19

75,49

0,96

Recall @ 50 - simplificado

Nesse nível de recall, o Elasticsearch BBQ é até 5x mais rápido (4,2x mais rápido em média) e tem 3,9x mais rendimento em média do que o OpenSearch FAISS.

Comparação de desempenho vetorial Recal @50: Elasticsearch BBQ vs Opensearch FAISS
O Elasticsearch BBQ é até 5 vezes mais rápido (4,2 vezes mais rápido em média) e tem 3,9 vezes mais capacidade de processamento em média do que o OpenSearch FAISS.

Resultados detalhados - Recall @ 50

Resultados de latência do Recall@50 Elasticsearch BBQ e Opensearch FAISS
Resultados de throughput do Elasticsearch BBQ e Opensearch FAISS no Recall@50

Tarefa

Média de latência

Média de rendimento

Recall médio

Elasticsearch-9.0-BBQ

50-1000-1000

25,71

246,44

0,95

Elasticsearch-9.0-BBQ

50-1200-1200

28,81

227,85

0,95

Elasticsearch-9.0-BBQ

50-150-150

13,43

362,90

0,90

Elasticsearch-9.0-BBQ

50-1500-1500

33,38

202,37

0,95

Elasticsearch-9.0-BBQ

50-200-200

12,99

406,30

0,91

Elasticsearch-9.0-BBQ

50-2000-2000

42,63

163,68

0,95

Elasticsearch-9.0-BBQ

50-250-250

14,41

373,21

0,92

Elasticsearch-9.0-BBQ

50-500-500

17h15

341,04

0,93

Elasticsearch-9.0-BBQ

50-750-750

31,25

248,60

0,94

OpenSearch-2.19-faiss

50-1000-1000

125,35

62,53

0,96

OpenSearch-2.19-faiss

50-1200-1200

143,87

54,75

0,96

OpenSearch-2.19-faiss

50-150-150

43,64

130,01

0,89

OpenSearch-2.19-faiss

50-1500-1500

169,45

46,35

0,96

OpenSearch-2.19-faiss

50-200-200

48,05

156,07

0,91

OpenSearch-2.19-faiss

50-2000-2000

216,73

36,38

0,96

OpenSearch-2.19-faiss

50-250-250

53,52

142,44

0,93

OpenSearch-2.19-faiss

50-500-500

78,98

97,82

0,95

OpenSearch-2.19-faiss

50-750-750

103,20

75,86

0,96

Recall @ 100

Nesse nível de recall, o Elasticsearch BBQ é até 5x mais rápido (média de 4,6x mais rápido) e tem 3,9x mais taxa de transferência em média do que o OpenSearch FAISS.

Relembrando os resultados do Elasticsearch BBQ VS Opensearch FAISS @100
Comparação de desempenho de latência e taxa de transferência do Elasticsearch BBQ e do Opensearch FAISS

Resultados detalhados - Recall @ 100

Resultados detalhados de latência - Recall @ 100 Elasticsearch BBQ vs Opensearch FAISS
Resultados detalhados de desempenho - Recall @ 100 Elasticsearch BBQ vs Opensearch FAISS.

tarefa

latência.média

rendimento.média

recuperação média

Elasticsearch-9.0-BBQ

100-1000-1000

27,82

243,22

0,95

Elasticsearch-9.0-BBQ

100-1200-1200

31.14

224.04

0,95

Elasticsearch-9.0-BBQ

100-1500-1500

35,98

193,99

0,95

Elasticsearch-9.0-BBQ

100-200-200

14.18

403,86

0,88

Elasticsearch-9.0-BBQ

100-2000-2000

45,36

159,88

0,95

Elasticsearch-9.0-BBQ

100-250-250

14,77

433,06

0,90

Elasticsearch-9.0-BBQ

100-300-300

14,61

375,54

0,91

Elasticsearch-9.0-BBQ

100-500-500

18,88

340,37

0,93

Elasticsearch-9.0-BBQ

100-750-750

23,59

285,79

0,94

OpenSearch-2.19-faiss

100-1000-1000

142,90

58,48

0,95

OpenSearch-2.19-faiss

100-1200-1200

153,03

51,04

0,95

OpenSearch-2.19-faiss

100-1500-1500

181,79

43,20

0,96

OpenSearch-2.19-faiss

100-200-200

50,94

131,62

0,83

OpenSearch-2.19-faiss

100-2000-2000

232,53

33,67

0,96

OpenSearch-2.19-faiss

100-250-250

57,08

131,23

0,87

OpenSearch-2.19-faiss

100-300-300

62,76

120,10

0,89

OpenSearch-2.19-faiss

100-500-500

84,36

91,54

0,93

OpenSearch-2.19-faiss

100-750-750

111,33

69,95

0,94

Melhorias no churrasco

BBQ percorreu um longo caminho desde seu primeiro lançamento. No Elasticsearch 8.16, para fins de comparação, incluímos uma execução de benchmark da versão 8.16 junto com a atual, e podemos ver como a recuperação e a latência melhoraram desde então.

Melhorias na latência de recall do Elasticsearch 9.0 BBQ comparadas com o Elasticsearch 8.16 BBQ

No Elasticsearch 8.18 e 9.0, reescrevemos o algoritmo principal para quantizar os vetores. Então, embora o BBQ na versão 8.16 fosse bom, as versões mais recentes são ainda melhores. Você pode ler sobre isso aqui e aqui. Em resumo, cada vetor é quantizado individualmente por meio de quantis escalares otimizados. Como resultado, os usuários se beneficiam de maior precisão na pesquisa de vetores sem comprometer o desempenho, tornando a recuperação de vetores do Elasticsearch ainda mais poderosa.

Conclusão

Nesta comparação de desempenho entre o Elasticsearch BBQ e o OpenSearch FAISS, o Elasticsearch supera significativamente o OpenSearch para pesquisa vetorial, alcançando velocidades de consulta até 5x mais rápidas e uma taxa de transferência 3,9x maior, em média, em vários níveis de recuperação.

As principais descobertas incluem:

  • Recall@10: O Elasticsearch BBQ é até 5x mais rápido (3,9x mais rápido em média) e tem 3,2x mais taxa de transferência em média em comparação ao OpenSearch FAISS.

  • Recall@50: O Elasticsearch BBQ é até 5x mais rápido (4,2x mais rápido em média) e tem 3,9x mais taxa de transferência em média em comparação ao OpenSearch FAISS.

  • Recall@100: O Elasticsearch BBQ é até 5x mais rápido (4,6x mais rápido em média) e tem 3,9x mais taxa de transferência em média em comparação ao OpenSearch FAISS.

Esses resultados destacam as vantagens de eficiência e desempenho do Elasticsearch BBQ, particularmente em cenários de pesquisa vetorial de alta dimensão. A técnica Better Binary Quantization (BBQ), introduzida no Elasticsearch 8.16, proporciona redução substancial de memória (~95%) enquanto mantém alta qualidade de classificação, tornando-a uma escolha superior para aplicações de pesquisa vetorial em larga escala.

Na Elastic, estamos inovando incansavelmente para melhorar o Apache Lucene e o Elasticsearch para fornecer o melhor banco de dados vetorial para casos de uso de pesquisa e recuperação, incluindo RAG (Retrieval Augmented Generation). Nossos avanços recentes aumentaram drasticamente o desempenho, tornando a pesquisa vetorial mais rápida e mais eficiente em termos de espaço do que antes, aproveitando os ganhos do Lucene 10. Este blog é outra ilustração dessa inovação.

Conteúdo relacionado

LINQ para Elasticsearch ES|QL: escreva Consultas em C# e Consulte o Elasticsearch

Florian Bernd

Aprimorando as capacidades de chatbots com PNL e busca vetorial no Elasticsearch.

Priscilla Parodi

Elasticsearch x OpenSearch: comparação de desempenho da busca vetorial

Ugo Sangiorgi

Detecção de plágio por IA: usando o Elasticsearch

Priscilla Parodi

Técnicas avançadas de RAG, parte 2: Consultas e testes

Han Xiang Choong

Pronto para criar buscas de última geração?

Uma pesquisa suficientemente avançada não se consegue apenas com o esforço de uma só pessoa. O Elasticsearch é impulsionado por cientistas de dados, especialistas em operações de aprendizado de máquina, engenheiros e muitos outros que são tão apaixonados por buscas quanto você. Vamos nos conectar e trabalhar juntos para construir a experiência de busca mágica que lhe trará os resultados desejados.

Experimente você mesmo(a)