Elasticsearch匹配数组中的日期范围或数字

时间:2016-09-18 07:56:53

标签: elasticsearch

我的目标是按日期和星期几过滤我的记录(Mo = 1,Tue = 2,Thu = 3,...,Sun = 7)。在这种情况下,日期或工作日应匹配数组中的任何日期。或两者兼而有之。我是Elasticsearch的新手,在我的查询中似乎有很多错误。我记录了所有内容,据我所知,并希望获得一些有用的见解。提前谢谢。

当前映射

{
  "index":{
    "mappings":{
      "entity":{
        "_meta":{
           "model":"AppBundle\\Entity\\Entity"
        },
        "properties":{
          "subEntity":{
            "properties":{
              "date":{
                "type":"date",
                "format":"strict_date_optional_time||epoch_millis"
              },
              "days":{
                "properties":{
                  "day":{
                    "type":"string"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

当前记录

curl -XGET 'localhost:9200/index/_search?pretty=1'
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 4,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "index",
      "_type" : "entity",
      "_id" : "1",
      "_score" : 1.0,
      "_source" : {
        "subEntity" : [ {
          "date" : "2016-09-20T00:00:00+02:00",
          "days" : [ ]
        }, {
          "date" : "2016-09-21T00:00:00+02:00",
          "days" : [ ]
        }, {
          "date" : "2016-09-22T00:00:00+02:00",
          "days" : [ {
            "day" : 4
          }, {
            "day" : 5
          }, {
            "day" : 6
          } ]
        }, {
          "date" : "2016-09-20T00:00:00+02:00",
          "days" : [ ]
        } ]
      }
    },
    [...]
  }
}

当前请求

{
  "query":{
    "should":{
      "filter":[ {
        "range":{
          "entity.subEntity.date":{
            "gte":"2016-09-20",
            "lte":"2016-09-21"
          }
        }
      }, {
        "term":{
          "entity.subEntity.days.day": 2
        }
      } ]
    }
  }
}

MySQL等效

SELECT entity
FROM entity
LEFT JOIN subEntity ON (subEntity.entity_id = entity.id)
LEFT JOIN day ON (day.subEntity_id = subEntity.id)
WHERE subEntity.date BETWEEN 2016-09-20 AND 2016-09-21
OR day = 2

2 个答案:

答案 0 :(得分:1)

如果要跨文档中的子对象的属性进行查询(文档可能包含此类子对象的集合),则需要将subEntity映射为nested type。在您的示例中,由于您只查找日期范围与日期值匹配的文档,因此您可以使用object映射,但是如果您需要合并查询使用操作,则需要nested类型映射。如果您需要这样做,那么映射为nested类型是有意义的。此外,由于日期是数字值,因此您应将其映射为byte

{
  "index":{
    "mappings":{
      "entity":{
        "_meta":{
           "model":"AppBundle\\Entity\\Entity"
        },
        "properties":{
          "subEntity":{
            "type": "nested",
            "properties":{
              "date":{
                "type":"date",
                "format":"strict_date_optional_time||epoch_millis"
              },
              "days":{
                "properties":{
                  "day":{
                    "type":"byte"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

现在subEntity被映射为nested类型,需要使用a nested query来查询它,因此查询变为

{
  "query": {
    "nested": {
      "query": {
        "bool": {
          "should": [
            {
              "bool": {
                "filter": [
                  {
                    "range": {
                      "subEntity.date": {
                        "gte": "2016-09-20",
                        "lte": "2016-09-21"
                      }
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "filter": [
                  {
                    "terms": {
                      "subEntity.days.day": [
                        2
                      ]
                    }
                  }
                ]
              }
            }
          ]
        }
      },
      "path": "subEntity"
    }
  }
}

这两个查询都是bool过滤查询,因为我们不需要计算任何一个的相关性得分,我们只需要知道文档是否匹配,即简单的是/否答案。在bool过滤器中扭曲查询意味着查询在过滤器上下文中运行。

接下来,任一查询都可以匹配,因此我们将should子句添加到外部bool查询。

作为一个完整的例子:

创建索引和映射

PUT http://localhost:9200/entities?pretty=true 
{
  "settings": {
    "index.number_of_replicas": 0,
    "index.number_of_shards": 1
  },
  "mappings": {
    "entity": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "subEntity": {
          "type": "nested",
          "properties": {
            "date": {
              "type": "date"
            },
            "days": {
              "properties": {
                "day": {
                  "type": "short"
                }
              },
              "type": "object"
            }
          }
        }
      }
    }
  }
}

批量索引四个实体

POST http://localhost:9200/_bulk?pretty=true 
{"index":{"_index":"entities","_type":"entity","_id":"1"}}
{"subEntity":{"date":"2016-09-19T05:00:00+00:00"}}
{"index":{"_index":"entities","_type":"entity","_id":"2"}}
{"subEntity":{"date":"2016-09-20T05:00:00+00:00"}}
{"index":{"_index":"entities","_type":"entity","_id":"3"}}
{"subEntity":{"date":"2016-09-18T18:00:00+00:00","days":[{"day":2},{"day":5}]}}
{"index":{"_index":"entities","_type":"entity","_id":"4"}}
{"subEntity":{"date":"2016-09-18T18:00:00+00:00","days":[{"day":3},{"day":4}]}}

发出上面的搜索查询

POST http://localhost:9200/entities/entity/_search?pretty=true 
{
  "query": {
    "nested": {
      "query": {
        "bool": {
          "should": [
            {
              "bool": {
                "filter": [
                  {
                    "range": {
                      "subEntity.date": {
                        "gte": "2016-09-20",
                        "lte": "2016-09-21"
                      }
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "filter": [
                  {
                    "terms": {
                      "subEntity.days.day": [
                        2
                      ]
                    }
                  }
                ]
              }
            }
          ]
        }
      },
      "path": "subEntity"
    }
  }
}

我们应该只返回带有ID 2和3的实体; id 2匹配日期,id 3匹配日

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.0,
    "hits" : [ {
      "_index" : "entities",
      "_type" : "entity",
      "_id" : "2",
      "_score" : 0.0,
      "_source" : {
        "subEntity" : {
          "date" : "2016-09-20T05:00:00+00:00"
        }
      }
    }, {
      "_index" : "entities",
      "_type" : "entity",
      "_id" : "3",
      "_score" : 0.0,
      "_source" : {
        "subEntity" : {
          "date" : "2016-09-18T18:00:00+00:00",
          "days" : [ {
            "day" : 2
          }, {
            "day" : 5
          } ]
        }
      }
    } ]
  }
}

答案 1 :(得分:0)

您的解决方案可以使用“或”查询轻松实现,但现在在es 2.0.0以后“或”查询已被弃用。在使用或查询的原位,我们现在可以使用“bool”查询。示例查询如下所示

{
 "query": {
    "bool" : {

    "should" : [
            {
                 "term" : { "CREAT_DT": "2015-11-03T07:49:07.000Z" }
            },
            {
                "term" : { "TableName": "dwd" }
            }
        ],

        "minimum_should_match" : 1,
        "boost" : 1.0
    }
    }
}

有关其用途的更多详细信息,请参阅以下链接 https://www.elastic.co/guide/en/elasticsearch/reference/2.0/query-dsl-bool-query.html