好吧,死磕一把,探個究竟:
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
"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 參數可以用指定的值替換顯式的空值,以便可以對其進行索引和搜尋。例如:
"type": "keyword",
"null_value": "NULL"
{"status_code":null}
{"status_code":[]}
{"status_code":"NULL"}
GET my-index-000001/_search
"status_code": "NULL"
注意,這裡傳回結果:包含 _id = 1 以及 _id =3 的文檔,不包含_id = 2 的文檔。
說明一下:
"null_value": "NULL" 的含義:用指定的值替換顯式的空值,“NULL”可以自定義,比如業務系統中我們可以定義成“Unkown”。
大家能看懂的大白話解釋如下:
相當于我們在 Mapping 定義階段指定了空的預設值,用“NULL”來代替,這樣做的好處:類似如上的_id = 1 的文檔,空字段也可以被索引、檢索。
不會再報 "field name is null or empty" 的錯誤了。
3、null_value 使用注意
null_value 必須和定義的資料類型比對,舉例:long 類型字段不能有string 類型的 null value。
如下的定義就會報錯:
"type": "long",
報錯如下:
"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\""
解釋一下:明顯類型不比對導緻。
null_value 隻影響了資料的索引,不會修改_source 文檔。
4、哪些字段有null_value, 哪些字段沒有null_value?
以下核心的常用字段都支援:null_value。
Arrays
Boolean
Date
geo_point
IP
Keyword
Numeric
point
别問我怎麼知道的,挨個翻查的官方文檔确認的。
最核心常問到的問題:
4.1 問題1:text 類型不支援 null_value 嗎?
是的,不支援。
來吧,實戰一把:
"type": "text",
傳回結果如下:
"reason": "Mapping definition for [title] has unsupported parameters: [null_value : NULL]"
"reason": "Failed to parse mapping [_doc]: Mapping definition for [title] has unsupported parameters: [null_value : NULL]",
"type": "mapper_parsing_exception",
"reason": "Mapping definition for [title] has unsupported parameters: [null_value : NULL]"
問題2:如果 text 類型也想設定空值,怎麼搞呢?
推薦 multi-fields,借助 keyword 和 text 組合達到業務需求。
定義參考如下:
"fields": {
"keyword": {
"type": "keyword",
"null_value": "NULL"
}
}
對于 text 類型的字段,實戰業務場景下,我們經常會需要同時設定:multi_fields, 将 text 和 keyword 組合設定。
text 類型用于全文檢索,keyword用于聚合和排序。
同時,multi_fields 是 Elastic 認證工程師的核心考點之一,大家務必要掌握。
5、線上問題探讨
老哥們,請教一個問題 ,我現在資料中有content這個字段,我想查詢這個字段不為空字元串,我用must_not不行。我貼下我的sql
死磕 Elasticsearch 技術交流群
我的解讀如下:
說下這個問題正确寫法,以及之前寫法不對的原因。
判定是否為空,本質是:精準比對問題,不是全文檢索的範疇(相似度比對),是以選型使用:match_phrase 導緻後面的錯誤。應該使用:term。
POST test_001/_search
"bool": {
"filter": {
"bool": {
"must": [
{
"exists": {
"field": "cont"
}
},
"term": {
"content.keyword": {
"value": ""
}
}
]
注意:exists 檢索的含義是判定字段是否存在,結合使用效果佳、更穩妥!
如下的腳本也可以實作,但由于性能問題,實際業務層面不推薦使用。
"script": {
"script": {
"source": "doc['content.keyword'].length == 1",
"lang": "painless"
試想一下,如果在定義 Mapping 的資料模組化階段就定義了 text 和 keyword的組合 fields,并且:為keyword 設定了 null_value,這個問題就更好解決了。
6、小結正如羅胖所說:再顯而易見的道理,在中國至少有一億人不知道。
而,我認為 Elasticsearch 技術也是,再顯而易見的技術點,在中國 Elastic 技術圈,至少有 N 多人不知道。
怎麼辦?死磕一下,探個究竟吧!
你的業務場景怎麼處理空值的呢?歡迎留言讨論。
7、加餐-讨論
有讀者私信留言:
其實老大也可以學習一下其他号,轉載一些大 V 或大公司的流量文章,圖文并茂的,雖然大家不一定看得懂,但看上去就很牛逼的樣子,給你的公号也能增粉,多好啊!你一周才1篇文章,大家都走了。
我的回複:
每個公衆号都有自己的使命和存在的價值,你可以仔細對比,每個号主都有自己的特點,為什麼要趨同呢?我感覺這樣也很好(就是苦點、窮點),并且從長遠角度(十年甚至更長時間),堅持原創的價值才能展現。
加微信:elastic6(僅有少量坑位了),和 BAT 大佬一起精進 Elastic 技術!