Elasticsearch查询数组匹配查询中的日期数

时间:2019-05-31 01:01:14

标签: elasticsearch

我的文件格式如下

PUT test_index/_doc/1
{
    "dates" : [
      "2018-07-15T14:12:12",
      "2018-09-15T14:12:12",
      "2018-11-15T14:12:12",
      "2019-01-15T14:12:12",
      "2019-03-15T14:12:12",
      "2019-04-15T14:12:12",
      "2019-05-15T14:12:12"],
    "message" : "hello world"
}

如何查询文档,以使n数组中有dates个日期位于两个指定日期之间?

例如:在dates"2018-05-15T14:12:12"之间的"2018-12-15T14:12:12"数组中查找具有3个日期的所有文档-这应以"2018-07-15T14:12:12",{ {1}}和"2018-09-15T14:12:12"介于"2018-11-15T14:12:12""2018-05-15T14:12:12"之间。

3 个答案:

答案 0 :(得分:1)

我最近遇到了同样的问题。但是提出了两种解决方案。

1)如果您不想更改当前映射,则可以使用query_string查询文档。还要注意,您将必须根据您拥有的范围来创建查询对象。 (“ \” 2019-04-08 \“或\” 2019-04-09 \“或\” 2019-04-10 \“”

      {
  "query": {
    "query_string": {
      "default_field": "dates",
      "query": "\"2019-04-08\" OR \"2019-04-09\" OR \"2019-04-10\" "
    }
  }
}

但是,仅当范围较短时,这种类型的查询才有意义。

2)第二种方法是嵌套方法。但是您将必须以这种方式更改当前映射。

 {
  "properties": {
    "dates": {
      "type": "nested",
      "properties": {
        "key": {
              "type": "date",
              "format": "YYYY-MM-dd"
            }
      }
    }
  }
}

因此您的查询将如下所示:-

     {
  "query": {
    "nested": {
      "path": "dates",
      "query": {
        "bool": {
          "must": [
            {
              "range": {
                "dates.key": {
                  "gte": "2018-04-01",
                  "lte": "2018-12-31"
                }
              }
            }
          ]
        }
      }
    }
  }
}

答案 1 :(得分:0)

您可以将日期创建为nested document,并使用bucket selector聚合。

{
  "empId":1,
  "dates":[
             { 
               "Days":"2019-01-01"
             },
             { 
               "Days":"2019-01-02"
             }
          ]
}

映射:

 "mappings" : {
      "properties" : {
       "empId" : {
              "type" : "keyword"
        },
        "dates" : {
          "type" : "nested",
          "properties" : {
            "Days" : {
              "type" : "date"
            }
          }
        }
     }
  }
GET profile/_search
{
  "query": {
    "bool": {
      "filter": {
        "nested": {
          "path": "dates",
          "query": {
            "range": {
              "dates.Days": {
                "format": "yyyy-MM-dd",
                "gte": "2019-05-01",
                "lte": "2019-05-30"
              }
            }
          }
        }
      }
    }
  },
  "aggs": {
    "terms_parent_id": {
      "terms": {
        "field": "empId"
      },
      "aggs": {
        "availabilities": {
          "nested": {
            "path": "dates"
          },
          "aggs": {
            "avail": {
              "range": {
                "field": "dates.Days",
                "ranges": [
                  {
                    "from": "2019-05-01",
                    "to": "2019-05-30"
                  }
                ]
              },
              "aggs": {
                "count_Total": {
                  "value_count": {
                    "field": "dates.Days"
                  }
                }
              }
            },
            "max_hourly_inner": {
              "max_bucket": {
                "buckets_path": "avail>count_Total"
              }
            }
          }
        },
        "bucket_selector_page_id_term_count": {
          "bucket_selector": {
            "buckets_path": {
              "children_count": "availabilities>max_hourly_inner"
            },
            "script": "params.children_count>=19;"  ---> give the number of days that should match
          }
        },
        "hits": {
              "top_hits": {
                "size": 10   
              }
            }
      }
    }
  }
}

答案 2 :(得分:0)

我找到了自己的答案,尽管我不确定与其他答案相比有多有效:

GET test_index/_search
{
  "query":{
    "bool" : {
        "filter" : {
          "script" : {
            "script" : {"source":"""
            int count = 0;
            for (int i=0; i<doc['dates'].length; ++i) {
              if (params.first_date < doc['dates'][i].toInstant().toEpochMilli() && doc['dates'][i].toInstant().toEpochMilli() < params.second_date) {
                count += 1; 
              }
            }
            if (count >= 2) {
              return true
            } else {
              return false
            }
            """,
            "lang":"painless",
            "params": {
              "first_date": 1554818400000,
              "second_date": 1583020800000
            }
            }
          }
        }
    }
  }
}

其中参数是纪元时间中的两个日期。我在这里选择了2个匹配项,但显然您可以将其推广到任何数字。