iT邦幫忙

2024 iThome 鐵人賽

DAY 0
0
自我挑戰組

重新開始 elasticsearch 系列 第 4

2024 鐵人賽 Day5: Index Mapping

  • 分享至 

  • xImage
  •  

因為 elasticsearch 要打很多字,寫文苦手如我決定縮寫它,所以會用 ES 代稱。

如果你沒有閱讀前面幾天的內容,在這裏先概念釐清一下,這邊說的 index,是名詞,是 es 的一個資料貯存單元的 namespace ;並不是在 RDB 中針對資料建立索引以加速搜尋的那個 create index,如果要用 RDB 中的概念來類比,index 比較像是 table,同一個 index 內會貯存 json 格式的資料,一筆 json 會稱為一個 Documents。

當你 create Index 的時候,基本上沒有發生太多事,ES 會把把預設的設定帶入 index,然後創建出來。如果想要知道預設的設定值,可以在還沒有寫入資料時執行:

PUT /my-index_new

GET /my-index_new

會得到以下類似的結果:

{
  "my-index_new": {
    "aliases": {},
    "mappings": {},
    "settings": {
      "index": {
        "routing": {
          "allocation": {
            "include": {
              "_tier_preference": "data_content"
            }
          }
        },
        "number_of_shards": "1",
        "provided_name": "my-index_new",
        "creation_date": "1726208147895",
        "number_of_replicas": "1",
        "uuid": "SqVg43F6TJqPoUhrFmxpfg",
        "version": {
          "created": "8512000"
        }
      }
    }
  }
}

ES 回傳的資訊是這個 index 的設定檔,可以看到除了 aliases 之外,還有 mappings、settings 等資訊,field 的設定會放在 mappings 內。設定檔的其他內容可以先跳過,之後有遇到會再說明。

那之前創建的 index 內已經有資料了,index 的設定會有什麼變化呢?

GET /my-index

執行以上 request,會得到以下內容(為了版面我把部分內容省略了):

{
  "my-index": {
    "aliases": {},
    "mappings": {
      "properties": {
        "description": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "id": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "title": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    },
    "settings": {
      ...略...
    }
  }
}

可以發現主要的差異會在 mappings 這個 filed。

mappings 是一個像是 schema 的東西,定義了某一個 field 的類別(type),這個 type 就定義了 es 會怎麼處裡然後貯存這個欄位,完整的 type list 可以參考 ES 官網

在上面的例子中,document 中的所有欄位都是 text type,text type 就是 es 會經過文字分析(text analysis)之後,可以對資料進行全文搜索的類別。除了 type 之外,每一個 field 都還有 fields 的設定,這個設定是 es 的 multi-field 設計,讓同一個 field 的資料可以以不同的方式被使用,上面的例子就是每一個欄位可以被全文搜索(full-text search),也可以被關鍵字搜索(keyword-search)。

multi-field 的設定語法說明:

...
	"<field_name>": {
          "type": "<type>",
          "fields": {
            "<multi_field_name>": {
              "type": "<multi_field_type>",
              <keyword>: <args>
            }
          }
        }
 ...

multi-field 的使用:

GET /my_index/_search
{
  "query": {
    "match": {
      "title.keyword": "Add a single document"
    }
  }
}

## 搜尋語法說明
# {
#   "query": {
#     "match": {
#       "<field_name>.<multi_field_name>": "<search keyword>"
#     }
#   }
# }

我們前一天從創建 index 到資料寫入的過程,其實完全沒有指定那一個 field 要用什麼 type,這些設定都是 es 自動偵測後產生的,這是 ES dynamic mapping 的功能,當你寫入的資料有 field 沒有被定義 type, ES 會動態、及時的調整 mapping 的內容。

但很多時候,其實我們會希望可以自訂 mapping 內各個 fields 的 type 來符合特定搜尋的方式。

所以當然你也可以自己定義你希望 field 的 type 是什麼,但這件需要在你創建 index 的時候進行,在 index 已經被創建的情況下,只能對現有的新增 field,不能對現有的 index mapping 做修改。

如果你真的需要更改 mapping,則需先創建想要的 index,再重新 index 原本的資料到新的 index 內,聽起來超級麻煩,還好 ES 提供了 reindex api 來做這件事。

假設我希望我的 mapping 是這樣的:

PUT /my-index2
{
  "mappings": {
    "properties": {
      "id":    { "type": "keyword" },
      "title":  { "type": "text" },
      "description":   { "type": "text" }
    }
  }
}

希望把原本在 my-index 的資料轉到 my-index2,就可以使用 reindex 的 api

POST _reindex
{
  "source": {
    "index": "my-index"
  },
  "dest": {
    "index": "my-index2"
  }
}

index mapping 的設計,在建構搜尋系統的時候一個相當需要認真考量的環節,針對挑選適合的 type 才能讓 ES 發揮它應有的功能。

明天是另外一個 ES 作為搜尋引擎很關鍵的設計:Text Analyzer。


上一篇
2024 鐵人賽 Day4: Start From Demo Code
下一篇
2024 鐵人賽 Day6: Text Analyzer I
系列文
重新開始 elasticsearch 29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言