我想获取给定期间内唯一数字用户ID的列表。
假设字段为userId
,时间字段为startTime
,我成功获得如下结果;
HashSet<int> hashUserIdList= new HashSet<int>(); // guarantees to store unique userIds.
// Step 1. get unique number of userIds
var total = client.Search<Log>(s => s
.Query(q => q
.DateRange(c => c.Field(p => p.startTime)
.GreaterThan(FixedDate)))
.Aggregations(a => a
.Cardinality("userId_cardinality", c => c
.Field("userId"))))
.Aggs.Cardinality("userId_cardinality");
int totalCount = (int)total.Value;
// Step 2. get unique userId values by Terms aggregation.
var response = client.Search<Log>(s => s
.Source(source => source.Includes(inc => inc.Field("userId")))
.Query(q => q
.DateRange(c => c.Field(p => p.startTime)
.GreaterThan(FixedDate)))
.Aggregations(a => a
.Terms("userId_terms", c => c
.Field("userId").Size(totalCount))))
.Aggs.Terms("userId_terms");
// Step 3. store unique userIds to HashSet.
foreach (var element in response.Buckets)
{
hashUserIdList.Add(int.Parse(element.Key));
}
它 可以工作,
但效率不高,因为(1)totalCount
首先获取,并且(2)它定义Size(totalCount)
由于存储桶溢出(如果结果有成千上万个),可能导致500个服务器错误。
以某种foreach
方式进行迭代会很好,但是我无法使它们按大小迭代100
。我在这里放了From
/ Size
或Skip
/
Take
,但是返回值不可靠。
如何正确编码?
对于某些集合,此方法可能是可行的,但需要注意以下几点:
您可能可以跳过基数汇总来获取大小,而只需将其int.MaxValue
作为术语汇总的大小即可。在速度方面效率较低的另一种方法是滚动浏览范围内的所有文档,使用源过滤器仅返回您感兴趣的字段。我希望使用Scroll方法可以减轻群集的压力,但我建议您监视您采用的任何方法。
这是对Stack Overflow数据集(2016年6月,IIRC)上这两种方法的比较,研究了两年前的今天和一年前的今天的独特提问者。
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings = new ConnectionSettings(pool)
.MapDefaultTypeIndices(d => d
.Add(typeof(Question), NDC.StackOverflowIndex)
);
var client = new ElasticClient(connectionSettings);
var twoYearsAgo = DateTime.UtcNow.Date.AddYears(-2);
var yearAgo = DateTime.UtcNow.Date.AddYears(-1);
var searchResponse = client.Search<Question>(s => s
.Size(0)
.Query(q => q
.DateRange(c => c.Field(p => p.CreationDate)
.GreaterThan(twoYearsAgo)
.LessThan(yearAgo)
)
)
.Aggregations(a => a
.Terms("unique_users", c => c
.Field(f => f.OwnerUserId)
.Size(int.MaxValue)
)
)
);
var uniqueOwnerUserIds = searchResponse.Aggs.Terms("unique_users").Buckets.Select(b => b.KeyAsString).ToList();
// 3.83 seconds
// unique question askers: 795352
Console.WriteLine($"unique question askers: {uniqueOwnerUserIds.Count}");
}
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings = new ConnectionSettings(pool)
.MapDefaultTypeIndices(d => d
.Add(typeof(Question), NDC.StackOverflowIndex)
);
var client = new ElasticClient(connectionSettings);
var uniqueOwnerUserIds = new HashSet<int>();
var twoYearsAgo = DateTime.UtcNow.Date.AddYears(-2);
var yearAgo = DateTime.UtcNow.Date.AddYears(-1);
var searchResponse = client.Search<Question>(s => s
.Source(sf => sf
.Include(ff => ff
.Field(f => f.OwnerUserId)
)
)
.Size(10000)
.Scroll("1m")
.Query(q => q
.DateRange(c => c
.Field(p => p.CreationDate)
.GreaterThan(twoYearsAgo)
.LessThan(yearAgo)
)
)
);
while (searchResponse.Documents.Any())
{
foreach (var document in searchResponse.Documents)
{
if (document.OwnerUserId.HasValue)
uniqueOwnerUserIds.Add(document.OwnerUserId.Value);
}
searchResponse = client.Scroll<Question>("1m", searchResponse.ScrollId);
}
client.ClearScroll(c => c.ScrollId(searchResponse.ScrollId));
// 91.8 seconds
// unique question askers: 795352
Console.WriteLine($"unique question askers: {uniqueOwnerUserIds.Count}");
}
术语汇总比Scroll API方法快24倍。
抱歉,如果已经问过了,但一直潜伏在SO周围,找不到任何适合我需要的东西。 基本上,我在使用ES的第一次快速尝试中试图实现的是在术语聚合中添加更多计数器。 快速尝试一下,我将以下请求发送给ES。 我现在得到的只是样本在文档中显示的内容。 但是,我真的不知道如何在桶中包含更多的内部聚合。会导致这样的文档的东西。 我应该如何构造聚合,以便按桶包含这些聚合?
问题内容: 我正在尝试使用以下查询对以下数据进行elasticsearch来执行术语聚合,输出将名称分解为标记(请参见下面的输出)。因此,我尝试将os_name映射为multi_field,但现在无法通过它查询。是否可以有没有令牌的索引?例如“ Fedora Core”? 查询: 数据: 输出: 映射: 问题答案: 实际上,您应该像这样更改映射 并且您的aggs应该更改为:
问题内容: 我只是想知道内部和外部迭代的真正好处是什么,以及为什么使用内部操作更好(至少是我所听到的)。在对集合进行内部迭代时,是否还可以删除集合的元素?就像在代码示例中一样: 我知道内部迭代的代码可读性更好,但是还有其他一些好处,例如性能改进? 问题答案: 您的情况有些简单,因为您可以简单地使用resp。而是使用内部迭代的替代方法,它也可以处理更复杂的条件。 在的情况下,这将立即显示内部迭代的优
问题内容: 索引文件如下: 我想要的是按平台计数和输出统计信息。为了进行计数,我可以将术语聚合作为字段进行计数: 这样,我就可以像预期那样将统计数据作为多个存储桶接收到。 现在,我还能以某种方式添加到这些存储桶中吗(以及用于统计的漂亮输出)?我附带的最好的看起来像: 实际上,它可以工作,并且在每个存储桶中返回非常复杂的结构: 当然,可以从此结构中提取平台的名称和网址(例如),但是是否有更干净,更简
索引文档如下: 我想要的是按平台计数和输出统计信息。对于计数,我可以使用带有的术语聚合作为字段进行计数: 通过这种方式,我以多个bucket的形式接收统计数据,看起来就像预期的那样{key:8,doc\u count:162511}。 现在,我可以以某种方式将和(用于漂亮的统计输出)添加到这些桶中吗?我带来的最好的看起来像: 实际上,它可以工作,并在每个桶中返回非常复杂的结构: 当然,平台的名称和
我使用聚合从嵌套字段收集数据并卡住了一点 文件示例: ES允许通过rectangle.attributes._id来分组数据,但是有没有办法让一些“其他”桶把没有添加到任何组中的文档放在那里?或者,也许有一种方法可以通过创建查询来为文档创建桶。我认为桶将是完美的,因为我需要使用“其他”文档进行进一步的聚合。或者也许有一些很酷的解决方法 我使用这样的查询进行聚合 然后得到这个结果 这样的结果将是完美