基本環境 elasticsearch版本:6.3.1 客戶端環境:kibana 6.3.4、Java8應用程式模塊。 其中kibana主要用於數據查詢診斷和查閱日誌,Java8為主要的客戶端,數據插入和查詢都是由Java實現的。 案例介紹 使用elasticsearch存儲訂單的主要信息,docum ...
基本環境
- elasticsearch版本:6.3.1
- 客戶端環境:kibana 6.3.4、Java8應用程式模塊。
其中kibana主要用於數據查詢診斷和查閱日誌,Java8為主要的客戶端,數據插入和查詢都是由Java實現的。
案例介紹
使用elasticsearch存儲訂單的主要信息,document內的field,基本上是long或keyword,創建索引的order.json文件如下:
{
"doc": {
"properties": {
"id": {
"type": "keyword",
"index": true
},
"status": {
"type": "byte",
"index": true
},
"createTime": {
"type": "long",
"index": true
},
"uid": {
"type": "long",
"index": true
},
"payment": {
"type": "keyword",
"index": true
},
"commentStatus": {
"type": "byte",
"index": true
},
"refundStatus": {
"type": "byte",
"index": true
}
}
}
}
某天發現有個查詢功能(單獨使用payment欄位查詢)沒有數據出來,最近未修改此部分代碼。對比研發環境,研發環境是正常的,同樣的代碼在測試環境下無數據返回。
問題定位
- 程式中使用該欄位用的是termQuery,如下:
QueryBuilders.termQuery("payment", req.getFilter().getOrder().getPayment())
在kibana上用命令診斷查詢數據,同樣沒有結果返回,查詢命令如下:
GET /order/doc/_search
{
"query": {
"bool": {
"must": [
{"term": {
"payment": "Alipay"
}}
]
}
}
}
- 查詢mapping信息,看是否為keyword:
GET /order/_mapping/doc
響應返回(只展示payment欄位):
{
"order": {
"mappings": {
"doc": {
"properties": {
"payment": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
問題原因
按照mapping返回結果來看,欄位payment原定義的類型是keyword,現在變成text了,這個是payment欄位使用termQuery查詢導致沒有數據的原因。
text與keyword的區別
keyword對保存的內容不分詞,也不改變大小寫,原樣存儲,預設可索引。
text對內容進行分詞,並且全部小寫存儲,同時會增加一個text.keyword欄位,為keyword類型,超過256字元後不索引。
由於payment欄位變成text了,原有的程式使用term查詢,用的"Alipay",而text存儲的是"alipay",所以查不到數據了。
嘗試排錯方法
- payment的值改成小寫
GET /order/doc/_search
{
"query": {
"bool": {
"must": [
{"term": {
"payment": "alipay"
}}
]
}
}
}
- 或將term查詢改成match查詢
GET /order/doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"payment": "alipay"
}
}
]
}
}
}
查詢有數據輸出,並且符合預期,嘗試方法有效。
問題追溯
明明order.json的對payment欄位定義的類型是keyword,怎麼變成text了?
由於出現此問題的環境是測試環境,有重刪索引數據,然後再全部導入的操作(有點不規範,但僅限於測試環境,生產環境不會這麼做),重新導入索引document數據的功能,es創建索引自動mapping時,payment欄位的string內容,會變成text。
解決辦法:
1.刪除索引
DELETE /order
2.按照order.json重建索引
PUT /order
{
"mappings": {
"doc": {
"properties": {
"id": {
"type": "keyword",
"index": true
},
"status": {
"type": "byte",
"index": true
},
"createTime": {
"type": "long",
"index": true
},
"uid": {
"type": "long",
"index": true
},
"payment": {
"type": "keyword",
"index": true
},
"commentStatus": {
"type": "byte",
"index": true
},
"refundStatus": {
"type": "byte",
"index": true
}
}
}
}
}
3.觸發程式灌數據(也可以用bulk)
小結
問題雖小,但一定要追溯源頭,比如此次測試環境的不規範操作。後期如果有刪除索引的操作,應該先手動建立索引後,再灌數據,而不是直接讓其自動mapping建立索引,自動mapping建立的欄位類型,可能不是我們期望的。
專註Java高併發、分散式架構,更多技術乾貨分享與心得,請關註公眾號:Java架構社區