V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
CRUD
V2EX  ›  Elasticsearch

elasticsearch 嵌套文档查询问题

  •  
  •   CRUD · 2021-11-22 11:44:45 +08:00 · 2103 次点击
    这是一个创建于 1074 天前的主题,其中的信息可能已经有所发展或是发生改变。

    求问一个 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
                                          }
                                        }
                                      }
                                    ]
                                  }
                                }
                              ]
                            }
                          }
                        }
                      }
                    ]
                  }
                }
              }
            }
          ]
        }
      }
    }
    
    5 条回复    2021-11-24 07:47:29 +08:00
    Saxton
        1
    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
        2
    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
        3
    CRUD  
    OP
       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
        4
    sadfQED2  
       2021-11-23 18:51:41 +08:00 via Android
    我最近也被 es 的反人类查询语法折腾得死去活来,最后想了个办法,先用 sql 写出查询语句,再用最新的 es sql api 转成 dsl 语句

    https://xjiangwei.cn/2021/11/23/ES_DSL/
    morewe
        5
    morewe  
       2021-11-24 07:47:29 +08:00
    @sadfQED2 看到你说被 ES 折磨的想原地去世那句好好笑。^-^。画面感扑面而来。一方面是大家都有 N 次被一个问题折磨几天的经历所以能够感同身受,但是当自己不被折磨时看别人被折磨就是有一种诡异的快乐。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4018 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 01:00 · PVG 09:00 · LAX 18:00 · JFK 21:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.