Elasticsearch Nest 动态聚合

4
我正在尝试在C#中运行聚合查询(使用nest 5),但我不知道输入了多少聚合和聚合类型。
例如,一个查询是: {"aggs":{"type_count":{"terms":{"field":"type"}}}}
另一个查询可能是: {"aggs":{"type_count":{"terms":{"field":"type"}},"salary_count": {"field":"salary"}}}
还有其他查询可能根本不包含聚合。
如何在C#中以动态方式编写此代码?
这是我尝试过的(我为所选聚合类型设置了特定情况。问题在于该代码仅支持一个聚合。)
SearchDescriptor<object> SearchAgg = new SearchDescriptor<object>();
for (i=0;i < aggList.length;i++)
{
    SearchAgg.Aggregations(a => a.terms (aggList[i]), t=> t.Field(aggList[i]));
}

编辑:

我成功使用以下代码添加了多个聚合:

AggregationContainerDescriptor<SearchRequest> agg = new
AggregationContainerDescriptor<SearchRequest>();

agg.Terms("bucket", tm=> tm.Field("field"));
agg &= new AggregationContainerDescriptor<SearchRequest>().Terms("bucket2", tm=> tm.Field("field2"));

谢谢


请查看有关编写聚合的文档:https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/writing-aggregations.html - Russ Cam
2个回答

7

一般来说,在NEST中使用流畅的lambda表达式语法进行方法调用时,执行赋值操作而不是加法操作,这意味着对同一方法的连续调用将覆盖已分配的内容。在您的示例中:

SearchDescriptor<object> SearchAgg = new SearchDescriptor<object>();
for (i=0;i < aggList.length;i++)
{
    SearchAgg.Aggregations(a => a.terms (aggList[i]), t=> t.Field(aggList[i]));
}

只有最后一次调用 SearchAgg.Aggregations(...) 才会生效。 编写聚合文档 中有多个示例展示了如何进行多个聚合操作。对于以下POCOs,考虑:
public class Project
{
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime StartedOn { get; set; }
    public DateTime LastActivity { get; set; }
    public IList<string> Tags { get; set; }
    public IList<string> Branches { get; set; }
    public IList<CommitActivity> Commits { get; set; }
}

public class CommitActivity
{
    public string Id { get; set; }
    public string Message { get; set; }
    public long SizeInBytes { get; set; }
}

在这里,CommitActivity 被映射为一个 nested 类型,在提交上执行两个术语聚合,并对提交执行嵌套聚合以聚合有关每个项目的提交统计信息。

使用流畅的 Lambda 表达式语法

var searchResponse = client.Search<Project>(s => s
    .Aggregations(aggs => aggs
        .Terms("project_tags", t => t.Field(p => p.Tags))
        .Terms("project_branches", t => t.Field(p => p.Branches))
        .Nested("commits", n => n
            .Path(p => p.Commits)
            .Aggregations(aa => aa
                .Stats("commit_size_stats", m => m.Field(p => p.Commits.First().SizeInBytes))
            )
        )
    )
);

Object Initializer syntax

var searchRequest = new SearchRequest<Project>
{
    Aggregations = new AggregationDictionary
    {
        { "project_tags", new TermsAggregation("project_tags") { Field = Nest.Infer.Field<Project>(p => p.Tags) } },
        { "project_branches", new TermsAggregation("project_branches") { Field = Nest.Infer.Field<Project>(p => p.Branches) } },
        { "commits", new NestedAggregation("commits") 
            {
                Path = Nest.Infer.Field<Project>(p => p.Commits),
                Aggregations = new AggregationDictionary
                {
                    { "commit_size_stats", new StatsAggregation("commit_size_stats", Nest.Infer.Field<Project>(p => p.Commits.First().SizeInBytes)) },
                }
            }
        }
    }
};

var searchResponse = client.Search<Project>(searchRequest);

由于搜索请求上的聚合最终只是聚合名称和聚合类型的字典,因此使用此语法可以快速增长。出于这个原因,NEST重载了逻辑&&运算符并实现了隐式转换,以允许更简洁地组合聚合。

简洁的对象初始化器语法

var searchRequest = new SearchRequest<Project>
{
    Aggregations = 
        new TermsAggregation("project_tags") { Field = Nest.Infer.Field<Project>(p => p.Tags) } &&
        new TermsAggregation("project_branches") { Field = Nest.Infer.Field<Project>(p => p.Branches) } &&
        new NestedAggregation("commits") 
        {
            Path = Nest.Infer.Field<Project>(p => p.Commits),
            Aggregations = 
                new StatsAggregation("commit_size_stats", Nest.Infer.Field<Project>(p => p.Commits.First().SizeInBytes))
        }
};

var searchResponse = client.Search<Project>(searchRequest);

0

我知道这个问题已经问了几年了,但我遇到了同样的问题。

使用NEST 7.17,我想根据用户选择动态创建多层聚合查询。固定查询的流畅式查询非常好用,但是我很难以这种方式动态添加多个 agg 级别。最终我逐步创建了查询,下面显示了一个示例。

这种方法比 Fluent 风格要冗长得多;但我最终将此处的代码包装在方法中,以添加每个 bucket-aggregation 和 value-aggregation 层,使我能够随意动态创建复杂的多层查询。

最初让我失误的一件事是,AggregationDictionary() 构造函数会复制所有细节,因此请确保在其他细节完全组装好后再调用它们。

/*
 Index for sample will be:
    country - keyword
    region - keyword
    price - float
*/        

// Level 1 - Break out 'Country' into buckets
var aggDictL1 = new Dictionary<string, IAggregationContainer>();
var terms = new TermsAggregation("country_level");
terms.Size = 100;
terms.Field = new Field("country.keyword");
aggDictL1["country_level"] = new AggregationContainer { Terms = terms };

// Total cost for each country
aggDictL1["total_cost"] = new AggregationContainer 
{
    Sum = new SumAggregation("total_cost", new Field("price"))
};


// Level 2 - Break out 'Region' within each country
var aggDictL2 = new Dictionary<string, IAggregationContainer>();
var terms2 = new TermsAggregation("region_level");
terms2.Size = 100;
terms2.Field = new Field("region.keyword");
aggDictL2["region_level"] = new AggregationContainer { Terms = terms2 };

// Total cost for each bucket within layer above ('Country' in this case)
aggDictL2["country_cost"] = new AggregationContainer
{
    Sum = new SumAggregation("country_cost", new Field("price"))
};


// Level 3 - Total cost for each region
var aggDictL3 = new Dictionary<string, IAggregationContainer>();

// Total cost for each bucket within layer above ('Region' in this case)
aggDictL3["region_cost"] = new AggregationContainer
{
    Sum = new SumAggregation("region_cost", new Field("price"))
};

// Assemble layers - do this last as AggregationDictionary() will copy details
aggDictL2["region_level"].Aggregations = new AggregationDictionary(aggDictL3);
aggDictL1["country_level"].Aggregations = new AggregationDictionary(aggDictL2);


// Assemble request
var sd = new SearchRequest<SpotRecord>(Indices.Index(indexName));
sd.Size = 0;
sd.Query = <your filter here...>
sd.Aggregations = new AggregationDictionary(aggDictL1);

// Run it
var ret = _client.Search<SpotRecord>(sd);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接