2016-12-22 2 views
4

Ein häufiges Problem in Suchschnittstellen ist, dass Sie eine Auswahl von Ergebnissen, , zurückgeben möchten, aber möglicherweise Informationen über alle Dokumente zurückgeben möchten. (z. B. möchte ich alle roten Shirts sehen, möchte aber wissen, welche anderen Farben verfügbar sind).Was unterscheidet Post-Filter und globale Aggregation bei der Facettensuche?

Dies wird manchmal als "facettierte Ergebnisse" oder "facettierte Navigation" bezeichnet. Die example from the Elasticsearch reference ist ziemlich klar zu erklären, warum/wie, so Ich habe dies als Basis für diese Frage verwendet.

Zusammenfassung/Frage: Es sieht so aus, als könnte ich sowohl einen Post-Filter als auch eine globale Aggregation dafür verwenden. Beide scheinen die exakt gleiche Funktionalität auf andere Weise zu bieten. Es kann Vorteile oder Nachteile für sie geben, die ich nicht sehe? Wenn ja, welche sollte ich verwenden?

Ich habe unten ein vollständiges Beispiel mit einigen Dokumenten und einer Abfrage mit beiden Methodentypen basierend auf dem Beispiel im Referenzhandbuch eingefügt.


Option 1: Nachfilter

die example from the Elasticsearch reference

Was sehen wir tun können, ist mehr Ergebnisse in unsere ursprüngliche Frage haben, können wir so aggregieren 'auf' diesen Ergebnissen und danach filtern unsere tatsächlichen Ergebnisse.

Das Beispiel ist ganz klar zu erklären, es:

Aber vielleicht möchten Sie auch den Benutzer sagen, wie viele Gucci Shirts gibt es in anderen Farben erhältlich. Wenn Sie nur eine Terms-Aggregation im Farbfeld hinzufügen, erhalten Sie nur die Farbe Rot zurück, da Ihre Abfrage nur rote Shirts von Gucci zurückgibt.

Stattdessen möchten Sie während der Aggregation Shirts aller Farben verwenden und dann den Farbfilter nur auf die Suchergebnisse anwenden.

Sehen Sie, wie dies im Beispielcode unten aussehen würde.

Ein Problem mit diesem ist, dass wir Caching nicht verwenden können. Dies ist in der (noch nicht verfügbar für 5.1) elasticsearch guide gewarnt:

Leistungsaspekt Verwenden Sie ein post_filter nur, wenn Sie Suchergebnisse filtern und Aggregationen differentiell müssen. Manchmal verwenden Benutzer post_filter für regelmäßige Suchen.

Tun Sie das nicht! Die Art des post_filter bedeutet, dass es nach der Abfrage ausgeführt wird, sodass der Leistungsvorteil der Filterung (z. B. Caches) vollständig verloren geht.

Der post_filter sollte nur in Kombination mit Aggregationen und nur dann verwendet werden, wenn Sie eine differenzielle Filterung benötigen.

Es gibt jedoch eine andere Option:

Option 2: global Aggregationen

Es gibt einen Weg, um eine Aggregation zu tun, die nicht von der Suchabfrage beeinflusst wird. Also anstatt viel zu bekommen, aggregieren, Filter, wir bekommen nur unsere gefilterten Ergebnisse, aber tun Aggregationen auf alles. Werfen Sie einen Blick at the reference

Wir können die gleichen Ergebnisse erhalten. Ich habe keine Warnungen über Caching dafür gelesen, aber es scheint, als ob wir am Ende ungefähr die gleiche Menge an Arbeit machen müssen. Das ist vielleicht die einzige Mission.

Es ist ein bisschen komplizierter, weil die Unter Aggregation wir brauchen (Sie nicht global und ein filter auf die gleiche ‚Ebene‘ haben können).

Die einzige Beschwerde, die ich über Abfragen mit diesem lesen, ist, dass Sie sich wiederholen müssen, wenn Sie dies für mehrere Elemente tun müssen. Am Ende können wir die meisten Abfragen generieren, also ist es kein Problem, sich selbst zu wiederholen, und ich betrachte das nicht als ein Problem, das mit "Cache kann nicht verwendet werden" gleichrangig ist.

Frage

Es scheint, beide Funktionen im Geringsten überlappend sind oder möglicherweise genau die gleiche Funktionalität. Das verwirrt mich. Abgesehen davon würde ich gerne wissen, ob der eine oder andere einen Vorteil hat, den ich nicht gesehen habe, und ob es hier irgendwelche Best Practices gibt?

Beispiel

Dies ist vor allem von den post-filter reference page, aber ich hinzugefügt, um die global filter Abfrage.

Mapping und Dokumente

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

Wir sind jetzt alle roten Gucci-Shirts (Artikel 1 und 3) anfordert, die Arten von Hemden haben wir (schlank und normal) für diese 2 Shirts, und die Farben Gucci da sind (rot und blau).

Zuerst ein Post-Filter: Holen Sie sich alle Shirts, aggregieren die Modelle für rote Gucci-Shirts und die Farben für Gucci-Shirts (alle Farben), und Post-Filter für rote Gucci-Shirts, nur diejenigen als Ergebnisse zu zeigen: (this ist ein bisschen anders aus dem Beispiel, wie wir sie so nahe kommen zu einer klaren Anwendung von Nachfilter als 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" 
      } 
     } 
     ] 
    } 
    } 
} 

wir auch alle roten Gucci-Shirts bekommen können (unsere ursprüngliche Abfrage) und dann versuchen Machen Sie eine globale Aggregation für das Modell (für alle rote Gucci-Shirts) und für die Farbe (für alle Gucci-Shirts).

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

Beide werden die gleichen Informationen zurückgeben, die zweite unterscheidet sich nur aufgrund der zusätzlichen Ebene, die durch die Unteraggregationen eingeführt wird. Die zweite Abfrage sieht etwas komplexer aus, aber ich halte das nicht für sehr problematisch.Eine echte Weltabfrage wird durch Code erzeugt, wahrscheinlich sowieso viel komplexer und es sollte eine gute Abfrage sein, und wenn das kompliziert ist, sei es so.

Antwort

1

Die tatsächliche Lösung, die wir verwendet haben, ist zwar keine direkte Antwort auf die Frage, ist aber im Grunde "weder".

Von this elastic blogpost haben wir den anfänglichen Hinweis:

Gelegentlich sehe ich eine zu komplizierte Suche, wo das Ziel so weit wie möglich in möglichst wenige Suchanfrage wie möglich zu tun ist. Diese neigen dazu, Filter so spät wie möglich zu haben, ganz im Gegensatz zu den Empfehlungen in Filter First. Haben Sie keine Angst, mehrere Suchanfragen zu verwenden, um Ihre Informationsbedürfnisse zu befriedigen. Mit der Mehrfachsuch-API können Sie einen Stapel von Suchanfragen senden.

Schaufeln Sie nicht alles in eine einzige Suchanfrage.

Und das ist im Grunde, was wir in der obigen Abfrage tun: eine große Gruppe von Aggregationen und einige Filterung.

Sie parallel laufen zu lassen, erwies sich als viel schneller. Sehen Sie sich the multi-search API an

1

In beiden Fällen wird Elasticsearch am Ende meistens dasselbe tun. Wenn ich wählen müsste, denke ich, würde ich die global Aggregation verwenden, die Ihnen vielleicht ein wenig Aufwand ersparen würde, wenn Sie zwei Lucene-Sammler gleichzeitig füttern müssten.

+0

So enden sie das gleiche funktionell, aber der Post-Filter könnte einige Overhead haben? Ich weiß nicht viel über Lucene-Sammler, könntest du ein wenig darüber hinausgehen, was du dort meinst, oder mir einen Link geben, auf was du dich da beziehst? – Nanne

+0

Das wichtige Bit in meiner Antwort ist, dass es nicht wirklich wichtig ist. Das Sammelargument besteht darin, dass Stack-Traces im Post-Filter-Fall eine Ebene mehr haben, da MultiCollector verwendet wird, da alles in einem einzigen Durchgang ausgeführt wird, während jede globale Aggregation die Daten weitergibt (aber mit einer Match_all-Abfrage). . – jpountz

+0

Eine weitere Möglichkeit, dieses Problem zu lösen, besteht darin, mehrere Anforderungen zu senden, eine für jeden Satz, den Sie analysieren möchten. Dadurch entfällt die Garantie, dass alle Anforderungen genau die gleiche Point-in-Time-Ansicht des Indexes anzeigen, aber bei sich langsam ändernden Daten ist dies wahrscheinlich akzeptabel, und dies erleichtert auch die Skalierung, da Dinge wie der Anforderungscache wahrscheinlicher sind genutzt werden. – jpountz

Verwandte Themen