【问题标题】:Elasticsearch: group into buckets, reduce to one document per bucket, group these documentsElasticsearch:分组到桶中,每个桶减少一个文档,将这些文档分组
【发布时间】:2017-01-25 17:54:12
【问题描述】:

我正在寻找一种如何使用弹性搜索计算网页跳出率的方法。

我们以以下简化结构收集数据

{"id":"1", "timestamp"="2017-01-25:15:23", "sessionid"="s1", "page"="index"}
{"id":"2", "timestamp"="2017-01-25:15:24", "sessionid"="s1", "page"="checkout"}
{"id":"3", "timestamp"="2017-01-25:15:25", "sessionid"="s1", "page"="confirm"}

{"id":"4", "timestamp"="2017-01-25:15:26", "sessionid"="s2", "page"="index"}
{"id":"5", "timestamp"="2017-01-25:15:27", "sessionid"="s2", "page"="checkout"}

{"id":"6", "timestamp"="2017-01-25:15:26", "sessionid"="s3", "page"="product_a"}
{"id":"7", "timestamp"="2017-01-25:15:28", "sessionid"="s3", "page"="checkout"}

对于这个样本,分析结果应该是:

2/3 的用户在结帐页面迷路。

1/3的用户在确认页面迷路

更正式地说,我正在寻找一种通用方法,如何在弹性查询中实现以下算法:

  1. 按字段对文档进行分组
  2. 按第二个字段对每个组(存储桶)进行排序并减少到最顶部的文档
  3. 按第三个字段对所有这些剩余文档进行分组
  4. 按文档数量对组进行排序

我的第一次尝试是使用 terms 聚合 然后是 top_hits 聚合 来解决这个问题,最后使用 terms_pipeline 聚合 对页面进行分组。

(简化聚合结构)

aggs
    terms
        field: sessionid
        aggs
            top_hits
                sort:timestamp desc
                size: 1
    terms_pipeline
        bucket_path: terms>top_hits
        field: page

...但不幸的是,没有像 terms_pipeline 聚合这样的东西。我的错。

对替代方法有什么想法吗?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    也许我误解了一些东西,但是如果您愿意知道您的用户在哪里跳动,因为所有页面都是按顺序排列的,您可以简单地在 page 字段上设置一个 terms 聚合(以了解访问了哪些页面)和sessionid 字段上的cardinalityone(以了解您拥有多少不同的独特会话)。在这种情况下,cardinality(sessionid) 将产生 3。

    再一次,由于所有页面都是按顺序排列的,我认为您实际上不需要知道给定会话中发生了什么。

    在您的示例中,从 terms(page) 聚合中,您知道有 3 个用户登陆了结帐页面,但只有一个用户进入了确认页面。使用会话的基数,这隐含地意味着 2 个用户(总共 3 个会话 - 1 个确认页面点击)在结帐页面上反弹。

    【讨论】:

    • 谢谢。我认为这适用于简化示例,但该示例仅用于说明。我正在寻找一种更通用的方法来如何在弹性查询中实现算法(如果可能的话)。我编辑了问题以澄清这一点。
    • 那么由于top_hits 是一个指标聚合,您无法进一步聚合该数据。实现所需的唯一方法是分两遍完成,即首先在 top_hits 结果中收集文档的 id,然后在第二个查询中按这些 id 过滤并按第三个字段分组。
    • 这个运气好吗?
    • 抱歉 Val 响应缓慢。当您谈论“两次通过”时,您建议将数据提取到我们的应用程序中并在那里构建第二个查询?我对你的理解正确吗?只要数据量适中,我认为您的建议将非常有效。不幸的是,我们需要处理可能不适合我们应用程序内存的卷。而我们使用 Elastic 的理由是把大数据保存在那里。不在这里 :) 如果我们采用两遍解决方案,那么两遍都应该在 Elastic 中进行。我目前正在考虑如何提前标记会话的所有“最后一页”......
    • 是的,这就是我的意思,虽然第一遍只会得到你需要的文档的 ID,而不是完整的文档源。无论如何,如果您希望让 ES 处理大部分工作(这是有道理的),那么您需要事先考虑如何索引数据以支持您的用例。在您的情况下,您可能希望为每个会话创建一个父文档,然后为该会话中的每个事件创建一个子文档。然后,您可以轻松地检索每个会话的最后一个事件,然后在 page 字段上进行聚合。
    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多