2012-11-17 10 views
5

Ich habe eine interessante Herausforderung, die ich denke, es gibt eine einfache Antwort auf."Dynamisch" Erstellen eines Filters in NEST

Ich weiß, dass NEST Filter korrekt funktionieren, wenn syntaktisch Sie so etwas tun:

var andFilter = FilterFactory.AndFilter(
        FilterFactory.TermFilter("name.first", "shay1"), 
        FilterFactory.TermFilter("name.first", "shay4") 
       ); 

Meine Basisdienste sollte ein der Anrufer erlauben, in einer Art enumerable Liste der Elemente passieren zu filtern.

Ich würde grundsätzlich gerne in der Lage sein, programmatisch so etwas wie dies zu erreichen (Filter in die Methode übergeben wird):

var andFilter = new FilterDescriptor(); 
foreach (var filter in filters) 
{ 
    andFilter = filter concatenated to andFilter 
} 

Mit anderen Worten, wenn ich in einer Reihe von {{ „first.name“ bestanden "joe"}, { "first.name", "jim"}, { "first.name", "Frank"}} ich möchte das Äquivalent von

var andFilter = FilterFactory.AndFilter(
        FilterFactory.TermFilter("name.first", "joe"), 
        FilterFactory.TermFilter("name.first", "joe"), 
        FilterFactory.TermFilter("name.first", "frank") 
       ); 

Antwort

8

den Lambda-basierten DSL verwenden Sie können folgendes tun:

var termsFilters = from tp in termParameters 
        let field = ToCamelCaseNestedNames(tp.SearchField) 
        let terms = tp.SearchValues 
        select Filter.Terms(field, terms); 

var prefixFilters = from tp in prefixParameters 
        let field = ToCamelCaseNestedNames(tp.SearchField) 
        let prefix = tp.SearchValues.FirstOrDefault().ToLowerInvariant() 
        select Filter.Prefix(field, prefix); 

var search = client.Search(s => s 
    .From(0) 
    .Size(20) 
    .Filter(f => f.And(termsFilters.Concat(prefixFilters).ToArray())) 
); 

die ich denke, ein bisschen besser liest :)

Nest unterstützt jetzt auch conditionless Abfragen also, wenn irgendeine tp.SearchValues ist null, empty oder all empty strings oder tp.SearchField ist null or empty es, dass Begriffe/Präfix Abfrage überspringen wird.

Sie können dieses Verhalten zurückkehren leicht aber:

var search = client.Search(s => s 
    .Strict() 
    .From(0) 
    .Size(20) 
    .Filter(f => f.And(termsFilters.Concat(prefixFilters).ToArray())) 
); 

, die eine DslException wenn eine leere Abfrage generiert wird, werfen.

Als letzte Anmerkung wird eine QueryResult<dynamic> zurückgeben, wenn Sie Ihre Dokumente stark schreiben können, so kann eine client.Search<MyDocument>() tun.

-1

konnte ich produzieren lösen dies nach einigen R & D auf das Thema mit etwas ähnlich wie folgt. Ich brauche einige zusätzliche Arbeiten am Und zu tun und Oder-Unterstützung:

 IList<IFilterBuilder> conditions = new List<IFilterBuilder>(); 
     if (termParameters != null) 
      foreach (var termParameter in termParameters) 
       conditions.Add(FilterFactory.TermsFilter(ToCamelCaseNestedNames(termParameter.SearchField), termParameter.SearchValues)); 

     if (prefixParameters != null) 
      foreach (var prefixParameter in prefixParameters) 
       conditions.Add(FilterFactory.PrefixFilter(ToCamelCaseNestedNames(prefixParameter.SearchField), prefixParameter.SearchValues.First().ToLowerInvariant())); 

     var filters = FilterFactory.AndFilter(); 
     filters.Add(FilterFactory.AndFilter(conditions.ToArray())); 

     MatchAllQueryBuilder matchAllQueryBuilder = new MatchAllQueryBuilder(); 
     FilteredQueryBuilder filteredQueryBuilder = new FilteredQueryBuilder(matchAllQueryBuilder, filters); 
     SearchBuilder searchBuilder = new SearchBuilder(); 
     searchBuilder.Query(filteredQueryBuilder); 
     searchBuilder.Size(maxResults); 
1

Martijns Antwort ist die beste, aber ich dachte, ich würde ein Beispiel hinzufügen, das ich erstellt habe, das für mich funktioniert, hoffentlich wird es für andere hilfreich sein. Ich habe eine Liste von BaseQuery-Objekten erstellt und diese dann mithilfe der .ToArray() -Methode in meine Abfrage eingefügt.

#region build query 

    var query = new List<BaseQuery> 
       { 
        Query<IAuthForReporting>.Range(r => r.OnField(f => f.AuthResult.AuthEventDate) 
                .From(authsByDateInput.StartDate.ToEPCISFormat()) 
                .To(authsByDateInput.EndDate.ToEPCISFormat())) 
       }; 
    if (authsByDateInput.AuthResult != AuthResultEnum.SuccessOrFailure) 
    { 
     var success = authsByDateInput.AuthResult == AuthResultEnum.Success; 
     query.Add(Query<IAuthForReporting>.Term(t => t.AuthResult.AuthenticationSuccessful, success)); 
    } 
    if (authsByDateInput.ProductID != null) 
    { 
     query.Add(Query<IAuthForReporting>.Term(t => t.AuthResult.ProductID, authsByDateInput.ProductID.Value)); 
    } 

    if (!authsByDateInput.CountryIDs.IsNullOrEmpty()) 
    { 
     query.Add(Query<IAuthForReporting>.Terms(t => t.AuthResult.Address.CountryID, authsByDateInput.CountryIDs.Select(x=> x.Value.ToString()).ToArray())); 
    } 
    #endregion 

     var result = 
      ElasticClient.Search<IAuthForReporting>(s => 
                s.Index(IndexName) 
                .Type(TypeName) 
                .Size(0) 
                .Query(q => 
                  q.Bool(b => 
                    b.Must(query.ToArray()) 
                   ) 
                 ) 
                .FacetDateHistogram(t => t.OnField(f => f.AuthResult.AuthEventDate).Interval(DateInterval.Day)) 
       ); 
Verwandte Themen