Чем отличается постфильтр от глобальной агрегации для граненого поиска?

Распространенной проблемой в интерфейсах поиска является то, что вы хотите вернуть выборку результатов, но, возможно, захотите вернуть информацию обо всех документах. (например, я хочу видеть все красные рубашки, но хочу знать, какие есть другие цвета).

Это иногда называют «побочными результатами» или «многогранной навигацией».пример из ссылки Elasticsearch достаточно ясно объяснять почему / как, поэтому я использовал это в качестве основы для этого вопроса.

Резюме / Вопрос: Похоже, я могу использовать для этого как постфильтр, так и глобальную агрегацию. Похоже, они оба предоставляют одинаковые функции по-разному. У них могут быть преимущества или недостатки, которых я не вижу? Если так, что я должен использовать?

Я включил полный пример ниже с некоторыми документами и запросом с обоими типами методов на основе примера в справочном руководстве.

Вариант 1: постфильтр

увидетьпример из ссылки Elasticsearch

Что мы можем сделать, так это получить больше результатов в нашем исходном запросе, поэтому мы можем агрегировать эти результаты и затем фильтровать наши фактические результаты.

Пример достаточно ясен в объяснении этого:

Но, возможно, вы также хотели бы сообщить пользователю, сколько рубашек Gucci доступно в других цветах. Если вы просто добавите агрегирование терминов в поле цвета, вы получите только красный цвет, потому что ваш запрос возвращает только красные рубашки от Gucci.

Вместо этого вы хотите включить рубашки всех цветов во время агрегации, а затем применить фильтр цветов только к результатам поиска.

Посмотрите, как это будет выглядеть ниже в примере кода.

Проблема в том, что мы не можем использовать кэширование. Это в (пока недоступно для 5.1)упругое руководство предупрежден о:

Оценка производительности Используйте post_filter, только если вам нужна дифференциальная фильтрация результатов поиска и агрегатов. Иногда люди будут использовать post_filter для регулярных поисков.

Не делай этого! Природа post_filter означает, что он запускается после запроса, поэтому любое повышение производительности фильтрации (например, кеширования) полностью теряется.

Post_filter следует использовать только в сочетании с агрегациями и только тогда, когда вам нужна дифференциальная фильтрация.

Однако есть другой вариант:

Вариант 2: глобальные агрегации

Существует способ выполнить агрегацию, на которую не влияет поисковый запрос. Поэтому вместо того, чтобы получать много, агрегировать по этому, затем фильтровать, мы просто получаем наши отфильтрованные результаты, но делаем агрегацию по всему. Взглянутьпо ссылке

Мы можем получить точно такие же результаты. Я не читал никаких предупреждений о кешировании для этого, но кажется, что в конце мы должны сделать примерно такой же объем работы. Так что, возможно, единственное упущение.

Это немного сложнее из-за необходимой нам субагрегации (вы не можете иметьglobal иfilter на том же уровне').

Единственная жалоба, которую я прочитал о запросах, использующих это, это то, что вам, возможно, придется повторить себя, если вам нужно сделать это для нескольких пунктов. В конце концов, мы можем генерировать большинство запросов, поэтому повторение не является большой проблемой для моего сценария использования, и я не считаю это проблемой наравне с «невозможно использовать кэш».

Вопрос

Кажется, что обе функции в меньшей степени пересекаются или, возможно, предоставляют одинаковую функциональность. Это сбивает с толку меня. Кроме того, я хотел бы знать, есть ли у того или другого преимущество, которого я не видел, и есть ли здесь лучшая практика?

пример

Это в основном изстраница пост-фильтра, но я добавилглобальный фильтр запрос.

картография и документы

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"
}

Сейчас мы запрашиваем все красные рубашки гуччи (пункты 1 и 3), типы рубашек, которые у нас есть (тонкие и нормальные) для этих двух рубашек, и какие цвета есть в гуччи (красный и синий).

Во-первых, пост-фильтр: получить все рубашки, объединить модели для красных рубашек гуччи и цвета для рубашек гуччи (все цвета), а также постфильтр для красных рубашек гуччи, чтобы показать только результаты в качестве результатов: (это немного отличается от пример, поскольку мы стараемся максимально приблизить его к четкому применению постфильтров.)

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"
          }
        }
      ]
    }
  }
}

Мы также могли бы получить все красные рубашки гуччи (наш первоначальный запрос), а затем выполнить глобальную агрегацию для модели (для всех красных рубашек гуччи) и для цвета (для всех рубашек гуччи).

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"
              }
            }
          }
        }
      }
    }
  }
}

Оба будут возвращать одну и ту же информацию, вторая отличается только из-за дополнительного уровня, введенного субагрегациями. Второй запрос выглядит немного сложнее, но я не думаю, что это очень проблематично. Запрос реального мира генерируется кодом, в любом случае, вероятно, более сложным, и это должен быть хороший запрос, и если это означает сложность, пусть будет так.

Ответы на вопрос(2)

Ваш ответ на вопрос