当前位置: 首页 > news >正文

【开源社区】Elasticsearch(ES)中 exists 查询空值字段的坑

文章目录

  • 1、概述
  • 2、使用 null_value 处理空值
  • 3、使用 exists 函数查询值为空的文档
    • 3.1 使用场景
    • 3.2 ES 中常见的空值查询方式
    • 3.3 常见误区
    • 3.4 使用 bool 查询函数查询空值字段
    • 3.5 exists 函数详解
      • 3.5.1 bool 查询的不足
      • 3.5.3 exists 的基本使用
    • 3.6 完美方案

1、概述

本文主要解决在 ES 中如何处理空只或者 NULL 值,如检索值为空的文档,如何存储空值或 NULL 值等。

2、使用 null_value 处理空值

详见:ES中使用 null_value 处理空值字段

3、使用 exists 函数查询值为空的文档

3.1 使用场景

在实际工作中,不可避免的可能会遇到以下需求:

查询 xx 字段 value = "" and value = null 的文档,或者value != "" and value != null 的文档

3.2 ES 中常见的空值查询方式

在本文第二小节相关文章的描述中,在 ES 中对于空值字段,通常采取的处理方式有两种:

  • 空值替换:预先对空值字段采取替换,即使用 null_value 设置针对于空值字段的替换值,具体用法详见文章内:传送门
  • exists 函数:exists 函数可用以判断字段是否存在,特定场景下可以用于对空值字段的查询

3.3 常见误区

我们仍以下面案例作为示例数据,来演示 esists 的具体使用细节

DELETE null_value_index
PUT null_value_index
{"mappings": {"properties": {"null_field": {"type": "text", "fields": {"keyword":{"type": "keyword"}}}}}
}# 写入测试数据
PUT null_value_index/_bulk
{"index":{"_id":1}}
{"null_field":null}
{"index":{"_id":2}}
{"null_field":"null"}
{"index":{"_id":3}}
{"null_field":""}
{"index":{"_id":4}}
{"null_field":" "}
{"index":{"_id":5}}
{"null_field":[]}

对于上述示例索引中的数据,如果我们希望 查询 null_field 字段不为空的所有文档,读者可以思考一下如何实现:

常见的误区:
以下是最容易产生的错误答案:

# 【错误答案】思路是查询字段值为""的文档
GET null_value_index/_search
{"query": {"bool": {"must": [{"match": {"null_field": ""}}]}}
}
# 或者:
# 【错误答案】思路是查询字段 null_field != "" 的文档
GET null_value_index/_search
{"query": {"bool": {"must_not": [{"match": {"null_field": ""}}]}}
}

执行以上查询发现结果是空的
在这里插入图片描述

3.4 使用 bool 查询函数查询空值字段

对于使用 must 或者 must_not 查询空值字段的方式是否可行呢?

虽然 3.3 小节中的答案是错误的,但是如果在此基础上稍加改变,将 match 查询改为 term 查询,就会得到争取的结果:

GET null_value_index/_search
{"query": {"bool": {"must": [{"term": {"null_field.keyword": ""}}]}}
}

执行结果如下(注意字段从 null_field 改为了 null_field.keyword):
在这里插入图片描述

对于上述结果,不难发现其扔存在一定问题:对于此类需求,往往需要查找的是所有空值字段,包括 ""、空白符、" "、null 等。解决办法也很简单:

把 term 换成 terms 即可

GET null_value_index/_search
{"query": {"bool": {"must": [{"terms": {"null_field.keyword": [""," "]}}]}}
}

在这里插入图片描述

3.5 exists 函数详解

3.5.1 bool 查询的不足

对于使用 bool 查询的方式查询空值字段是否能完美解决问题呢?

答案是:不能! id: 1 的这条数据并未被查询到,
在这里插入图片描述
肯定有大聪明会说,那是因为 terms 查询中并未添加 null,那么好,我们加上,发现会出现异常:
在这里插入图片描述
请注意,这里是 null 而非字符串 "null"

3.5.3 exists 的基本使用

那么对于以上问题,就需要使用 exists 函数来帮助解决。

首先要注意的是,exists 函数的意义是查询某个字段是不是存在,而非字段值。

举个例子,当我们执行以下代码的时候,其语义为:查询所有不存在 un_exists_field 字段的文档

GET null_value_index/_search
{"query": {"bool": {"must_not": [{"exists": {"field": "un_exists_field"}}]}}
}

当我们使用 exists 去查询 null 会出现什么结果呢?
在这里插入图片描述
请注意看,结果中包含了两条数据,被 exists 查询的字段都是存在的,但是却被召回了,这意味着:值为 null 或者 空数组 的字段,会被当做这个字段是不存在的

3.6 完美方案

基于 exists 这个特性,就弥补了 bool 查询不能查到 null 和 [] 这两种情况的缺陷,那么就可以将这两个查询结合起来使用

为了方便对比结果,我们加入第六条测试数据:

PUT null_value_index/_doc/6
{"null_field":"只是唯一有值的记录"
}

然后执行测试代码

# 查询所有空值字段, 包括 null""、空白符、空数组等
# 第一个子查询匹配 null 和 空数组,第二个子查询匹配其他空白符和 ""GET null_value_index/_search
{"query": {"bool": {"should": [{"bool": {"must_not": [{"exists": {"field": "null_field"}}]}},{"terms": {"null_field.keyword": [""," "]}}]}}
}

执行结果如图:
在这里插入图片描述
字段值为“空值”的 id:1/3/4/5 四条记录都被召回了,而 id:2/6 因为字段值不为空或 null,因此没有被召回,虽然 id: 2 的值为 “null”,但其也只不过为一个值为 “null” 的字符串而已,如果不希望被召回,将其添加到 terms 的 value 数组中即可。

同理,如果我们想 查询值不为空的所有记录,将上述代码改为以下代码即可

# 查询所有非空值字段
# 第一个子查询,匹配所有值非 null 和 空数组 的记录
# 第二个子查询,在第一个基础上,过滤掉所有值为 """ " 的字段
GET null_value_index/_search
{"query": {"bool": {"must":[ {"exists": {"field": "null_field"}},{"bool": {"must_not": [{"terms": {"null_field.keyword": [""," "]}}]}}]}}
}

执行结果如下:
在这里插入图片描述
同理,如果不希望 “null” 被查询到,将其添加到第二个子查询即可。

推荐阅读:【开源社区】Elasticsearch(ES)中空值字段 null_value 及通过exists查找非空文档

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【前端】vue监视属性和计算属性对比
  • mp4怎么转换成mp3?看了就会的8种mp4转mp3方法!
  • 快速查找数组中出现奇数次的数字
  • Web应用加密数据传输方案
  • mac安装xmind
  • 前后端不分离,form前端表单提交,springboot后端list接收
  • <数据集>车内视角行人识别数据集<目标检测>
  • Ubuntu系统入门
  • fpga图像处理实战-水平镜像
  • Linux--网络层 IP协议
  • 数据结构-双向链表 代码实现
  • 二刷代码随想录训练营Day 38|322. 零钱兑换、279.完全平方数、139.单词拆分
  • 证书学习(一)keytool 工具使用介绍
  • Lesson 81+82 Roast beef and potatoes
  • RAG优化技巧 | 7大挑战与解決方式 | 提高你的LLM: 下篇
  • 网络传输文件的问题
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • 2019.2.20 c++ 知识梳理
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • dva中组件的懒加载
  • eclipse(luna)创建web工程
  • Java 内存分配及垃圾回收机制初探
  • JS+CSS实现数字滚动
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • PermissionScope Swift4 兼容问题
  • SpringCloud(第 039 篇)链接Mysql数据库,通过JpaRepository编写数据库访问
  • yii2权限控制rbac之rule详细讲解
  • 笨办法学C 练习34:动态数组
  • 开发基于以太坊智能合约的DApp
  • 力扣(LeetCode)965
  • 前端相关框架总和
  • 深度解析利用ES6进行Promise封装总结
  • 思考 CSS 架构
  • 为视图添加丝滑的水波纹
  • 说说我为什么看好Spring Cloud Alibaba
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • #13 yum、编译安装与sed命令的使用
  • #define用法
  • #Z2294. 打印树的直径
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (1)虚拟机的安装与使用,linux系统安装
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (pojstep1.1.2)2654(直叙式模拟)
  • (附源码)计算机毕业设计ssm电影分享网站
  • (一)基于IDEA的JAVA基础1
  • (一)十分简易快速 自己训练样本 opencv级联haar分类器 车牌识别
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • .gitignore
  • .Net Core 微服务之Consul(三)-KV存储分布式锁
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET 动态调用WebService + WSE + UsernameToken
  • .NET 解决重复提交问题
  • .net生成的类,跨工程调用显示注释