elasticsearch 嵌套文档查询问题

2021-11-22 11:44:45 +08:00
 CRUD

求问一个 es 嵌套文档查询,仅当查询范围内所有嵌套文档都满足条件时才返回,而不是只要有一个嵌套文档满足条件就返回。

我的场景是按天建立嵌套文档,筛选时给定日期范围,需要筛选出该日期范围内每天都满足筛选条件的文档,目前我自己写的搜索语法只要日期范围内有一天满足就会返回..

我的文档结构如下:

{
    "mappings": {
        "properties": {
            "adResource": {
                "type": "nested",
                "properties": {
                    "day": {
                        "type": "date",
                        "format": "yyyy-MM-dd || epoch_millis"
                    },
                    "total": {
                        "type": "integer"
                    },
                    "subResource": {
                        "type": "nested",
                        "properties": {
                            "hours": {
                                "type": "integer"
                            },
                            "total": {
                                "type": "integer"
                            }
                        }
                    }
                }
            }
        }
    }
}

数据示例:

{
    "adResource": [
        {
            "total": 1800,
            "subResource": [
                {
                    "hours": 0,
                    "total": 0
                },
                {
                    "hours": 3600,
                    "total": 0
                },
                {
                    "hours": 7200,
                    "total": 0
                },
                {
                    "hours": ...,
                    "total": ...
                },
                {
                    "hours": 82800,
                    "total": 0
                }
            "day": "2021-11-20"
        },
        {
           "total": 5200,
           "subResource":[......]
           "day": "2021-11-21"
        }
    ]
}

需求:检索的时候给定一个日期区间和小时区间,要求检索出日期区间和小时区间内资源全部满足的文档,例如给定检索条件:

{
    "dayStart": "2021-11-20",
    "dayEnd": "2021-11-21",
    "total": 540,
    "subResource": [
        {
            "hour": 0,
            "total": 180
        },
        {
            "hour": 3600, // hour 3600 表示 1:00:00 到 1:59:59 的区间
            "total": 360
        }
    ]
}

表示 20 、21 这两天的 total>540 ,且这两天内的 hour 0 > 180 && hour 3600 > 360

目前的搜索语法如下,该搜索会返回 20 、21 这两天只有一天满足条件的文档,而我需要的是两天都满足的文档:

{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "adResource",
            "query": {
              "bool": {
                "must": [
                  {
                    "range": {
                      "adResource.day": {
                        "gte": "2021-11-20",
                        "lte": "2021-11-21"
                      }
                    }
                  },
                  {
                    "nested": {
                      "path": "adResource.subResource",
                      "query": {
                        "bool": {
                          "must": [
                            {
                              "bool": {
                                "must": [
                                  {
                                    "term": {
                                      "adResource.subResource.hours": {
                                        "value": "0"
                                      }
                                    }
                                  },
                                  {
                                    "range": {
                                      "adResource.subResource.total": {
                                        "gte": 180
                                      }
                                    }
                                  }
                                ]
                              }
                            },
                            {
                              "bool": {
                                "must": [
                                  {
                                    "term": {
                                      "adResource.subResource.hours": {
                                        "value": "3600"
                                      }
                                    }
                                  },
                                  {
                                    "range": {
                                      "adResource.subResource.total": {
                                        "gte": 360
                                      }
                                    }
                                  }
                                ]
                              }
                            }
                          ]
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}
2134 次点击
所在节点    Elasticsearch
5 条回复
Saxton
2021-11-22 14:54:40 +08:00
'''
{
"bool":{
"must":[
{
"term":{
"adResource.subResource.hours":{
"value":"0"
}
}
},
{
"range":{
"adResource.subResource.total":{
"gte":180
}
}
}
]
}
}
'''
为什么这里有一个 "value":"0" 呢
Saxton
2021-11-22 15:06:54 +08:00
你想要查询表示 20 、21 这两天的 total>540 ,且这两天内的 hour 0 > 180 && hour 3600 > 360 ,解析一下你的条件,20 、21 这两天的 total>540 这个为必要条件, 那么 hour 0 > 180 && hour 3600 > 360 应该为或条件,而不是且
CRUD
2021-11-22 16:23:36 +08:00
@Saxton value 0 表示的是 00:00-00:59 这段时间,我是把距离 0 点的秒数当做了小时的 key ,比如 0 表示 0 点到 1 点,3600 表示 1 点到 2 点,7200 表示 2 点到 3 点。

实际上 hour 0 > 180 && hour 3600 > 360 也是为且的,因为我需要的是在 0 点-1 点,1 点-2 点这个区间都满足的数据。
sadfQED2
2021-11-23 18:51:41 +08:00
我最近也被 es 的反人类查询语法折腾得死去活来,最后想了个办法,先用 sql 写出查询语句,再用最新的 es sql api 转成 dsl 语句

https://xjiangwei.cn/2021/11/23/ES_DSL/
morewe
2021-11-24 07:47:29 +08:00
@sadfQED2 看到你说被 ES 折磨的想原地去世那句好好笑。^-^。画面感扑面而来。一方面是大家都有 N 次被一个问题折磨几天的经历所以能够感同身受,但是当自己不被折磨时看别人被折磨就是有一种诡异的快乐。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/817085

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX