提问人:gron 提问时间:10/25/2023 更新时间:10/25/2023 访问量:39
Elasticsearch - 如何找出嵌套对象的字段值大于 X 且最大日期的所有文档
Elasticsearch - How to find out all the documents where a field value of a nested object is greater than X with the max date
问:
我有一些公司模型的文件。每家公司都有一些财务报告。它们被设计为 Elasticsearch 的嵌套对象。例如:
[
{
"id": 1,
"financials": [
{
"periodEndDate": "2022-06-30",
"cash": 10000,
"inventory": 24000
},
{
"periodEndDate": "2022-12-31",
"cash": 12000,
"inventory": 19000
}
]
},
{
"id": 2,
"financials": [
{
"periodEndDate": "2022-12-31",
"cash": 200000,
"inventory": 1590000
},
{
"periodEndDate": "2023-03-31",
"cash": 210000,
"inventory": 1430000
}
]
}
]
我想在最近的期间结束日期报告中找出所有现金> 200000 的公司。期望的结果是公司 2,因为它的最新报告是 periodEndDate 为 2023-03-31 的报告,报告的现金是 210000。
如何编写查询?
此外,如果我想使用第二个到最近的日期筛选报告,查询是什么?
我找到了这篇文章: ElasticSearch - 获取字段值为 x 且类型的最大日期低于 y 日期的文档 但它需要“否定”过滤器,这对我不起作用,因为财务报告嵌套对象有太多字段。
答:
0赞
imotov
10/25/2023
#1
如果公司数量足够少,您不需要对它们进行分页,则可以使用组合和聚合来完成。基本上,它将找到最新报告,并将删除所有没有足够现金的公司。top_hits
bucket_selector
top_hits
bucket_selector
PUT test
{
"mappings": {
"properties": {
"id": {
"type": "long"
},
"financials": {
"type": "nested",
"properties": {
"periodEndDate": {
"type": "date"
},
"cash": {
"type":"long"
},
"inventory": {
"type": "long"
}
}
}
}
}
}
POST test/_bulk?refresh
{"index":{"_id":1}}
{"id":1,"financials":[{"periodEndDate":"2022-06-30","cash":10000,"inventory":24000},{"periodEndDate":"2022-12-31","cash":12000,"inventory":19000}]}
{"index":{"_id":2}}
{"id":2,"financials":[{"periodEndDate":"2022-12-31","cash":200000,"inventory":1590000},{"periodEndDate":"2023-03-31","cash":210000,"inventory":1430000}]}
POST test/_search
{
"size": 0,
"aggs": {
"companies": {
"terms": {
"field": "id"
},
"aggs": {
"nested": {
"nested": {
"path": "financials"
},
"aggs": {
"last_cash": {
"top_hits": {
"sort": [
{
"financials.periodEndDate": {
"order": "desc"
}
}
],
"_source": {
"includes": [
"financials.cash",
"financials.periodEndDate"
]
},
"size": 1
}
}
}
},
"having.top_cash": {
"bucket_selector": {
"buckets_path": {
"last_cash": "nested>last_cash[_source.cash]"
},
"script": "params.last_cash > 200000"
}
}
}
}
}
}
此方法有几个局限性,包括可伸缩性差、可以处理的公司数量有限以及不支持第二旧的报告。如果您还需要按相关性对公司进行排序或浏览它们,这也不是最好的解决方案。
为了实现所有这些功能并构建可扩展的解决方案,我建议在索引期间添加额外的处理,并将最新报表和第二个报表索引为主对象中的专用字段,而不是将它们存储为嵌套并尝试在搜索期间查找最新和第二个最新。因此,基本上您的记录应如下所示:
{
"id": 1,
"latest_finanicals": {
"periodEndDate": "2022-12-31",
"cash": 12000,
"inventory": 19000
}
},
"previous_finanicals": {
"periodEndDate": "2022-06-30",
"cash": 10000,
"inventory": 24000
}
}
"financials": [
{
"periodEndDate": "2022-06-30",
"cash": 10000,
"inventory": 24000
},
{
"periodEndDate": "2022-12-31",
"cash": 12000,
"inventory": 19000
}
]
}
with 和 having type 而不是 type。然后,您的所有查询都将变得非常简单。latest_finanicals
previous_finanicals
object
nested
评论
0赞
gron
10/25/2023
感谢您的精彩回答!我们有数以百万计的公司,因此分页和排序是强制性的。第二个解决方案是我一开始尝试过的。但是,财务报告有两种时间类型:年度和季度。PM 要求查找“最新”、“第二晚”、“最新年度”、“第二晚年度”、“最新季度”和“第二最新季度”。这些是 6 个额外的对象。我们还有更多模型,如财务报告。如果没有别的办法,我会采用它。
0赞
imotov
10/26/2023
嗯,我不确定您多久会在索引中收到相对于期间结束日期的报告,但我想知道 - 您能否将这些条件表示为日期范围,而不是排序列表中的最后一个和倒数第二个?如果可以的话,我想我可以提供更好的解决方案。
0赞
imotov
10/26/2023
在这种情况下,您还可以在嵌套对象上添加一个标记字段,指示该报表的状态,而不是创建所有这些附加字段。然后,您只需要在标记字段上添加一个术语查询作为条件之一。这里的主要问题是您要根据与其他记录的关系选择一条记录。如果您可以将相同的条件表达为不涉及记录之间关系的内容,那将会容易得多。例如,从现在到一个季度前的任何报告,而不是上一份报告,都会简化这一点。
0赞
gron
10/26/2023
不幸的是,我无法将日期条件表示为范围。例如,有两家公司 A 和 B。A的最新报告日期为2015-12-31。B的最新一次是在2023-06-30。虽然 A 报告的日期看起来很古老,但它是最新的并且与条件相符。
评论