O que difere entre pós-filtro e agregação global para pesquisa facetada?

Um problema comum nas interfaces de pesquisa é que você deseja retornar uma seleção de resultados, mas pode retornar informações sobre todos os documentos. (por exemplo, quero ver todas as camisas vermelhas, mas quero saber quais outras cores estão disponíveis).

Às vezes, isso é chamado de "resultados facetados" ou "navegação facetada". aexemplo da referência Elasticsearch é bastante claro ao explicar por que / como, então usei isso como base para esta pergunta.

Resumo / Pergunta: Parece que eu posso usar um pós-filtro ou uma agregação global para isso. Ambos parecem fornecer exatamente a mesma funcionalidade de uma maneira diferente. Pode haver vantagens ou desvantagens para eles que eu não vejo? Se sim, qual devo usar?

Eu incluí um exemplo completo abaixo com alguns documentos e uma consulta com os dois tipos de método com base no exemplo no guia de referência.

Opção 1: pós-filtro

Veja oexemplo da referência Elasticsearch

O que podemos fazer é ter mais resultados em nossa consulta original, para que possamos agregar esses resultados e depois filtrar nossos resultados reais.

O exemplo é bastante claro ao explicá-lo:

Mas talvez você também queira dizer ao usuário quantas camisas Gucci estão disponíveis em outras cores. Se você adicionar uma agregação de termos no campo de cores, você só receberá de volta a cor vermelha, porque sua consulta retorna apenas camisas vermelhas da Gucci.

Em vez disso, você deseja incluir camisas de todas as cores durante a agregação e aplicar o filtro de cores apenas aos resultados da pesquisa.

Veja como isso ficaria abaixo no código de exemplo.

Um problema é que não podemos usar o cache. Isso está no (ainda não disponível para 5.1)elasticsearch guide alertou sobre:

Consideração de desempenho Use um post_filter apenas se precisar filtrar diferencialmente os resultados e agregações da pesquisa. Às vezes, as pessoas usam o post_filter para pesquisas regulares.

Não faça isso! A natureza do post_filter significa que ele é executado após a consulta, portanto, qualquer benefício de desempenho da filtragem (como caches) é perdido completamente.

O post_filter deve ser usado apenas em combinação com agregações e somente quando você precisar de filtragem diferencial.

Existe, no entanto, uma opção diferente:

Opção 2: agregações globais

Existe uma maneira de fazer uma agregação que não é influenciada pela consulta de pesquisa. Então, em vez de obter muito, agregar isso e filtrar, apenas obtemos nossos resultados filtrados, mas fazemos agregações em tudo. Dê uma olhadana referência

Podemos obter exatamente os mesmos resultados. Não li nenhum aviso sobre armazenamento em cache para isso, mas parece que, no final, precisamos fazer a mesma quantidade de trabalho. Então essa talvez seja a única omissão.

É um pouco mais complicado por causa da subagregação de que precisamos (você não pode terglobal e umfilter no mesmo 'nível').

A única reclamação que li sobre consultas usando isso é que talvez você precise se repetir se precisar fazer isso para vários itens. No final, podemos gerar a maioria das consultas, portanto, repetir a si mesmo não é um problema tão grande para o meu caso de uso, e eu realmente não considero isso um problema parecido com "não é possível usar cache".

Pergunta, questão

Parece que ambas as funções se sobrepõem, no mínimo, ou possivelmente fornecem exatamente a mesma funcionalidade. Isso me confunde. Além disso, eu gostaria de saber se um ou outro tem uma vantagem que eu não vi e se há alguma prática recomendada aqui?

Exemplo

Isto é em grande parte dopágina de referência pós-filtro, mas eu adicionei ofiltro global inquerir.

mapeamento e documentos

PUT /shirts
{
    "mappings": {
        "item": {
            "properties": {
                "brand": { "type": "keyword"},
                "color": { "type": "keyword"},
                "model": { "type": "keyword"}
            }
        }
    }
}

PUT /shirts/item/1?refresh
{
    "brand": "gucci",
    "color": "red",
    "model": "slim"
}

PUT /shirts/item/2?refresh
{
    "brand": "gucci",
    "color": "blue",
    "model": "slim"
}


PUT /shirts/item/3?refresh
{
    "brand": "gucci",
    "color": "red",
    "model": "normal"
}


PUT /shirts/item/4?refresh
{
    "brand": "gucci",
    "color": "blue",
    "model": "wide"
}


PUT /shirts/item/5?refresh
{
    "brand": "nike",
    "color": "blue",
    "model": "wide"
}

PUT /shirts/item/6?refresh
{
    "brand": "nike",
    "color": "red",
    "model": "wide"
}

Agora, estamos solicitando todas as camisas vermelhas da Gucci (itens 1 e 3), os tipos de camisas que temos (magras e normais) para essas duas camisas e quais as cores da Gucci (vermelha e azul).

Primeiro, um filtro de postagem: obtenha todas as camisas, agregue os modelos de camisas vermelhas da gucci e as cores das camisas da gucci (todas as cores) e o filtro posterior das camisas da gucci vermelha para mostrar apenas os resultados: (isso é um pouco diferente de por exemplo, ao tentarmos chegar o mais próximo possível de uma aplicação clara de pós-filtros.)

GET /shirts/_search
{
  "aggs": {
    "colors_query": {
      "filter": {
        "term": {
          "brand": "gucci"
        }
      },
      "aggs": {
        "colors": {
          "terms": {
            "field": "color"
          }
        }
      }
    },
    "color_red": {
      "filter": {
        "bool": {
          "filter": [
            {
              "term": {
                "color": "red"
              }
            },
            {
              "term": {
                "brand": "gucci"
              }
            }
          ]
        }
      },
      "aggs": {
        "models": {
          "terms": {
            "field": "model"
          }
        }
      }
    }
  },
  "post_filter": {
    "bool": {
      "filter": [
        {
          "term": {
            "color": "red"
          }
        },
        {
          "term": {
            "brand": "gucci"
          }
        }
      ]
    }
  }
}

Também podemos obter todas as camisetas gucci vermelhas (nossa consulta inicial) e, em seguida, fazer uma agregação global para o modelo (para todas as camisetas gucci vermelhas) e para cores (para todas as camisetas gucci).

GET /shirts/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "color": "red"   }},
        { "term": { "brand": "gucci" }}
      ]
    }
  },
  "aggregations": {
    "color_red": {
      "global": {},
      "aggs": {
        "sub_color_red": {
          "filter": {
            "bool": {
              "filter": [
                { "term": { "color": "red"   }},
                { "term": { "brand": "gucci" }}
              ]
            }
          },
          "aggs": {
            "keywords": {
              "terms": {
                "field": "model"
              }
            }
          }
        }
      }
    },
    "colors": {
      "global": {},
      "aggs": {
        "sub_colors": {
          "filter": {
            "bool": {
              "filter": [
                { "term": { "brand": "gucci" }}
              ]
            }
          },
          "aggs": {
            "keywords": {
              "terms": {
                "field": "color"
              }
            }
          }
        }
      }
    }
  }
}

Ambos retornarão a mesma informação, a segunda apenas difere devido ao nível extra introduzido pelas sub-agregações. A segunda consulta parece um pouco mais complexa, mas não acho isso muito problemático. Uma consulta no mundo real é gerada por código, provavelmente muito mais complexo de qualquer maneira e deve ser uma boa consulta e, se isso significa complicado, que seja.

questionAnswers(2)

yourAnswerToTheQuestion