ElasticSearch Nest。在时间跨度内获取聚合结果,排除另一个时间跨度

时间:2017-04-06 11:09:40

标签: c# elasticsearch nest

关注this question - get unique user within timespan,我想过滤掉仅在指定时间内出现的用户。

例如,仅在2016年访问但在2017年访问的用户列表。当我们仅使用过滤器2016时间跨度时,情况并非如此,因为用户可能也会出现在2017中。因此,可能的试验是设置[2016..2017 users] - [2017 users]

我的试用版是向ES发送2个查询([2016..2017 users][2017 users]),并在我的应用程序中使用userList_20162017.Except(userList_2017)过滤掉。

但我认为这似乎是非常低效的方法。我们能否只用ElasticSearch NEST查询来实现它?

void Main()
{
    var client = new ElasticClient(connectionSettings);

    var twoYearsAgo = new DateTime(2016,1,1);
    var yearAgo = new DateTime(2017,1,1);

    // get 2016..2017 users
    var searchResponse20162017 = client.Search<Visitor>(s => s
        .Size(0)
        .Query(q => q
            .DateRange(c => c.Field(p => p.CreationDate)
                .GreaterThan(twoYearsAgo)
                .LessThan(DateeTime.UtcNow)
            )
        )
        .Aggregations(a => a
            .Terms("unique_users", c => c
                .Field(f => f.OwnerUserId)
                .Size(int.MaxValue)
            )
        )
    );

    // get 2017 users
    var searchResponse2017 = client.Search<Visitor>(s => s
        .Size(0)
        .Query(q => q
            .DateRange(c => c.Field(p => p.CreationDate)
                .GreaterThan(yearAgo)
                .LessThan(DateeTime.UtcNow)
            )
        )
        .Aggregations(a => a
            .Terms("unique_users", c => c
                .Field(f => f.OwnerUserId)
                .Size(int.MaxValue)
            )
        )
    );

    var uniqueUser20162017 = searchResponse20162017.Aggs.Terms("unique_users").Buckets.Select(b => b.KeyAsString).ToList();
    var uniqueUser2017 = searchResponse2017.Aggs.Terms("unique_users").Buckets.Select(b => b.KeyAsString).ToList();

    // Final result. seems so naïve and inefficient.
    var uniqueUser2016Only = searchResponse20162017.Except(searchResponse2017);

}

1 个答案:

答案 0 :(得分:1)

可以使用filter sub aggregation执行此操作;首先,使用terms聚合获取2016年和2017年范围的唯一ID,然后对此执行子聚合以获取不在2017年范围内的那些ID。如果{{1的文档计数聚合等于过滤器聚合的文档计数,那么这是一个仅在2016年而不是2017年的ID。

这是一个例子

terms

void Main() { var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); var defaultIndex = "examples"; var connectionSettings = new ConnectionSettings(pool) .DefaultIndex(defaultIndex); var client = new ElasticClient(connectionSettings); if (client.IndexExists(defaultIndex).Exists) client.DeleteIndex(defaultIndex); var examples = new[]{ new Example(1, new DateTime(2016, 01, 01)), new Example(1, new DateTime(2017, 01, 01)), new Example(2, new DateTime(2016, 01, 01)), new Example(3, new DateTime(2017, 01, 01)), }; client.Bulk(b => b .IndexMany(examples) .Refresh(Refresh.WaitFor)); client.Search<Example>(s => s .Size(0) .Query(q => +q .DateRange(c => c.Field(p => p.Date) .GreaterThanOrEquals(new DateTime(2016, 01, 01)) .LessThan(new DateTime(2018, 01, 01)) ) ) .Aggregations(a => a .Terms("ids_in_2016_and_2017", c => c .Field(f => f.ExampleId) .Size(int.MaxValue) .Aggregations(aa => aa .Filter("ids_only_in_2016", f => f .Filter(ff => +!ff .DateRange(d => d .Field(p => p.Date) .GreaterThanOrEquals(new DateTime(2017, 01, 01)) .LessThan(new DateTime(2018, 01, 01)) ) ) ) ) ) ) ); } public class Example { public Example(int exampleId, DateTime date) { ExampleId = exampleId; Date = date; } public int ExampleId { get; set; } public DateTime Date { get; set; } } 2仅在2016年,而不是在2017年,因为2016年和2017年的医生数量仅等于2016年的医生数量

ExampleId

*附加OP:获取userId列表的结果。

{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "ids_in_2016_and_2017" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 1,
          "doc_count" : 2,
          "ids_only_in_2016" : {
            "doc_count" : 1
          }
        },
        {
          "key" : 2,
          "doc_count" : 1,
          "ids_only_in_2016" : {
            "doc_count" : 1
          }
        },
        {
          "key" : 3,
          "doc_count" : 1,
          "ids_only_in_2016" : {
            "doc_count" : 0
          }
        }
      ]
    }
  }
}