【elasticsearch】Elasticsearch 空值处理实战

561 篇文章 548 订阅 ¥79.90 ¥99.00
本文介绍了Elasticsearch中如何处理空值,详细解析了null_value参数的含义和用法,强调了null_value需与数据类型匹配的重要性。针对text类型不支持null_value的问题,提出了使用keyword和text组合的解决方案。同时,文章讨论了在线问题,指出查询字段不为空应使用exists而非must_not,以及性能考虑。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1.概述

转载:Elasticsearch 空值处理实战指南
并且进行实操。

1、引言

实战业务场景中,经常会遇到定义空值、检索指定空值数据的情况。

这时候,当我们翻看官方文档 null_value 部分,会看到如下的描述:

Accepts a string value which is substituted for any explicit null values. Defaults to null, which means the field is treated as missing.

接受一个字符串值替换所有显式的空值。默认为null,这意味着该字段被视为丢失。

A null value cannot be indexed or searched. When a field is set to null, (or an empty array or an array of null values) it is treated as though that field has no values.

空值不能被索引或搜索。当字段设置为null(或空数组或 null 值的数组)时,将其视为该字段没有值。

光看字面意思,你是不是感觉不好理解?

好吧,死磕一把,探个究竟:

DELETE my-index-000001
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "status_code": {
        "type": "keyword"
      },
      "title": {
        "type": "text"
      }
    }
  }
}
 
PUT my-index-000001/_bulk
{"index":{"_id":1}}
{"status_code":null,"title":"just test"}
{"index":{"_id":2}}
{"status_code":"","title":"just test"}
{"index":{"_id":3}}
{"status_code":[],"title":"just test"}
 
POST my-index-000001/_search
 
POST my-index-000001/_search
{
  "query": {
    "term": {
      "status_code": null
    }
  }
}

如上检索返回错误如下:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "field name is null or empty"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "field name is null or empty"
  },
  "status": 400
}

2、null_value 的含义

The null_value parameter allows you to replace explicit null values with the specified value so that it can be indexed and searched.

使用 null_value 参数可以用指定的值替换显式的空值,以便可以对其进行索引和搜索。例如:

DELETE my-index-000001
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "status_code": {
        "type":       "keyword",
        "null_value": "NULL"
      }
    }
  }
}
 
PUT my-index-000001/_bulk
{"index":{"_id":1}}
{"status_code":null}
{"index":{"_id":2}}
{"status_code":[]}
{"index":{"_id":3}}
{"status_code":"NULL"}
 
GET my-index-000001/_search
{
  "query": {
    "term": {
      "status_code": "NULL"
    }
  }
}

返回值如下

    "hits" : [
      {
        "_index" : "my-index-000002",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18232156,
        "_source" : {
          "status_code" : null
        }
      },
      {
        "_index" : "my-index-000002",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.18232156,
        "_source" : {
          "status_code" : "NULL"
        }
      }
    ]

注意,这里返回结果:包含 _id = 1 以及 _id =3 的文档,不包含_id = 2 的文档。

说明一下:

"null_value": "NULL" 的含义:用指定的值替换显式的空值,“NULL”可以自定义,比如业务系统中我们可以定义成“Unkown”。

大家能看懂的大白话解释如下:

  1. 相当于我们在 Mapping 定义阶段指定了空的默认值,用“NULL”来代替,这样做的好处:类似如上的_id = 1 的文档,空字段也可以被索引、检索。

  2. 不会再报 “field name is null or empty” 的错误了。

3、null_value 使用注意

null_value 必须和定义的数据类型匹配,举例:long 类型字段不能有string 类型的 null value。

如下的定义就会报错:

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "status_code": {
        "type": "keyword"
      },
      "title": {
        "type": "long",
        "null_value": "NULL"
      }
    }
  }
}

报错如下:

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "Failed to parse mapping [_doc]: For input string: \"NULL\""
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "Failed to parse mapping [_doc]: For input string: \"NULL\"",
    "caused_by": {
      "type": "number_format_exception",
      "reason": "For input string: \"NULL\""
    }
  },
  "status": 400
}

解释一下:明显类型不匹配导致。

null_value 只影响了数据的索引,不会修改_source 文档。

4. 哪些字段有 null_value

哪些字段有null_value, 哪些字段没有null_value?

以下核心的常用字段都支持:null_value。

Arrays
Boolean
Date
geo_point
IP
Keyword
Numeric
point

别问我怎么知道的,挨个翻查的官方文档确认的。

最核心常问到的问题:

4.1 问题1:text 类型不支持 null_value 吗?

是的,不支持。

来吧,实战一把:

DELETE my-index-000001
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "status_code": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "null_value": "NULL"
      }
    }
  }
}

返回结果如下:

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "Mapping definition for [title] has unsupported parameters:  [null_value : NULL]"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "Failed to parse mapping [_doc]: Mapping definition for [title] has unsupported parameters:  [null_value : NULL]",
    "caused_by": {
      "type": "mapper_parsing_exception",
      "reason": "Mapping definition for [title] has unsupported parameters:  [null_value : NULL]"
    }
  },
  "status": 400
}

问题2:如果 text 类型也想设置空值,怎么搞呢?

推荐 multi-fields,借助 keyword 和 text 组合达到业务需求。

定义参考如下:

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "status_code": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "null_value": "NULL"
          }
        }
      }
    }
  }
}

对于 text 类型的字段,实战业务场景下,我们经常会需要同时设置:multi_fields, 将 text 和 keyword 组合设置

text 类型用于全文检索,keyword用于聚合和排序。

同时,multi_fields 是 Elastic 认证工程师的核心考点之一,大家务必要掌握。

5、线上问题探讨

老哥们,请教一个问题 ,我现在数据中有content这个字段,我想查询这个字段不为空字符串,我用must_not不行。我贴下我的sql

在这里插入图片描述

我的解读如下:

说下这个问题正确写法,以及之前写法不对的原因。

判定是否为空,本质是:精准匹配问题,不是全文检索的范畴(相似度匹配),所以选型使用:match_phrase 导致后面的错误。应该使用:term

POST test_001/_search
{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": [
            {
              "exists": {
                "field": "cont"
              }
            },
            {
              "term": {
                "content.keyword": {
                  "value": ""
                }
              }
            }
          ]
        }
      }
    }
  }
}
 

注意:exists 检索的含义是判定字段是否存在,结合使用效果佳、更稳妥!

如下的脚本也可以实现,但由于性能问题,实际业务层面不推荐使用。

POST test_001/_search
{
  "query": {
    "bool": {
      "filter": {
        "script": {
          "script": {
            "source": "doc['content.keyword'].length == 1",
            "lang": "painless"
          }
        }
      }
    }
  }
}
 

试想一下,如果在定义 Mapping 的数据建模阶段就定义了 text 和 keyword的组合 fields,并且:为keyword 设置了 null_value,这个问题就更好解决了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值