我有一个有趣的挑战,我认为有一个简单的答案。
我知道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")
);
答案 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
empty
,all empty strings
或tp.SearchField
或null 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}},因此可以{{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);