07 | 范围查询

465 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

1.查询过程

因为本专栏只讲实战,理论性的东西只稍微讲一下

我们现在是在集群上新建的索引,之前的新建索引的时候我们是设置了分片是3,也即是说数据会根据Es的分片算法,将3份数据分布在各个机器上。

比如现在有三条数据,分了三个shard,每个机器一个shard, 当我们发起一个查询的时候,查询流程大致如下:

1.客户端将查询请求发送到master节点

2.master节点将查询请求发送到索引的各个分片中

3.每个分片在本地执行查询逻辑

4.每个分片将查询结果返回给master节点,由master节点进行合并

es查询流程.png

## 2.ES的范围查询

2.1 范围查询的一些基础

范围查询主要是用于匹配某些字段的字段值位于特定范围内的文档。

范围查询接收以下参数

  • gt:大于
  • gte:大于等于
  • lt:小于
  • lte:小于等于
  • format:用于转换日期查询中值类型为date数据的格式
  • time_zone:时区,默认的是美国时区,中国时间查询时候我们需要加上Asia/Shanghai
  • boost:相关性,值是float类型,默认相关性是1.0,我们查处的结果会有一个_score字段,它代表的意思就是查询条件跟结果的相关性得分

2.2 普通范围查询

比如我们要查询商品价格在10-15元范围内的商品价格,DSL实现如下

GET /goods_item_index/_search
{
  "query": {
    "range": {
      "basePrice": {
        "gte": 10,
        "lte": 15
      }
    }
  }
}

2.3 日期范围查询

查询更新时间在2008-01-01 00:00:00到2010-01-01 00:00:00这个时间范围内的商品数据,DSL实现如下

GET /goods_item_index/_search
{
  "query": {
    "range": {
      "updateTime": {
        "gte": "2008-01-01 00:00:00",
        "lte": "2010-01-01 00:00:00",
        "format": "yyyy-MM-dd HH:mm:ss",//如期格式
        "time_zone": "Asia/Shanghai"    //上海时区
      }
    }
  }
}

2.4 Date Math日期数学表达式

当我们使用gtgteltlte这几个比较参数的时候,我们可以使用日期数学表达式来进行日期的比较。

支持的时间单位为包含如下几项

  • y:年
  • M:月
  • w:周
  • d:天
  • h:小时
  • H:小时
  • m:分钟
  • s:秒

表达式通常的操作会是这样

  • +1d,表示加上一天
  • -15y,表示减去15年
  • /d,表示向一天取整

举几个例子:

  • now-14y/y,表示当前时间减去14年,并向一年取整
  • now+1h+1m,表示当前时间加上一个小时零一分钟
  • 2008-08-01 00:00:00||-1M/d,表示2008-08-01减去一个月,并向一天取整

假如我们要查询从现在开始,查询过去14年的数据,DSL表达式如下

GET /goods_item_index/_search
{
  "query": {
    "range": {
      "updateTime": {
        "gte": "now-14y/y",
        "lte": "now/y"
      }
    }
  }
}

假如我们要查询小于2008-08-01 00:00:00开始减去一个月的时间,且大于2008-06-01 00:00:00这个时间点的数据,DSL如下

GET /goods_item_index/_search
{
  "query": {
    "range": {
      "updateTime": {
        "gte": "2008-06-01 00:00:00",
        "lte": "2008-08-01 00:00:00||-1M/d"
      }
    }
  }
}

3. 基于Java Api实现

我们在com.daiyu.elastic.service.GoodsService新增范围查询方法

  /**
     * 日期范围查询
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 返回结果集
     */
    List<GoodsItemRep> queryByDateRange(String startTime, String endTime);

    /**
     * 标签价格范围查询
     *
     * @param minPrice 最小价格
     * @param maxPrice 最大价格
     * @return 返回结果集
     */
    List<GoodsItemRep> queryByPriceRange(String minPrice, String maxPrice);

然后在com.daiyu.elastic.service.Impl.GoodsServiceImpl进行实现

@Override
    public List<GoodsItemRep> queryByDateRange(String startTime, String endTime) {
        List<GoodsItemRep> goodsItemReps = new ArrayList<>();

        Query query = RangeQuery.of(q -> q
                .field("updateTime")
                .gt(JsonData.of(startTime))
                .lt(JsonData.of(endTime))
                .timeZone("Asia/Shanghai")
        )._toQuery();
        List<GoodsItem> result = client.search(index, GoodsItem.class, query);

        result.stream().forEach(goodsItem -> {
            GoodsItemRep goodsItemRep = new GoodsItemRep();
            BeanUtils.copyProperties(goodsItem, goodsItemRep);
            goodsItemReps.add(goodsItemRep);
        });

        return goodsItemReps;
    }

    @Override
    public List<GoodsItemRep> queryByPriceRange(String minPrice, String maxPrice) {
        List<GoodsItemRep> goodsItemReps = new ArrayList<>();

        Query query = RangeQuery.of(q -> q
                .field("basePrice")
                .gt(JsonData.of(minPrice))
                .lt(JsonData.of(maxPrice)))._toQuery();
        List<GoodsItem> result = client.search(index, GoodsItem.class, query);

        result.stream().forEach(goodsItem -> {
            GoodsItemRep goodsItemRep = new GoodsItemRep();
            BeanUtils.copyProperties(goodsItem, goodsItemRep);
            goodsItemReps.add(goodsItemRep);
        });

        return goodsItemReps;
    }

接下来在postman等接口调用工具进行调用查看接调用结果

  • 日期范围查询
curl --location --request POST 'http://localhost:8089/goods/queryByDateRange?startDate=2008-06-01 00:00:00&endDate=2008-08-01 00:00:00'

image-20221122160042269.png

  • 价格范围查询
curl --location --request POST 'http://localhost:8089/goods/queryByPriceRange?minPrice=10.00&maxPrice=15.00'
image-20221122160055068.png

到此我们已经熟悉了es的范围查询,更多的我们还需要根据自己的业务实际场景去调整。