Elasticsearch 谜之null values

探讨Elasticsearch中处理空值或缺失字段的方法,包括null_value的设置与使用exists查询代替missing查询,确保数据完整性与搜索效率。

很多时候,我们需要面临null值的烦扰,查询es时传入null值是要查询出null的数据还是不查这个field呢,稍有不慎就会引发新的bug,这的确是个问题!

null_value 意味着无法索引或搜索空值。当字段设置为 null , [] ,和 [null] (这些null的表示形式都是等价的),它被视为该字段没有值。

null_value 意味着它将不会被表示为一个反向索引数据结构,它们根本不存在于反向索引中,故搜索也就无任何意义了。

难道就搜索没有办法了吗?

es为我们提供了missing查询,代表缺少字段或null值,但在6.x版本已经移除。取而代之的是exists查询,它的语义相当于SQL 中的 column is not null(有值)。它们都属于聚合操作。

显然,这个世界并不简单,数据常常缺少字段,或者包含显式的空或空数组。为了处理这些情况,es 给我们推荐了一些办法可以处理空值或缺少的值。

幸运的是,es 可以设置一个选项,用我们选择的占位符值替换显式的空值(当为字符串、数字、布尔值或日期字段指定映射时设置),当insert/update数据遇到空值时,将使用该值,这个显式的空值会对其进行索引,以便于搜索。

选择合适的空值时,请确保:

  • 它与字段的类型匹配。在日期类型的字段中不能使用字符串空值
  • 它不同于字段可能包含的正常值,以避免将实值与空值混淆

PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "status_code": {
          "type":       "keyword",
          "null_value": "NULL" 
        }
      }
    }
  }
}

PUT my_index/_doc/1
{
  "status_code": null
}

PUT my_index/_doc/2
{
  "status_code": [] 
}

GET my_index/_search
{
  "query": {
    "term": {
      "status_code": "NULL" 
    }
  }
}

<think> 我们注意到用户的问题是关于ElasticsearchES)中查询null的数据。虽然问题中提到了ES,但根据我们的角色设定,我们只能提供Java代码。因此,我们需要将问题转化为在Java中使用Elasticsearch客户端进行查询的场景。 在Elasticsearch中,查询null的数据通常有两种情况: 1. 字段不存在(不存在该字段) 2. 字段存在且显式设置为nullES中,我们可以使用`bool`查询结合`must_not`和`exists`来查询字段为null或字段不存在的文档。另外,也可以使用`missing`查询(旧版本),但是在较新的版本中,`missing`已经被废弃,推荐使用`bool`查询来实现。 以下是在Elasticsearch查询某个字段(例如"field_name")为null(包括不存在)的两种方法: 方法一:使用`bool`查询的`must_not`和`exists`组合 ``` { "query": { "bool": { "must_not": { "exists": { "field": "field_name" } } } } } ``` 方法二:直接使用`term`查询查询null(注意:这种方式只能查询显式设置为null的字段,而不能查询不存在的字段) ``` { "query": { "term": { "field_name": { "value": null } } } } ``` 但是,通常我们想要的是既不存在又为null的情况,所以方法一是更常用的。 由于我们的角色是Java专家,我们需要用Java代码来构建这个查询(假设使用Elasticsearch的高级REST客户端)。 以下是一个使用Java高级REST客户端构建查询的示例: 假设我们有一个Elasticsearch客户端实例`RestHighLevelClient client`。 步骤: 1. 构建一个`BoolQueryBuilder`,其中包含一个`must_not`子句,该子句是一个`ExistsQueryBuilder`(用于检查字段是否存在)。 2. 执行搜索。 注意:这里我们查询的是字段"exampleField"为null(包括不存在)的文档。 代码示例: </think> 在Elasticsearch查询字段为`null`的数据(包括字段不存在或显式设置为`null`),需要使用`bool`查询结合`must_not`和`exists`子句。以下是Java代码实现(使用Elasticsearch High Level REST Client): ### Java代码示例 ```java import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.ExistsQueryBuilder; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; public class ElasticsearchNullQuery { public void searchNullField(RestHighLevelClient client, String indexName, String fieldName) throws Exception { // 构建布尔查询:排除存在目标字段的文档 BoolQueryBuilder boolQuery = new BoolQueryBuilder(); boolQuery.mustNot(new ExistsQueryBuilder(fieldName)); // 关键语句 // 配置搜索源 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(boolQuery); sourceBuilder.size(100); // 设置返回结果数量 // 创建搜索请求 SearchRequest searchRequest = new SearchRequest(indexName); searchRequest.source(sourceBuilder); // 执行查询 SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); // 处理结果 SearchHits hits = response.getHits(); System.out.println("找到 " + hits.getTotalHits().value + " 条结果:"); hits.forEach(hit -> System.out.println(hit.getSourceAsString())); } } ``` ### 关键解释 1. **`mustNot(existsQuery(fieldName))`**: - `ExistsQueryBuilder` 匹配所有**包含目标字段**的文档(无论字段是什么) - `mustNot` 反向筛选,即排除所有包含该字段的文档 - 最终结果:只返回**字段不存在**或**字段为`null`**的文档 2. **为什么这样设计?** - Elasticsearch中字段为`null`、空数组`[]`或字段**不存在**会被视为等效 - 显式设置`{ "field": null }`和完全省略该字段在查询中行为一致 - 单独使用`term`查询无法覆盖字段不存在的情况 3. **注意事项**: - 确保字段在映射中未设置`"doc_values": false`或`"index": false` - 若需精确匹配**显式存储的`null`**(不含字段缺失),需额外结合`term`查询
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值