C# Nest 与 Elasticsearch 聚合

6

有人知道如何使用nest进行多重聚合吗?我找到了很多示例,但很不幸,它们都无法正常工作。

这是我的代码:

Vehicles fields = new Vehicles();

//create a terms query
var query = new TermsQuery
{
    IsVerbatim = true,
    Field = "VehicleOwnerId",
    Terms = new string[] { 25 },
};

var aggregations = new Dictionary<string, IAggregationContainer>
{
    { "years", new AggregationContainer
        {
            Terms = new TermsAggregation(nameof(fields.Year))
            {
                Field = new Field(nameof(fields.Year))
            }
        }
    }
    //,
    //{ "makes", new AggregationContainer
    //    {
    //        Terms = new TermsAggregation("Make")
    //        {
    //            Field = new Field(nameof(fields.Make))
    //        }
    //    }
    //}
};

//create the search request
var searchRequest = new SearchRequest
{
    Query = query,
    From = 0,
    Size = 100,
    Aggregations = aggregations
};

var result = client.SearchAsync<InventoryLiveView>(searchRequest).Result;

var years = result.Aggregations.Terms("years");
Dictionary<string, long> yearCounts = new Dictionary<string, long>();
foreach (var item in years.Buckets)
{
    yearCounts.Add(item.Key, item.DocCount ?? 0);
}

如果我只是像这样执行代码,它就能正常工作。Years按预期返回聚合值。如果我尝试添加另一个字段(如上面注释掉的字段),它会失败并返回零条记录。 如何在一个查询中获取多个聚合值?我看到这方面的示例很多,但我尝试的所有示例似乎都不起作用,大多数都已过时(包括Nest文档中的一些示例)。 我还尝试了这种方法,它与文档非常接近。

//create the search request
var searchRequest = new SearchRequest
{
    Query = query,
    From = 0,
    Size = 100,
    //Aggregations = aggregations
    Aggregations = new AggregationDictionary
    {
        { 
            "childAgg", new ChildrenAggregation("childAgg", typeof(Vehicles ))
            {
                Aggregations = new AggregationDictionary
                {
                    {"years", new TermsAggregation(nameof(fields.VehicleYear))},
                    {"makes", new TermsAggregation(nameof(fields.VehicleMakeName))},
                    {"models", new TermsAggregation(nameof(fields.VehicleModelName))},
                }
            }
        }
    }
};

var result = client.SearchAsync<Vehicles>(searchRequest).Result;

这只会产生一个空引用异常。


哪些NEST文档已经过时了?您看过https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/writing-aggregations.html吗? - Russ Cam
我认为那个页面已经过时了。它显示了这个例子:new MaxAggregation("max_per_child", Field(p => p.ConfidenceFactor)) 应该改为 MaxAggregation("max_per_child", new Field("ConfidenceFactor")) 或者至少在我看来是这样的。 - user2033791
现在我尝试从页面上的示例中运行一个,但是出现了错误。错误信息是“类型:null_pointer_exception 原因:""" 我不确定为什么会出现这个错误,也不知道它确切的含义。 - user2033791
1
该页面上的文档是由测试源代码生成的:https://github.com/elastic/elasticsearch-net/blob/c90f22be7d1f2ad20d6aac482e236f65e5708948/src/Tests/Tests/Aggregations/WritingAggregations.doc.cs 这些测试每次检入时运行,以通知是否存在编译错误或客户端代码的更改,使得最终文档与该分支中的最新客户端代码保持一致。在这种情况下,我没有看到文档存在任何问题,但如果您发现有问题,请随时在 https://github.com/elastic/elasticsearch-net/issues 上开启一个问题,以便我们可以解决。 - Russ Cam
似乎对我无效的代码是关于terms聚合的一个示例。它显示了Field = Field<Project>(p => p.State),但我无法让Field<T>起作用。然而,Field(string)却可以正常工作。我不记得确切的错误,但它只是无法识别它。谢谢您提供的信息 - 我可能做错了什么。 - user2033791
这是一个很好的观点 - 文档使用了 Nest.Infer 静态导入:https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/field-inference.html#nest-infer。 - Russ Cam
2个回答

12

我想我永远不用担心作为一个程序员过于骄傲了 :) 因为问题的解决方案经常会让我感到愚蠢。

所以我的问题是我试图在聚合中使用的字段是文本,不能使用。我把所有东西都换成了ID字段,多个聚合按预期工作。

所以这个代码版本完美地工作了:

Vehicle fields = new Vehicle ();

//create a terms query
var query = new TermsQuery
{
    IsVerbatim = true,
    Field = "VehicleOwnerId",
    Terms = new string[] { "30" },
};

string[] Fields = new[]
{
    nameof(fields.Year),
    nameof(fields.MakeId),
    nameof(fields.ModelId)
};

var aggregations = new Dictionary<string, IAggregationContainer>();
foreach (string sField in Fields)
{
    var termsAggregation = new TermsAggregation(sField)
    {
        Field = sField
    };

    aggregations.Add(sField, new AggregationContainer { Terms = termsAggregation });
}

//create the search request
var searchRequest = new SearchRequest
{
    Query = query,
    From = 0,
    Size = 10,
    Aggregations = aggregations
};

var result = client.SearchAsync<InventoryLiveView>(searchRequest).Result;

var years = result.Aggregations.Terms(nameof(fields.Year));
Dictionary<string, long> yearCounts = new Dictionary<string, long>();
foreach (var item in years.Buckets)
{
    yearCounts.Add(item.Key, item.DocCount ?? 0);
}

我在Postman中看到的Elasticsearch精确错误如下:

默认情况下,文本字段上禁用了Fielddata。 在[MakeName]上设置fielddata=true以通过反转索引取消反转索引并将fielddata加载到内存中。 请注意,这可能会使用大量内存。 或者改用关键字字段。


2

这里是我使用SearchDescriptors的示例。我唯一的问题是如何将返回的结果序列化为正确的键值列表。是否循环遍历字段列表是返回结果的最佳方式。

SearchDescriptor<Advert> agghDescriptor = new SearchDescriptor<Advert>();

agghDescriptor.Aggregations(ag => ag.Terms("make", a => a.Field(f => f.Make)) &&
                                  ag.Terms("region", a => a.Field(f => f.Region)) &&
                                  ag.Terms("city", a => a.Field(f => f.City)) &&
                                  ag.Terms("category", a => a.Field(f => f.Category)) &&
                                  ag.Terms("application", a => a.Field(f => f.Application)) &&
                                  ag.Terms("portalId", a => a.Field(f => f.PortalId)) &&
                                  ag.Terms("isActiveAuctionAdvert", a => a.Field(f => f.IsActiveAuctionAdvert)) &&
                                  ag.Terms("isBargainAccount", a => a.Field(f => f.IsBargainAccount)) &&
                                  ag.Terms("condition", a => a.Field(f => f.Condition))
);
agghDescriptor.Size(0);

var json2 = _client.RequestResponseSerializer.SerializeToString(agghDescriptor);
var aggregationResult = _client.Search<Advert>(agghDescriptor);

List<string> fields = new List<string>();
fields.Add("make");
fields.Add("category");
fields.Add("region");

List<Aggregation> aggregations = new List<Aggregation>();

foreach (var field in fields)
{
    var aggrs = aggregationResult.Aggregations.Terms(field);
    List<AggregateItem> aggregateItems = new List<AggregateItem>();
    
    foreach (var item in aggrs.Buckets)
    {
        aggregateItems.Add(new AggregateItem()
        {
            Count = item.DocCount ?? 0,
            Key = item.Key
        });
    }

    aggregations.Add(new Aggregation()
    {
        Name = field,
        Aggregates = aggregateItems
    });
}

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