当前位置: 首页 > 知识库问答 >
问题:

在elasticsearch中按嵌套字段值之和查询文档

颜森
2023-03-14

在这里给ElasticSearch的初学者排名。

我有一个客户列表,他们的订单作为一个嵌套字段。假设文档结构如下:

[
  { customerId: 123,
    birthday: 1980-01-01,
    orders: [
      {
        orderValue: 1500,
        orderDate: 2018-12-18T12:18:12Z
      },
      [...]
    ]
  },
  [...]
}

我想查询的是:在两个日期之间订购了一定数量的用户列表。我希望能够将它与例如生日的范围查询结合起来。

我已经到了这样的地步,我可以使用聚合来获得每个订户在两个日期之间的排序总和:

{
  "size": 0,
  "aggs": {
    "foo": {
      "nested": {
        "path": "orders"
      },
      "aggs": {
        "grouped_by_customerId": {
          "terms": {
            "field": "orders.customerId.keyword"
          },
          "aggs": {
            "filtered_by_date": {
              "filter": {
                "range": {
                  "orders.orderDate": {
                    "from": "2018-01-28",
                    "to": null,
                    "include_lower": false,
                    "include_upper": true,
                    "format": "yyyy-MM-dd",
                    "boost": 1
                  }
                }
              },
              "aggs": {
                "sum": {
                  "sum": {
                    "field": "orders.orderValue"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

但是,我想限制查询部分返回的结果,以便更好地与所有其他过滤器混合。

我的第一个想法是使用一个脚本过滤器,并将边界日期和最小值作为参数传递进来,但随后我必须迭代一个文档的嵌套文档,这似乎不起作用。

最后一个想法可能吗?如果可能,怎么可能?

谢了!

共有1个答案

松雅昶
2023-03-14

最后我自己解决了这个问题,使用如下函数得分查询:

{
  "query": {
    "bool": {
      "must": [
        {
          "function_score": {
            "min_score": 1,
            "query": {
              "nested": {
                "path": "orders",
                "ignore_unmapped": false,
                "score_mode": "min",
                "boost": 1,
                "query": {
                  "range": {
                    "orders.orderDate": {
                      "from": "2018-12-10",
                      "to": null,
                      "include_lower": true,
                      "include_upper": true,
                      "format": "yyyy-MM-dd",
                      "boost": 1
                    }
                  }
                }
              }
            },
            "functions": [
              {
                "filter": {
                  "match_all": {}
                },
                "script_score": {
                  "script": {
                    "source": "ArrayList x = params['_source']['orders'];if (x == null) { return 0 }long result = x.stream().filter(order -> {  if(params.startDate != null && !ZonedDateTime.parse(order.orderDate).isAfter(ZonedDateTime.parse(params.startDate))) return false; return true}).mapToLong(order->Long.parseLong(order.orderValue)).sum();if(params.operator == 'GT') return result > params.totalOrderValue ? 2 : 0;else if (params.operator == 'GE') return result >= params.totalOrderValue ? 3 : 0;else if (params.operator == 'LE') return result <= params.totalOrderValue ? 4 : 0;else if(params.operator == 'LT') return result < params.totalOrderValue ? 5 : 0;return result == params.totalOrderValue ? 6 : 0",
                    "lang": "painless",
                    "params": {
                      "totalOrderValue": 120,
                      "operator": "GE",
                      "startDate": "2012-12-10T23:00:00.000Z"
                    }
                  }
                }
              }
            ],
            "score_mode": "multiply",
            "max_boost": 3.4028235e+38,
            "boost": 1
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  }
}

它产生的实际分数是测试运算符的调试输出,但是min_score为1意味着它们中的任何一个都匹配。使用_source相当慢。

如果function_score中没有查询,它可以工作,但需要20秒左右的时间来处理300万条记录。使用该查询,您只查看订单实际上与日期范围匹配的客户。

由于无痛脚本处理整个订单列表,它必须重做日期数学。一些优化做那里,但至少我有一个概念证明。

我以前见过这个问题没有令人满意的答案,所以希望有人发现这很有用。

 类似资料:
  • 有没有办法在嵌套查询中使用“script_fields”,将字段添加到返回的inner_hits?例: 我执行n个嵌套查询,向每个嵌套查询传递一组特定的参数。这个想法是让源脚本根据提供的参数为每个内部命中的重叠字段分配一个值。 看起来在同一嵌套路径上执行更多的嵌套查询,定义不同的inner_hits使 ES 去除inner_hits匹配项。例: 如果像这样运行更多的嵌套查询,我会得到正确的匹配项,

  • 我是elasticsearch的新手,对如何进行过滤器、查询和聚合有一些想法,但不确定如何解决下面的问题。我希望能够从下面显示的文档中只查询公司的最新交付(日期和crate_quantity)。我不确定如何去做。有没有办法使用最大聚合从每个文档中只提取最近的交付?

  • null 我也尝试使用scripted_field,但是脚本字段似乎是在最后一个阶段计算的,在查询过程中不可用。 我也有一个按照相同逻辑进行排序的方法(根据给定仓库中库存的总和对产品进行排序),它像一个魅力一样工作: 但我也找不到访问此排序值的方法:(

  • 我有一个如下所示的ElasticSearch查询: 和像这样的文件作对。 因此,我能够根据文档名称和搜索名称与我的查询的接近程度来检索文档。 要求是,文本搜索框应该检索与查询匹配的最接近的名称,但是,如果给定相对相似的名称,在过去的时间段内投诉数量超过10的文档在搜索结果中的显示应该高于那些少于10的文档。 因此,我需要传递一个时间段的关键字,例如“01/01/2001-31/12/2001”,如

  • Sup社区。我有个问题。我正在使用Elasticsearch 6.4 我的数据结构的一部分: 我需要得到按成本排序的文档desc,我需要排序dirs字段中的值date_by字段与nulls-first。 如何对嵌套字段内的值进行排序,而不按此嵌套字段对文档进行排序?

  • 问题内容: 我想使用ES进行图书搜索。因此,我决定将作者姓名和标题(作为嵌套文档)放入索引,如下所示: 我不明白的是:如何构造搜索查询,以便在搜索“一二”时仅找到第二本书,而在搜索“二三”时什么也找不到,而在搜索“一”时所有图书呢? 问题答案: 也许是这样的? 该查询基本上说一个文件必须有and 。您可以轻松地重新配置该查询。例如,如果您只想搜索作者,请删除嵌套部分。如果您想要另一本书,请更改嵌套