Elasticsearch支持的基本類型
自定義 mapping
index
: 設置此字段能不能被查詢,就是決定要不要將這個字段放進倒排索引裡
analyzer
: 主要用在 text 類型的字段上,就是設定要使用哪種分詞器來建立索引
可以使用 /_analyze
測試分析器具體會將句子分詞成什麼樣子,它能幫助我們理解 Elasticsearch 索引內部發生了什麼
GET _analyze
{
"analyzer": "standard",
"text": "Text to analyze"
}
具體實例
mapping
PUT mytest
{
"mappings": {
"doc": {
"properties": {
"name": {
"type": "keyword",
"index": false
},
"uid": {
"type": "integer"
},
"nickname": {
"type": "text",
"analyzer": "standard"
}
}
}
}
}
搜索 uid 時,name 會一起被找出來
GET mytest/_search
{
"query": {
"term": {
"uid": 1
}
}
}
{
"uid": 1,
"name": "1-hello",
"nickname": "1-nickname"
}
搜索 name,會報 error
GET mytest/_search
{
"query": {
"term": {
"name": "1-hello"
}
}
}
"error": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [name] since it is not indexed."
}
更新 mapping
當首次創建一個 index 的時候,可以指定類型的 mapping,但假設後來想要增加一個新的映射字段,可以使用 /_mapping
把新的字段加進 mapping 映射裡
具體實例
在 mytest 映射中的 doc
類型增加一個新的名爲 tag
的 keyword
PUT mytest/_mapping/doc
{
"properties": {
"tag": {
"type": "keyword"
}
}
}
在 ES 中更新 mapping(新增一個字段)會產生的問題
雖然 ES 支持更新映射在 mapping 中新增字段,但是這樣會造成一個問題,就是舊的文檔並不會自動更新產生新的字段
假設舊文檔有 name、nickname
這兩個字段,並且已經插入了兩筆數據
{ "name": "Jackson", "nickname": "jack" }
{ "name": "Amy", "nickname": "a" }
此時插入一個新的字段 sex
,並且插入一筆新的數據
{ "name": "NewYork", "nickname": "new", "sex": 1 }
執行 "match_all": {}
查詢時,結果如下
由於 Jackson 和 Amy 並沒有 sex 這個字段,所以雖然執行 match_all 搜索時能被搜出來,但是搜索 "term": { "sex": 1 }
的話,就搜索不出來
{ "name": "Jackson", "nickname": "jack" }
{ "name": "Amy", "nickname": "a" }
{ "name": "NewYork", "nickname": "new", "sex": 1 }
我們希望的狀況是,增加一個新字段,舊文檔應該也要設置一個預設值,像是 sex=0,而不是整個字段消失,如此在查詢時邏輯才不會有問題
解決舊文檔沒有新字段這個問題主要有3種方法
新建一個 index,使用 scroll + bulk insert 將數據從舊的索引批量插入到新索引中
新建一個 index,使用 ES 提供的 reindex API 將數據從舊的索引 reindex 到新索引
需要使用 ES 的腳本 script,在 reindex 的請求裡定義舊文檔預設值的邏輯
POST _reindex
{
"source": {
"index": "mytest"
},
"dest": {
"index": "mytest2"
},
"script": {
"source": "if (ctx._source.new == null) {ctx._source.new = params.new}",
"params": {
"new": "good"
},
"lang": "painless"
}
}
使用 update_by_query 更新所有舊文檔,給他們加上新的字段