“动态地”在NEST中创建过滤器

时间:2012-11-17 19:25:33

标签: c# elasticsearch 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”,“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")
                );

3 个答案:

答案 0 :(得分:8)

使用基于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.SearchValues null emptyall empty stringstp.SearchFieldnull or emptyvar 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}},因此可以{{1}}。

答案 1 :(得分: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))
                );

答案 2 :(得分:-1)

我能够在一些R&amp; D之后解决这个问题,并提供类似于以下内容的内容。我需要在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);