2016-06-08 4 views
4

Ich mag würde eine Elasticsearch Abfrage wie dies zu tun:NEST Conditional Filterabfrage mit mehreren Begriffen

{ 
    "query" : 
    { 
     "bool" : 
     { 
      "filter" : [ 
       { 
        "terms" : 
        { 
         "name" : ["name1", "name2"] 
        } 
       }, 
       { 
        "terms" : 
        { 
         "color" : ["orange", "red"] 
        } 
       } 
      ] 
     } 
    } 
} 

Ich habe versucht, es in NEST wie folgt umzusetzen:

_elasticClient 
    .SearchAsync<MyDocument>(s => 
     s.Index("myindex") 
      .Query(q => q 
       .Bool(bq => bq 
        .Filter(fq => 
        { 
         QueryContainer query = null; 

         if (nameList.Any()) { 
          query &= fq.Terms(t => t.Field(f => f.Name).Terms(nameList)); 
         } 

         if (colorList.Any()) { 
          query &= fq.Terms(t => t.Field(f => f.Color).Terms(colorList)); 
         } 

         return query; 
        }) 
       ) 
      ) 
    ); 

Aber das gibt mir eine Abfrage wie diese, wo die Filter in einem Bool Muss gewickelt sind:

{ 
    "query" : 
    { 
     "bool" : 
     { 
      "filter" : [ 
       { 
        "bool" : 
        { 
         "must" : [ 
          { 
           "terms" : 
           { 
            "name" : ["name1", "name2"] 
           } 
          }, 
          { 
           "terms" : 
           { 
            "color" : ["orange", "red"] 
           } 
          } 
         ] 
        } 
       } 
      ] 
     } 
    } 
} 

Wie sollte ich meinen NEST-Code ändern, um die richtige Abfrage zu erhalten? Müssen meine Begriffe zu etwas anderem als einem QueryContainer hinzufügen?

Antwort

7

Sie können eine Liste von Filtern erstellen, bevor Sie eine Abfrage machen, wenn Sie bedingte Filter überprüfen möchten, wie unten dargestellt:

var nameList = new[] {"a", "b"}; 
var colorList = new[] {1, 2}; 

var filters = new List<Func<QueryContainerDescriptor<MyDocument>, QueryContainer>>(); 
if (nameList.Any()) 
{ 
    filters.Add(fq=> fq.Terms(t => t.Field(f => f.Name).Terms(nameList))); 
} 

if (colorList.Any()) 
{ 
    filters.Add(fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList))); 
} 

ISearchResponse<Property> searchResponse = 
    elasticClient.Search<MyDocument>(x => x.Query(q => q 
    .Bool(bq => bq.Filter(filters)))); 

Wenn Sie brauchen keine Bedingung zu überprüfen, bevor Sie Filterabfrage Sie dann haben können, dass so etwas wie:

ISearchResponse<MyDocument> searchResponse = 
elasticClient.Search<MyDocument>(x => x.Query(q => q 
.Bool(bq => bq 
.Filter(
     fq => fq.Terms(t => t.Field(f => f.Name).Terms(nameList)), 
     fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList)) 
     )))); 
6

Die Filter Methode einer Bool Abfrage dauert eine params Func<QueryContainerDescriptor<T>, QueryContainer>[] so, dass man es mehrere Ausdrücke passieren können mehrere Filter

darstellen
var nameList = new string[] { "name1", "name2" }; 
var colorList = new string[] { "orange", "red" }; 

client.SearchAsync<MyDocument>(s => s 
     .Index("myindex") 
     .Query(q => q 
      .Bool(bq => bq 
       .Filter(
        fq => fq.Terms(t => t.Field(f => f.Name).Terms(nameList)), 
        fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList)) 
       ) 
      ) 
     ) 
); 

die

{ 
    "query": { 
    "bool": { 
     "filter": [ 
     { 
      "terms": { 
      "name": [ 
       "name1", 
       "name2" 
      ] 
      } 
     }, 
     { 
      "terms": { 
      "color": [ 
       "orange", 
       "red" 
      ] 
      } 
     } 
     ] 
    } 
    } 
} 

NEST also has the concept of conditionless queries in ergibt, das heißt, wenn eine Abfrage sein bedingungs bestimmt wird, dann wird es nicht als Teil der Anforderung serialisiert werden.

Was bedeutet es, konditionslos zu sein? Nun, das hängt von der Abfrage ab; beispielsweise im Falle einer terms Abfrage wird es bedingungs erachtet werden, wenn eine der folgenden Bedingungen erfüllt sind

  • die field keinen Wert haben
  • der Begriff Werteliste ist null
  • die Begriffe Wert ist eine leere Sammlung
  • die Begriffe Werteliste Werte hat, aber sie sind alle null oder leere Strings

Um

var emptyNames = new string[] {}; 
string[] nullColors = null; 

client.SearchAsync<MyDocument>(s => 
s.Index("myindex") 
    .Query(q => q 
     .Bool(bq => bq 
      .Filter(
       fq => fq.Terms(t => t.Field(f => f.Name).Terms(emptyNames)), 
       fq => fq.Terms(t => t.Field(f => f.Color).Terms(nullColors))) 
     ) 
    ) 
); 

Ergebnisse in

{} 

bedingungs Abfragen zu demonstrieren dient NEST macht das Schreiben von Abfragen einfacher, dass Sie nicht brauchen, um zu überprüfen, ob die Sammlung Wert hat, bevor eine Abfrage zu konstruieren. Sie können die bedingungslose Semantik pro Abfrage ändern using .Strict() and .Verbatim().

Verwandte Themen