2012-11-17 18 views
5

我有一個有趣的挑戰,我認爲這是一個簡單的答案。「動態地」在NEST中創建過濾器

我知道,當你語法做這樣的事NEST過濾器正常工作:

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

我的基本服務應該允許調用者在某種物品進行過濾的枚舉列表的傳遞。

我基本上希望能夠實現編程是這樣的(過濾器通入法):

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

換句話說,如果我在{{「first.name」的一個數組傳遞「喬」},{ 「first.name」, 「吉姆」},{ 「first.name」, 「坦誠」}}我想產生的

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

回答

8

使用拉姆達基於DSL,你可以做到以下幾點:

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())) 
); 

我認爲讀好一點:)

鳥巢現在還支持conditionless查詢,因此,如果任何tp.SearchValuesnullemptyall empty stringstp.SearchFieldnull or empty它會跳過條款/前綴查詢。

您可以輕鬆地恢復,雖然這種行爲:

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

如果產生一個空的查詢,這將拋出一個DslException

作爲最後一個註釋client.Search()將返回QueryResult<dynamic>如果您可以強烈鍵入您的文檔,那麼可以做一個client.Search<MyDocument>()

-1

我能夠解決的等效這後面的一些R &關於這個問題類似於以下內容。我需要做AND和OR支持一些額外的工作:

 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

Martijn的回答是最好的,但我想我會添加一個我創建的例子,這對我來說很有幫助,希望對他人有幫助。我構建了一個BaseQuery對象列表,然後使用.ToArray()方法將其放入我的查詢中。

#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)) 
       );