6

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

我知道当您在语法上执行以下操作时,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")
                );
4

3 回答 3

9

使用基于 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.SearchValuesis或is null,它将跳过该术语/前缀查询。emptyall 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()将返回 aQueryResult<dynamic>如果您可以强烈键入您的文档,那么可以执行 a client.Search<MyDocument>()

于 2012-12-02T20:53:49.100 回答
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))
                );
于 2014-03-04T15:02:11.470 回答
-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);
于 2012-11-19T14:38:26.237 回答