前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES系列10:Term-level queries 之 Range query

ES系列10:Term-level queries 之 Range query

作者头像
方才编程_公众号同名
发布2020-11-13 10:46:50
9040
发布2020-11-13 10:46:50
举报
文章被收录于专栏:方才编程

带着问题学习才高效

  1. 对date字段进行范围检索时,你还在使用代码计算时间范围?不知道 Date Math 如何使用?
  2. Date Math 的四舍五入没弄明白?检索范围总是违背预期
  3. 对区间类型字段的检索,不明白两个范围值的数学关系?

Term-level queries系列脑图

ps:上图的xmind文件获取方式见文末!

本文结构导航

在学习本文之前,请先参考ES系列09:Term-level queries 之 Term/Terms query完成 blogs_index 索引的创建,同时批量导入如下数据:

代码语言:javascript
复制
POST _bulk
{"index":{"_index":"blogs_index","_type":"_doc","_id":"1"}}
{"id":1,"author":"方才兄","title":"昨日博客","influence":{"gte":10,"lte":15},"createAt":"2020-05-24T10:56:23Z"}
{"index":{"_index":"blogs_index","_type":"_doc","_id":"2"}}
{"id":2,"author":"方才兄","title":"今日博客","influence":{"gte":10,"lte":20},"createAt":"2020-05-25T10:56:23Z"}
{"index":{"_index":"blogs_index","_type":"_doc","_id":"3"}}
{"id":3,"author":"方才兄","title":"一周内的博客","influence":{"gte":15,"lte":18},"createAt":"2020-05-18T10:56:23Z"}
{"index":{"_index":"blogs_index","_type":"_doc","_id":"4"}}
{"id":4,"author":"方才兄","title":"一周外的博客","influence":{"gte":15,"lt":18},"createAt":"2020-05-17T10:56:23Z"}
{"index":{"_index":"blogs_index","_type":"_doc","_id":"5"}}
{"id":5,"author":"方才兄","title":"上月博客","influence":{"gt":15,"lt":18},"createAt":"2020-04-26T10:56:23Z"}

01

range query 简介

range query 将匹配到检索字段在一定范围内的文档。Lucene查询的类型取决于字段类型,对于string字段为TermRangeQuery,对于数字/日期字段,类型为 NumericRangeQuery。【这涉及到ES底层实现,后续TeHero会专门开专栏进行分享】

该range查询接受以下参数:

gte 大于或等于

gt 大于

lte 小于或等于

lt 少于

boost 设置查询的提升值,默认为 1.0【权重问题,后续详解】

DSL示例:查询 1<= id <= 2 的文档

代码语言:javascript
复制
GET /tags_index/_search
{
    "query": {
        "range" : {
            "id" : {
                "gte" : 1,
               "lte" : 2,
                "boost" : 2.0
            }
        }
    }
}

02

在data字段上的range query

2.1 Date Math 详解

Date Math 由两部分组成:1、以固定的日期开头,这个固定的日期也可以是 now 或者是以“||”结尾的时间字符串;2、固定日期后面可接一个或多个数学表达式。

支持的时间单位有:y-Years、M-Months、w-Weeks、d-Days、h-Hours、H-Hours、m-Minutes、s-Seconds

看几个Date Math 示例加以理解,比如当前时间:now = 2020-05-26 13:00:00

1)now + 1h :now的毫秒值 + 1小时,结果为:2020-05-26 14:00:00

2)now-1h/d:now的毫秒值 + 1小时,再根据情况四舍五入到最近的一天的起始:2020-05-26 00:00:00 或者 结束:2020-05-26 23:59:59.999

3)2020-05-26||-1M/M:2020-05-26 的毫秒值 + 1个月,再根据情况四舍五入到最近的一月的起始:2020-04-01 00:00:00 或者 结束:2020-04-30 23:59:59.999

ps:这里说的“根据情况四舍五入”就是下面即将介绍的 date math to round

2.2 date math to round

当使用date math 将日期四舍五入到最接近的日期、月份、小时等的时候,四舍五入的日期取决于范围的结尾是包含端点还是排除端点。

1)包含端点:按最大范围四舍五入

gte 大于或等于四舍五入的日期:2020-05-25||/M变为 2020-05-01,即包括整个月份

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gte" : "2020-05-25||/M"
            }
        }
    }
}

上述DSL语句,是可以检索到文档1、2、3、4的(检索结果过长,此处就不展示了,可自行验证)。等价于sql【where createAt >= "2020-05-01 00:00:00"】

lte 小于或等于四舍五入的日期:2020-05-25||/M变为2020-05-31T23:59:59.999,即包括整个月份。

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "lte" : "2020-05-01||/M"
            }
        }
    }
}

上述DSL语句,可以检索到所有文档(检索结果过长,此处就不展示了,可自行验证)。等价于sql【where createAt <= "2020-05-31 23:59:59.999"】

2)排除端点:按最小范围四舍五入

gt 大于四舍五入的日期:2020-05-01||/M 变为 2020-05-31T23:59:59.999,即排除整个月份。

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gt" : "2020-05-01||/M"
            }
        }
    }
}

上述DSL语句,检索不到任何文档。等价于sql【where createAt > "2020-05-31T23:59:59.999"】

lt 少于四舍五入的日期:2020-05-31||/M变为2020-05-01,即排除整个月份。

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "lt" : "2020-05-31||/M"
            }
        }
    }
}

上述DSL语句,可以检索到文档5。等价于sql【where createAt < "2020-05-01 00:00:00"】

2.3 使用 Date Math 进行检索

ps:以下示例,基于now = 2020-05-25 23:00:00

1) 获取昨天发布的博客

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gte" : "now-1d/d",
               "lt" :  "now/d"
            }
        }
    }
}

分析:上述DSL可以检索到文档1【"title": "昨日博客"】,等价于sql【where createAt >= "2020-05-24 00:00:00" and createAt < "2020-05-25 00:00:00"】

2) 获取一周内发布的博客

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gte" : "now-1w/d",
               "lt" :  "now/d"
            }
        }
    }
}

分析:上述DSL可以检索到文档1【"title": "昨日博客"】和文档3【"title": "一周内的博客",】,等价于sql【where createAt >= "2020-05-18 00:00:00" and createAt < "2020-05-25 00:00:00"】

3) 获取本月内发布的博客

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gte" : "now/M",
               "lte" :  "now/M"
            }
        }
    }
}

分析:上述DSL可以检索到文档1/2/3/4,等价于sql【where createAt >= "2020-05-01 00:00:00" and createAt < "2020-05-31 23:59:59.999"】

2.4 日期格式

1)对日期字段进行检索时,默认使用被检索字段的format,但是可以通过“format”参数覆盖

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gte": "20/05/2020",
                "lte": "2021",
                "format": "dd/MM/yyyy||yyyy"
            }
        }
    }
}

请注意,如果日期缺少年,月和日的某些坐标,则丢失的部分将以unix time的开始(即1970年1月1日)填充 。
这意味着,例如,当指定dd格式时,"gte" : 10 将使用翻译成1970-01-10T00:00:00.000Z。

上述DSL语句,可以检索到文档1和文档2。等价于sql【where createAt >= "2020-05-24T00:00:00Z" and createAt < "2021-01-01T00:00:00.000Z" 】

注意:如果没有 "format",上述DSL执行将报parse_exception 异常,因为date类型默认只支持3种格式,请参见【ElasticSearch系列03:ES的数据类型

2)时区问题:time_zone参数

将日期从另一个时区转换为UTC

代码语言:javascript
复制
GET /blogs_index/_search
{
    "query": {
        "range" : {
            "createAt" : {
                "gte": "2020-05-25T11:56:23",
                "lte": "now",
                "time_zone": "+02:00"
            }
        }
    }
}

"gte": "2020-05-25T11:56:23", 该日期将转换为2020-05-25T09:56:23 UTC。【所以该DSL可以检索到文档2(它的"createAt" :"2020-05-25T10:56:23Z"),如果没有 "time_zone": "+02:00",就检索不到任何文档。 now不受time_zone参数的影响,它始终是当前系统时间(以UTC为单位)。但是,在使用日期数学舍入时(例如,使用向下舍入到最近的日期now/d),time_zone将考虑提供的值。

03

对类型为 range 字段的查询

relation参数控制这两个范围值【一个是文档field的value,一个是检索范围】如何匹配

先把文档influence字段的value列出来,方便大家对比数据:文档1【"gte":10,"lte":15】、文档2【"gte":10,"lte":20】、文档3【"gte":15,"lte":18】、文档4【"gte":15,"lt":18】、文档5【"gt":15,"lt":18】

3.1 WITHIN:文档的范围字段要完全在检索关键词的范围里

代码语言:javascript
复制
GET /blogs_index/_search
{
  "query" : {
    "range" : {
      "influence": {
        "gte" : 12,
        "lte" : 17,
        "relation" : "within"
      }
    }
  }
}

可以检索到文档4和文档5,【15,18)完全在【12,17】范围里

3.2 CONTAINS:文档的范围字段完全包含检索关键词的范围;

代码语言:javascript
复制
GET /blogs_index/_search
{
  "query" : {
    "range" : {
      "influence": {
        "gte" : 12,
        "lte" : 17,
        "relation" : "CONTAINS"
      }
    }
  }
}

可以检索到文档2,只有【10,20】完全包含【12,17】范围

3.3 INTERSECTS:为默认值)文档的范围字段与检索关键词的范围有交集即可。

代码语言:javascript
复制
GET /blogs_index/_search
{
  "query" : {
    "range" : {
      "influence": {
        "gte" : 12,
        "lte" : 17,
        "relation" : "CONTAINS"
      }
    }
  }
}

可以检索到所有文档,都有交集

04

总结

通过本文,我们应该掌握以下知识点:

1、会计算 Date Math,理解并掌握 Date Math 的四舍五入

2、掌握 range query 使用 Date Math 作检索;

3、对区间类型字段的检索,要理解并掌握 relation 参数的 3个值的含义

下期预告:Term-level queries(3)【关注公众号:方才编程,系统学习ES

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 方才编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档