关注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);
}
答案 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
}
}
]
}
}
}