記一次ES查詢數據突然變爲空的問題

基本環境

  • 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架構社區
Java架構社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章