根据 Elastic Search 中过滤器的最后一个条目分组

如何解决根据 Elastic Search 中过滤器的最后一个条目分组

我有一个类似于以下的场景:

包含商店购买商品的索引,其中每个商品都有一个 order_id。 而且我只需要按每个订单的最后项的颜色分组。

数据结构:

{
    "order_id": 1,"product_id":235233
    "color": "Blue","purchase_date": "2020-08-21T05:53:43.362Z"
},{
    "order_id": 1,"product_id":2352662
    "color": "Black","purchase_date": "2020-08-23T05:53:43.362Z"
},{
    "order_id": 2,"product_id":855477
    "color": "Blue","purchase_date": "2020-08-22T05:53:43.362Z"
},"product_id":322352
    "color": "Red","purchase_date": "2020-08-24T05:53:43.362Z"
},{
    "order_id": 3,"product_id":3225235
    "color": "Red","purchase_date": "2020-08-25T05:53:43.362Z"
}

预期结果

黑色:1(order_id 1 的最后一个产品的颜色)

Red:2(order_id 2,3 的最后一个产品的颜色)

基于 this answer,我可以将每个订单的最后一个项目作为整个项目,但我正在寻找的是直接获取每种颜色的项目数

POST /items/_search?search_type=count
{
    "aggs": {
        "group": {
            "terms": {
                "field": "order_id"
            },"aggs": {
                "group_items": {
                    "top_hits": {
                        "size": 1,"sort": [
                            {
                                "purchase_date": {
                                    "order": "desc"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
}

下面给出了所有订单商品的每种颜色的商品数量,而不仅仅是每个订单的最后一个

GET /items/_search?search_type=count
{
 "size":0,"aggs": {
    "colors": {
       "terms": {
        "field": "color.keyword"
        }
     }
  }
}

解决方法

解决该问题的另一种方法是创建并维护一个单独的索引 (latest_by_order),用于跟踪每个订单的最新文档。 这可以使用转换 (see docs) 来实现。

可以使用以下命令创建此类转换:

PUT _transform/latest_by_order
{
  "source": {
    "index": "items"
  },"dest": {
    "index": "latest_by_order"
  },"latest": {
    "unique_key": ["order_id"],"sort": "purchase_date"
  }
}

然后,可以在新的(转换后的)索引之上进行二次分析。 以下请求:

GET latest_by_order/_search
{
  "size": 0,"aggs": {
    "count_by_color": {
      "terms": {
        "field": "color.keyword"
      }
    }
  }
}

将产生以下响应:

{
  "took" : 2,"timed_out" : false,"_shards" : {
    "total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0
  },"hits" : {
    "total" : {
      "value" : 3,"relation" : "eq"
    },"max_score" : null,"hits" : [ ]
  },"aggregations" : {
    "count_by_color" : {
      "doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [
        {
          "key" : "Red","doc_count" : 2
        },{
          "key" : "Black","doc_count" : 1
        }
      ]
    }
  }
}
,

您可以使用 group by color 并按 purchase_date 的最大值排序,如下所示:

{
  "size": 0,"aggs": {
    "group": {
      "terms": {
        "field": "color.keyword","order": {
          "by_latest_purchase": "desc"
        }
      },"aggs": {
        "by_latest_purchase": {
          "max": {
            "field": "purchase_date"
          }
        }
      }
    }
  }
}

但您最终仍会得到 blue b/c,这是您的文档中存在的一种颜色,我不知道是否可以将其过滤掉。


当有疑问(或其他所有方法都失败)时,scripted metric aggregations 来救援:

{
  "size": 0,"aggs": {
    "by_color": {
      "scripted_metric": {
        "init_script": "state.by_order_id = [:]","map_script": """
          def color = doc['color.keyword'].value;
          def date = doc['purchase_date'].value.millis;
          def order_id = doc['order_id'].value;
          
          def current_group = ['color':color,'date': date];
          
          if (state.by_order_id.containsKey(order_id)) {
            def max_group = state.by_order_id[order_id];
            if (date > max_group.date) {
              // we've found a new maximum
              state.by_order_id[order_id] = current_group
            }
          } else {
            state.by_order_id[order_id] = current_group;
          }
        ""","combine_script": """
          def colors_vs_count = [:];
          
          for (def group : state.by_order_id.entrySet()) {
            def order_id = group.getKey();
            def color = group.getValue()['color'];
            if (colors_vs_count.containsKey(color)) {
              colors_vs_count[color]++;
            } else {
              colors_vs_count[color] = 1;
            }
          }
          
          return colors_vs_count;
        ""","reduce_script": "return states"
      }
    }
  }
}

产量:

...
"aggregations" : {
  "by_color" : {
    "value" : [
      {
        "Red" : 2,"Black" : 1
      }
    ]
  }
}

这是一个 JSON 友好的精简版脚本:

{"size":0,"aggs":{"by_color":{"scripted_metric":{"init_script":"state.by_order_id = [:]","map_script":"          def color = doc['color.keyword'].value;\n          def date = doc['purchase_date'].value.millis;\n          def order_id = doc['order_id'].value;\n          \n          def current_group = ['color':color,'date': date];\n          \n          if (state.by_order_id.containsKey(order_id)) {\n            def max_group = state.by_order_id[order_id];\n            if (date > max_group.date) {\n              state.by_order_id[order_id] = current_group\n            }\n          } else {\n            state.by_order_id[order_id] = current_group;\n          }","combine_script":"          def colors_vs_count = [:];\n          \n          for (def group : state.by_order_id.entrySet()) {\n            def order_id = group.getKey();\n            def color = group.getValue()['color'];\n            if (colors_vs_count.containsKey(color)) {\n              colors_vs_count[color]++;\n            } else {\n              colors_vs_count[color] = 1;\n            }\n          }\n          \n          return colors_vs_count;","reduce_script":"return states"}}}}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?