【问题标题】:Aggregation by nested objects with filter in ElasticSearch 6在 ElasticSearch 6 中使用带有过滤器的嵌套对象进行聚合
【发布时间】:2018-11-19 03:20:25
【问题描述】:

我在 ElasticSearsh 6 中有一组表示属性单元的文档。每个属性都有嵌套的每周费率数组:

{
   "name" : "Completely Awesome Cabin"
   "rates" : [
      {
         "start": "2018-06-09T00:00:00",
         "end": "2018-06-16T00:00:00",
         "weeklyRate": 100.0,
      },
      {
         "start": "2018-06-16T00:00:00",
         "end": "2018-06-23T00:00:00",
         "weeklyRate": 200.0,
      }
      ...
   ]    
   ...
}

我正在通过包括日期在内的几个选项执行一些过滤。我需要添加聚合,以便在通过过滤器的所有单元之间为我提供最小和最大每周速率。我想它应该是某种带有过滤器的嵌套聚合。我怎样才能做到这一点?

【问题讨论】:

  • startendrate 对象是否与其他 rate 对象重叠,或者它们总是在同一天开始并且有相同的持续时间(7 天)?我试图了解 start 上的聚合是否足以推断一周的持续时间
  • 是的,每个费率对象代表特定一周的租金成本。它们彼此不重叠。租金成本从一个星期到另一个星期发生变化,所以当我搜索可用的属性时,例如从 06/01 到 07/01(我通过其他过滤器进行),我需要知道所有可用属性之间的最大和最小每周费率这些日期。

标签: elasticsearch nest elasticsearch-aggregation


【解决方案1】:

这是一个使用 NEST 6.1.0 运行的完整示例

private static void Main()
{
    var index = "default";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    var connectionSettings = new ConnectionSettings(pool)
        .DefaultIndex(index);

    var client = new ElasticClient(connectionSettings);

    if (client.IndexExists(index).Exists)
        client.DeleteIndex(index);

    client.CreateIndex(index, c => c
        .Mappings(m => m
            .Map<MyDocument>(mm => mm
                .AutoMap()
                .Properties(p => p
                    .Nested<Rate>(n => n
                        .AutoMap()
                        .Name(nn => nn.Rates)
                    )
                )
            )
        )
    );

    client.Bulk(b => b
        .IndexMany(new[] {
            new MyDocument
            {
                Name = "doc 1",
                Rates = new []
                {
                    new Rate
                    {
                        Start = new DateTime(2018, 6, 9),
                        End = new DateTime(2018, 6, 16),
                        WeeklyRate = 100
                    },
                    new Rate
                    {
                        Start = new DateTime(2018, 6, 16),
                        End = new DateTime(2018, 6, 23),
                        WeeklyRate = 200
                    }
                }
            },
            new MyDocument
            {
                Name = "doc 2",
                Rates = new []
                {
                    new Rate
                    {
                        Start = new DateTime(2018, 6, 9),
                        End = new DateTime(2018, 6, 16),
                        WeeklyRate = 120
                    },
                    new Rate
                    {
                        Start = new DateTime(2018, 6, 16),
                        End = new DateTime(2018, 6, 23),
                        WeeklyRate = 250
                    }
                }
            }
        })
        .Refresh(Refresh.WaitFor)
    );

    var searchResponse = client.Search<MyDocument>(s => s
        // apply your filtering in .Query(...) e.g. applicable date range
        .Query(q => q.MatchAll())
        // don't return documents, just calculate aggregations
        .Size(0)
        .Aggregations(a => a
            .Nested("nested_start_dates", n => n
                .Path(f => f.Rates)
                .Aggregations(aa => aa
                    .DateHistogram("start_dates", dh => dh
                        .Field(f => f.Rates.First().Start)
                        .Interval(DateInterval.Day)
                        .MinimumDocumentCount(1)
                        .Aggregations(aaa => aaa
                            .Min("min_rate", m => m
                                .Field(f => f.Rates.First().WeeklyRate)
                            )
                            .Max("max_rate", m => m
                                .Field(f => f.Rates.First().WeeklyRate)
                            )
                        )
                    )
                )
            )
        )
    );

    var nested = searchResponse.Aggregations.Nested("nested_start_dates");

    var startBuckets = nested.DateHistogram("start_dates").Buckets;

    foreach(var start in startBuckets)
    {
        var min = start.Min("min_rate").Value;
        var max = start.Max("max_rate").Value;

        Console.WriteLine($"{start.KeyAsString} - min: {min}, max: {max}");
    }
}

public class MyDocument
{
    public string Name {get;set;}

    public IEnumerable<Rate> Rates {get;set;}
}

public class Rate
{
    public DateTime Start {get;set;}

    public DateTime End {get;set;}

    public double WeeklyRate {get;set;}
}

将以下内容打印到控制台

2018-06-09T00:00:00.000Z - min: 100, max: 120
2018-06-16T00:00:00.000Z - min: 200, max: 250

您可能还对其他指标聚合感兴趣,例如 Stats Agggregation

【讨论】:

  • 感谢您的回答!此实现的唯一问题是聚合中的速率未按某些日期范围过滤。必须有两个参数fromto。我不明白如何将它们应用于过滤桶。
  • 在 bool 过滤子句中应用范围查询以仅匹配给定日期范围内汇率的文档。这将返回匹配文档的所有比率。然后可能需要使 DateHistogram 成为 Filter 聚合的子聚合,以过滤掉不属于给定范围的匹配文档中的比率。
  • 你是对的!在过滤器下进行 DateHistogram 子聚合会有所帮助。您能否在 DateHistogram 上添加过滤器聚合,以便我可以将您的答案标记为完全正确?
【解决方案2】:

除了来自 Russ Cam 的非常有用和有帮助的答案之外,我还想发布最终实现,这正是我所需要的。这是 NEST 聚合:

.Aggregations(a => a
    .Nested("budget_bound", n => n
        .Path(p => p.Rates)
        .Aggregations(aa => aa
            .Filter("by_start_date", fl => fl
                .Filter(fld => fld 
                    .DateRange(dr => dr
                        .Field(f => f.Rates.First().Start)
                        .GreaterThanOrEquals(checkIn)
                        .LessThanOrEquals(checkOut)))
                     .Aggregations(md => md
                         .Min("min_budget", m => m
                             .Field(f => f.Rates.First().WeeklyRate))
                         .Max("max_budget", m => m
                             .Field(f => f.Rates.First().WeeklyRate))
                      )
                 )
            )
       )

下面是对应的ES查询:

"aggs": {
"budget_bound": {
  "nested": {
    "path": "rates"
  },
  "aggs": {
    "by_start_date": {
      "filter": {
        "range": {
          "rates.start": {
            "gte": "2018-06-29T00:00:00+07:00", // parameter values
            "lte": "2018-07-06T00:00:00+07:00"  // parameter values
          }
        }
      },
      "aggs": {
        "min_budget": {
          "min": {
            "field": "rates.weeklyRate"
          }
        },
        "max_budget": {
          "max": {
            "field": "rates.weeklyRate"
          }
        }
      }
    }
  }
}}

对我来说,要弄清楚如何嵌套聚合以在获得最小和最大聚合之前添加对嵌套集合的过滤。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-05
    • 2015-11-14
    • 2018-01-30
    • 2014-12-31
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多