2016-12-22 14 views
4

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

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

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

В приведенном ниже примере приведен полный пример с некоторыми документами и запрос с использованием обоих типов методов на основе примера .


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

см example from the Elasticsearch reference

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

Пример совершенно ясно объяснить это:

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

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

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

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

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

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

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

Существует, однако, другой вариант:

Вариант 2: глобальные скопления

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

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

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

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

Вопрос

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

Пример

Это в значительной степени от post-filter reference page, но я добавил 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" 
} 

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

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

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

мы могли бы также получить все красные GUCCI рубашки (наш оригинальный запрос), а затем сделайте глобальную агрегацию для модели (для всех красных рубашек gucci) и для цвета (для всех рубашек 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" 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

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

ответ

1

Фактическое решение, которое мы использовали, хотя и не является прямым ответом на вопрос, в основном «ни».

От this elastic blogpost мы получили первоначальный намек:

Иногда, я вижу над осложненным поиском, где цель состоит в том, чтобы сделать как можно больше, как несколько поисковых запросов, как это возможно. Они, как правило, имеют фильтры как можно позже, полностью в противоположность рекомендациям в Filter First. Не бойтесь использовать несколько поисковых запросов, чтобы удовлетворить ваши потребности в информации. Многопользовательский API-интерфейс позволяет отправлять пакет поисковых запросов.

Не переделывайте все в один запрос на поиск.

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

Наличие параллельных параллелей оказалось намного более быстрым. Посмотрите на the multi-search API

1

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

+0

Таким образом, они в конечном итоге выполняют те же функции, но пост-фильтр может иметь некоторые накладные расходы? Я мало знаю о коллекционерах люцен, не могли бы вы немного рассказать о том, что вы имеете в виду, или ударить меня ссылкой на то, что вы там указываете? – Nanne

+0

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

+0

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

 Смежные вопросы

  • Нет связанных вопросов^_^