【问题标题】:"Dynamically" creating a filter in NEST在 NEST 中“动态”创建过滤器
【发布时间】:2012-11-06 04:55:11
【问题描述】:

我有一个有趣的挑战,我认为有一个简单的答案。

我知道 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", "joe"}, {"first.name", "jim"}, {"first.name", "frank"}}我想产生相当于

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

【问题讨论】:

    标签: c# elasticsearch nest


    【解决方案1】:

    在对该主题进行了一些研发后,我能够通过类似于以下内容的方式解决此问题。我需要在 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);
    

    【讨论】:

      【解决方案2】:

      使用基于 lambda 的 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()))
      );
      

      我认为读起来更好:)

      Nest 现在还支持 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&lt;dynamic&gt;,如果您可以强输入您的文档,那么您也可以输入 client.Search&lt;MyDocument&gt;()

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-19
          • 1970-01-01
          • 2019-12-16
          • 1970-01-01
          • 2011-04-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多