Elasticsearch(十一)搜索---搜索匹配功能②--range查询和exists查询

news2024/9/29 15:34:10

一、前言

继上一节学习了ES的搜索的查询全部和term搜索后,此节将把搜索匹配功能剩余的2个学习完,分别是range搜索和exists搜索

二、range范围搜索

range查询用于范围查询,一般是对数值型和日期型数据的查询。使用range进行范围查询时,用户可以按照需求中是否包含边界数值进行选项设置,可供组合的选项如下:

  • gt:大于;
  • lt 小于;
  • gte 大于等于;
  • lte 小于等于;

其请求形式如下:

GET /hotel/_search
{
 
 "query": {
   "range": {
     "FIELD": {   //需要范围查询的列
       "gte": "${VALUE1}",   //大于等于value1
       "lte": "${VALUE2}"    //小于等于value2
     }
   }
 }
}

以下是数值类型的查询示例,查询住宿价格在500~600(包含边界值)元的酒店:

GET /hotel/_search
{
 
 "query": {
   "range": {
     "price": {
       "gte": "500",
       "lte": "600"
     }
   }
 }
}

ES返回的数据如下:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "001",
        "_score" : 1.0,
        "_source" : {
          "title" : "文雅酒店",
          "city" : "北京",
          "price" : "558.00",
          "create_time" : "2020-03-29 21:00:00",
          "amenities" : "浴池,普通停车场/充电停车场",
          "full_room" : true,
          "location" : {
            "lat" : 36.940243,
            "lon" : 120.394
          },
          "praise" : 10
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "006",
        "_score" : 1.0,
        "_source" : {
          "title" : "京盛集团精选酒店",
          "city" : "上海",
          "price" : "500.00",
          "create_time" : "2022-01-29 22:50:00",
          "full_room" : true,
          "location" : {
            "lat" : 40.918229,
            "lon" : 118.422011
          },
          "praise" : 20
        }
      }
    ]
  }
}

如果我需要查询大于500元(不包含边界值)的酒店:

GET /hotel/_search
{
 
 "query": {
   "range": {
     "price": {
       "gt": "500"
     }
   }
 }
}

注意,使用range查询时,查询值必须符合该字段在mappings中设置的规范。例如,在酒店索引中,price字段是double类型,则range应该使用数值型或者数值类型的字符串形式,不能使用其他形式。以下示例将导致ES返回错误:

GET /hotel/_search
{
 
 "query": {
   "range": {
     "price": {
       "gt": "abc"
     }
   }
 }
}

执行上述DSL后,ES返回信息如下:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "query_shard_exception",
        "reason" : "failed to create query: For input string: \"abc\"",
        "index_uuid" : "az-MqIf9QM6asEIfivIBLQ",
        "index" : "hotel"
      }
    ],
    "type" : "search_phase_execution_exception",   //range查询解析异常
    "reason" : "all shards failed",
    "phase" : "query",
    "grouped" : true,
    "failed_shards" : [
      {
        "shard" : 0,
        "index" : "hotel",
        "node" : "ER773I31Sx-wJuJwJCh7Ng",
        "reason" : {
          "type" : "query_shard_exception",
          //构建range查询时出现异常
          "reason" : "failed to create query: For input string: \"abc\"",
          "index_uuid" : "az-MqIf9QM6asEIfivIBLQ",
          "index" : "hotel",
          "caused_by" : {
          //字符串类型不能转换为range查询对应的数值型数据
            "type" : "number_format_exception",
            "reason" : "For input string: \"abc\""
          }
        }
      }
    ]
  },
  "status" : 400
}

和term查询类似,查询日期型的字段时,需要遵循该字段在mappings中定义的格式进行查询。例如create_time使用的格式为"yyyy-MM-dd HH:mm:ss",则range查询应该使用如下方式:

GET /hotel/_search
{
 
 "query": {
   "range": {
     "create_time": {
       "gte": "2021-02-27 22:00:00",
       "lte": "2024-02-27 22:00:00"
     }
   }
 }
}

在Java客户端上构建range请求是使用QueryBuilders.rangeQuery()方法实现的,该方法的参数为字段名称,然后再调用对应的方法即可构建相应的查询范围。可以调用gt()、lt()、gte()、lte()等方法分别实现大于、小于、大于等于、小于等于等查询范围。在使用时支持链式编程,可以连着使用"."操作符,这样不用拆分语句,也比较容易理解,一下通过range查询完成一个createTime大于等于输入的createTimeStart和小于等于createEnd的一个范围查询
Service层:

		public List<Hotel> rangeQuery(HotelDocRequest hotelDocRequest) throws IOException {
		//新建搜索请求
		String indexName = hotelDocRequest.getIndexName();
		if (CharSequenceUtil.isBlank(indexName)) {
			throw new SearchException("索引名不能为空");
		}
		SearchRequest searchRequest = new SearchRequest(indexName);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		Date createTimeStart = hotelDocRequest.getCreateTimeStart();
		String createTimeStartToSearch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(createTimeStart);
		Date createTimeEnd = hotelDocRequest.getCreateTimeEnd();
		String createTimeEndToSearch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(createTimeEnd);
		searchSourceBuilder.query(QueryBuilders.rangeQuery("create_time").gte(createTimeStartToSearch).lte(createTimeEndToSearch));
		searchRequest.source(searchSourceBuilder);
		return getQueryResult(searchRequest);
	}

Controller层:

	@PostMapping("/query/range")
	public FoundationResponse<List<Hotel>> rangeQuery(@RequestBody HotelDocRequest hotelDocRequest) {
		try {
			List<Hotel> hotelList = esQueryService.rangeQuery(hotelDocRequest);
			if (CollUtil.isNotEmpty(hotelList)) {
				return FoundationResponse.success(hotelList);
			} else {
				return FoundationResponse.error(100,"no data");
			}
		} catch (IOException e) {
			log.warn("搜索发生异常,原因为:{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		} catch (Exception e) {
			log.error("服务发生异常,原因为:{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		}
	}

postman调用该接口:
在这里插入图片描述

三、exists查询

在某些场景下,我们希望找到某个字段不为空的文档,则可以用exists搜索。字段不为空的条件有:

  • 值存在且不是null
  • 值不是空数组
  • 值是数组,但不是[null]

为方便测试,给索引hotel增加tag字段,DSL如下:

POST /hotel/_mapping
{
    "properties": {
      "tag":{
        "type": "keyword"
      }
    }
}

下面向该索引中分别写入3条字段为空的数据。
添加tag字段值为null的文档,DSL如下:

POST /hotel/_create/020
{
  "title":"环球酒店",
  "tag":null
}

添加tag字段是空数组的文档,DSL如下:

POST /hotel/_create/021
{
  "title":"环球酒店2",
  "tag":[]
}

添加tag为数组,其中只有一个元素,且该元素为null的文档,DSL如下:

POST /hotel/_create/022
{
  "title":"环球酒店3",
  "tag":[null]
}

上面3种情况的数据使用exists查询都不命中,查询的DSL如下:

GET /hotel/_search
{
  "query": {
    "exists": {
      "field": "tag"
    }
  }
}

返回结果如下:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,          //命中的文档个数为0
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]   //命中的文档集合为空
  }
}

在java客户端中进行查询时,可以调用QueryBuilders.existsQuery(String name)方法新建一个exists查询,传递的name参数是目标字段名称。以下是使用Java客户端构建exists查询的示例:
service层:

	public List<Hotel> existQuery(HotelDocRequest hotelDocRequest) throws IOException {
		//新建搜索请求
		String indexName = hotelDocRequest.getIndexName();
		String propertiesName = hotelDocRequest.getPropertiesName();
		if (CharSequenceUtil.isBlank(indexName)) {
			throw new SearchException("索引名不能为空");
		}
		if (CharSequenceUtil.isBlank(propertiesName)) {
			throw new SearchException("想要查询的字段名不能为空");
		}
		SearchRequest searchRequest = new SearchRequest(indexName);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.from(hotelDocRequest.getOffset());
		searchSourceBuilder.size(hotelDocRequest.getLimit());
		searchSourceBuilder.query(QueryBuilders.existsQuery(propertiesName));
		searchRequest.source(searchSourceBuilder);
		return getQueryResult(searchRequest);
	}

controller层:

	@PostMapping("/query/exist")
	public FoundationResponse<List<Hotel>> existQuery(@RequestBody HotelDocRequest hotelDocRequest) {
		try {
			List<Hotel> hotelList = esQueryService.existQuery(hotelDocRequest);
			if (CollUtil.isNotEmpty(hotelList)) {
				return FoundationResponse.success(hotelList);
			} else {
				return FoundationResponse.error(100,"no data");
			}
		} catch (IOException e) {
			log.warn("搜索发生异常,原因为:{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		} catch (Exception e) {
			log.error("服务发生异常,原因为:{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		}
	}

postman调用即可,比如搜索之前tag字段:
没有搜到,所以报了no data
在这里插入图片描述
如果搜索title,则会将title不为null的值全部搜索出来,由于title不为空的比较多,我这边只查前3条:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/670817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

创建多线程的四种方式

目录儿 一、创建线程的四种方式1. 继承Thread类2. 实现Runnable接口3. 实现Callable接口4. 线程池禁止使用 Executors 构建线程池构建线程池的正确方式 一、创建线程的四种方式 1. 继承Thread类 ① 创建一个类继承Thread类&#xff0c;重写run()方法 ② 调用start()方法启动线…

AI卷入618战场;印象AI开放次数限制;2023 AIGC人才趋势洞察报告;员工瞒着老板悄悄用AI;超好用的AI头像生成教程 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 澳洲游戏媒体 Gamurs 招聘AI编辑&#xff0c;被各路媒体口诛笔伐 上周&#xff0c;澳洲知名游戏媒体集团 Gamurs 在官网招聘「AI Edit…

负载测试和压力测试有何区别?资深测试老鸟总结,一篇搞定...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 负载与压力测试 …

js中数组对象去重的几种方式

js中数组对象去重的几种方式 1、方法一&#xff1a;双层for循环2、对象访问属性的方法3、Map()方法4、reduce方法 首先我们定义数组的形式 let arrObj [{ name: "张三", key: 1 },{ name: "李四", key: 2 },{ name: "王五", key: 3 },{ name: &…

基于langchain+chatGLM搭建部署本地私有化知识库系统

前言 一、 自主GPT 所谓自主&#xff08;autonomous&#xff09;GPT是设计一个Agent&#xff0c;让它自己做计划、决策和动作&#xff0c;通过源源不断的迭代&#xff0c;去完成设定的目标。比如 AutoGPT 。 AutoGPT把GPT的能力推向了更高的应用层次。设定一个任务&#xff…

mac下qtcreator代码格式化

代码开发&#xff1a;qtcreator qtcreator 插件&#xff1a;Beautifier 格式化工具&#xff1a;clang-format 1、Beautifier插件安装 将复现框勾选后重启qtcreator即可。 2、安装clang-format工具 &#xff08;1&#xff09;打开终端输入下面命令等待安装完成 brew install…

Python基础(19)——Python函数讲解一

Python基础&#xff08;19&#xff09;——Python函数讲解一 文章目录 Python基础&#xff08;19&#xff09;——Python函数讲解一目标一. 函数的作用二. 函数的使用步骤2.1 定义函数2.2 调用函数2.3 快速体验 三.函数的参数作用四.函数的返回值作用4.1 应用 五.函数的说明文档…

大快人心,华为EDA领域的新突破,关联软件已取得全面适配

EDA被称为“芯片之母”&#xff0c;是集成电路、电子信息&#xff0c;甚至是全球数字经济的赋能者&#xff0c;是许多电子产业链的基石。 一直以来&#xff0c;就被国际的三大巨头占领&#xff1a;美国Synopsys、美国Cadence、德国Mentor Graphics&#xff0c;市场份额高达90%。…

locust学习教程(6)- 使用更快的http客户端:FastHttpUser

目录 1、概念 2、估算电脑允许的最大并发数 3、fasthttpuser的使用 &#x1f381;更多干货 完整版文档下载方式&#xff1a; 1、概念 Locust 的默认 HTTP 客户端使用的是 python-requests 库。如果我们需要运行非常高的吞吐量测试&#xff0c;去判断吞吐量是否达到预期值&…

免费文字转语音软件哪个好?推荐这三款文字转语音软件给你

文字转语音软件可以将我们输入的文字内容转化为人声朗读出来&#xff0c;这在很多场合都非常实用。比如&#xff0c;在开车或者做家务时&#xff0c;无法手持手机进行阅读&#xff0c;但是通过文字转语音功能&#xff0c;就可以轻松地听取所需内容。然而&#xff0c;市面上的文…

贴吧私信辅助软件工具开发

贴吧私信辅助软件工具开发&#xff0c;贴吧无线私信&#xff0c;用好贴吧也是一个大流量途径 【引流必备】最新外面卖1000多一套的贴吧私信机&#xff0c;日发私信十万条【详细视频操作教程软件】 服务时间&#xff1a;&#xff08;8&#xff1a;00—23&#xff1a;00&#xf…

MySQL数据库——事务

MySQL数据库——事务 一、事务的概念二、事务的ACID特点1.原子性2.一致性3.隔离性4.持久性5.事务隔离级别的作用范围 三、事务级别的查看与设置1.查询全局事务隔离级别2.查询会话事务隔离级别3.设置全局事务隔离级别4.设置会话事务隔离级别 四、事务控制语句1.测试提交事务2.测…

ssm 疫情防控数据可视化平台-计算机毕设 附源码87063

ssm 疫情防控数据可视化平台 摘要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对疫情防控数据可…

图像直方图笔记

图像直方图 在统计学中&#xff0c;直方图是一种对数据分布情况的图形化表示方法。 图像直方图是用来表示数字图像中亮度分布的直方图&#xff0c;使用图像直方图可以很直观地观察到该图的亮度分布情况。在图像直方图中&#xff0c;横轴从左到右分别表示了从纯黑到纯白区域的亮…

【C语言初阶】函数的具体用法,有这篇博客就够了

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello&#xff0c;这里是君兮_&#xff0c;今天又又又来给大家更新0基础C语言中的内容啦&#xff01;今天给大家带来的是C语言当中函数的调用以及使用&#xff0c;废话不多说我们直接开始吧&#xff01; 函数详解 一.函数…

专治疑难系列 - 解决打印机凭证冲突问题

‍‍&#x1f3e1;博客主页&#xff1a; Passerby_Wang的博客_CSDN博客-系统运维,云计算,Linux基础领域博主 &#x1f310;所属专栏&#xff1a;『专治疑难系列』 &#x1f30c;上期文章&#xff1a; 专治疑难系列 - 解决Ubuntu忘记root密码问题 &#x1f4f0;如觉得博主文章…

深度学习实例分割篇——Mask RCNN原理详解篇

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

如何系列 如何使用SikuliX执行自动化任务

文章目录 什么是SikuliX&#xff1f;SikuliX的使用场景安装SikuliX常用方法查找鼠标键盘其他 示例脚本示例一 自动抢票示例二 自动打开计算器示例三 自动访问CSDN博客搜索博主并关注其他 SikuliX原理SikuliX脚本Sikuli 源文件夹或压缩文件&#xff08;.sikuli、.skl&#xff09…

电源纹波测试,居然还能这么玩

开关稳压器因其具有非常高的效率优势&#xff0c;正在各个领域逐渐替代线性稳压器。 但由于开关稳压器通常被认为具有很大的输出纹波(Ripple)&#xff0c;所以很多工程师在高性能和噪声敏感型系统中只考虑使用低压差(LDO)稳压器。 而事实上&#xff0c;现今很多高性能开关稳压…

人机接口回路原理(三)

四、串行通信接口电路 &#xff08;一&#xff09;人机接口与保护CPU之间的串行通信 1&#xff0e;串行通信接口电路及其作用 人机接口与保护CPU之间的串行通信的作用是人机对话和巡检&#xff0c;其电路见图1&#xff0d;33所示。这个串行通信系统是主从分布式的系统&#x…