天天看點

Elasticsearch 空值處理實戰指南

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

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 技術交流群

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 技術!