elasticsearch中索引的管理
索引管理
我們看到es讓開發一個新的應用變得簡單,不需要任何預先計劃和設定,不過要不了多久
你就會開始想要優化索引和搜尋過程,以便更好的適合您的特定用例,這些定製圍繞著索引和型別的方方面面
本章介紹管理索引和型別對映的API以及一些重要的設定
建立一個索引
- 簡單建立一個索引
PUT /test01
當我們這樣建立一個索引的時候,索引採用的是預設的配置,新的欄位通過動態對映的方面新增到型別對映
- 現在我們需要對建立這個索引的過程做更多的控制,我們想要這個索引有數量適中的主分片
並且我們在索引任何資料前,分析器和對映已經被建立好 - 為了達到這個目的我們需要手動建立索引,在請求體裡面傳入設定和型別對映,
{
"settings": { ... any settings ... },
"mappings": {
"type_one": { ... any mappings ... },
"type_two": { ... any mappings ... },
...
}
}
注意:我們之後可以使用索引模板來預配置開啟自動建立索引,這在索引日誌資料時尤其有用
你將日誌資料索引在一個以日期結尾的索引上,子夜時分,一個預配置的新索引將會自動建立
刪除一個索引
DELETE /my_index
- 也可以這樣刪除多個索引
DELETE /my_index,myindex2
DELETE /index_* - 刪除全部索引
DELETE /*
DELETE /_all
索引設定
- es提供了優化好的預設配置,除非你理解了這些配置的作用並且知道為什麼要去修改,否則不要隨意修改
- 下面是兩個比較重要的設定
number_of_shards: 每個索引的主分片數,預設值是1,這個配置在索引建立後不能修改
number_of_replicas: 每個主分片的副本數,預設值是1,對於活動的索引庫,這個配置可以隨時修改
例如,我們可已建立一個只有一個主分片,沒有副本的小索引
PUT /my_index
{ "settings": { "number_of_shards": 1, "number_of_replicas": 0 } }
然後我們可以利用update-index-settings API動態修改副本數,
PUT /my_index/_settings
將剛剛建立的my_index副本數量從0改為1
{
"number_of_replicas": 1
}
配置分析器
- 第三個重要的索引設定是analysis, 用來配置已存在的分析器或者針對你的索引建立新的自定義分析器
前面介紹了一些內建分析器,用來將全文字串轉換為適合搜尋的倒排索引
- standard分析器適用於全文欄位的預設分析器,對於大部分西方語系來說不錯
- standard分詞器,通過單詞邊界分割輸入的文字
- standard語彙單元過濾器,整理分詞器觸發的語彙單元
- lowercase語彙單元過濾器,轉換所有的語彙單元為小寫
- stop語彙單元過濾器,刪除停用詞和對搜尋相關性影響不大的常用詞,如a the and is
- 預設情況下,停用詞過濾器是被禁用的
如果需要啟動它,你可以通過建立一個基於standard分析器的自定義分析器並設定stopwords引數
可以給分析器提供一個停用詞列表,或者告知使用一個基於特定語義的停用詞列表
下面我們建立一個新的分析器,鍵es_std,並使用預定義的西班牙停用詞列表
{
"settings": {
"analysis": {
"analyzer": {
"es_std": {
"type": "standard",
"stopwords": "_spanish_"
}
}
}
}
}
es_std分析器不是全域性的,它僅僅存在於我們定義的spanish_docs索引中,
為了使用analyze API對它進行測試,我們必須使用特定的索引名spanish_docs
GET /spanish_docs/_analyze
{
"analyzer": "es_std",
"text": "El veloz zorro marrón"
}
簡化的結果已經顯示西班牙語停用詞El已被正確的移除
自定義分析器
- 雖然es帶有一些現成的分析器,但是es的強大之處在於你可以自己組合字串過濾器、分詞器、詞彙單元過濾器
來建立自定義的分析器 - 一個分析器包含三部分
- 字串過濾器
字串過濾器用來整理一個尚未被分詞的字串,例如我們的文字是Html格式的,標籤div或者p等需要清除掉
此時我們可以使用html清除 字元過濾器來移除所有的html標籤
一個分析器可以包含0個或多個字元過濾器 - 分詞器
一個分析器必須有且僅有一個分詞器,分詞器把字串分解成單個詞條或者詞彙單元,標準分析器裡面的標準分詞器
把一個字串按照單詞邊界分解成單個詞條,並且移除大部分的標點符號,當然也有其它不同行為的分詞器存在
例如關鍵詞分詞器完整的輸出接收到的同樣的字串,空格分詞器只根據空格拆分為本,
正則分詞器根據正則表示式來分割文字 - 詞彙單元過濾器
經過分詞後,詞單元流會按照順序經過詞彙單元過濾器,詞單元過濾器可以新增、修改、刪除詞單元
向lowercase和stop詞過濾器,但是es裡面還有很多詞單元過濾器,詞幹過濾器把詞單元遏制為詞幹
- 建立一個自定義分析器
和我們之前配置es_std分析器一樣,我們可以在analysis下配置字串過濾器、分詞器、詞彙單元過濾器
我們來建立一個自定義分析器:
- 使用html清除 字元過濾器來移除html部分
- 使用一個自定義的對映 字元過濾器來吧&替換為and
- 使用標準分詞器分詞
- 小寫詞條,使用小寫詞過濾器處理
- 使用自定義停止詞過濾器移除自定義的停止詞列表中包含的詞,
{
"settings": {
"analysis": {
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [
"&=> and "
]
}
},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": [
"the",
"a"
]
}
},
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [
"html_strip",
"&_to_and"
],
"tokenizer": "standard",
"filter": [
"lowercase",
"my_stopwords"
]
}
}
}
}
}
索引被建立以後,使用analyze API來測試這個新的分析器
GET /my_index/_analyze
{
"analyzer": "my_analyzer",
"text": "a the & ABD <p>12345</p>"
}
分析結果:
{
"tokens": [
{
"token": "and",
"start_offset": 6,
"end_offset": 7,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "abd",
"start_offset": 8,
"end_offset": 11,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "12345",
"start_offset": 15,
"end_offset": 20,
"type": "<NUM>",
"position": 4
}
]
}
可以看到效果,詞單元過濾器中的my_stopwords去掉了a和the詞條,字元過濾器中的&_to_and將&替換成了and
內建詞彙過濾器lowercase將ABC轉換成了abd,內建字元過濾器html_strip將html標籤直接去掉了
- 注意,這個分析器目前是沒有多大用處的,除非我們告訴es在哪裡用上它,
- 我們可以像下面這樣把該分析器用在text欄位上
PUT /my_index/_mapping
{
"properties": {
"title": {
"type": "text",
"analyzer": "my_analyzer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
然後我們使用analyze API介面測試一下我們新建的分析器如何
GET /my_index/_analyze/
{
"field": "title",
"text": "中國我愛你, & <p>the</p> aBB"
}
返回結果
{
"tokens": [
{
"token": "中國",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "我愛你",
"start_offset": 2,
"end_offset": 5,
"type": "CN_WORD",
"position": 1
},
{
"token": "愛你",
"start_offset": 3,
"end_offset": 5,
"type": "CN_WORD",
"position": 2
},
{
"token": "abb",
"start_offset": 20,
"end_offset": 23,
"type": "ENGLISH",
"position": 3
}
]
}
自定義分析器很強大啊!
對映
- 對映就像資料庫中的schema,描述了文件可能具有的欄位或者屬性,每個欄位的資料型別比如integer date bool text等
以及lucene是如何索引和儲存這些欄位的 - lucene如何處理文件
lucene中一個文件有簡單的鍵值對組成,當我們在Lucene中索引一個文件時,每個欄位的值都被新增到相關欄位的倒排索引中去
lucene也沒有對映的概念,對映是es將複雜的json文件對映成lucene需要的扁平化資料的方式
{
"name": {
"type": "text",
"analyzer": "whitespace"
}
}
name欄位的對映可以宣告該欄位是text型別,並且它的值被索引到name欄位的倒排索引之前
需要通過whitespace分詞器分析
根物件
對映的最高一層被稱為根物件,他可能包含下面幾項
- 一個properties節點列出了文件中可能包含的每個欄位的對映
- 各種元資料欄位例如:_id,_source
- 屬性:
type:欄位的資料型別例如:text、date
analyzer: 確定在索引和搜尋時,全文欄位使用的analyzer
index: 布林型別,索引還是不索引(注意:如果是字串需要跟欄位型別keyword配合使用)
{
"properties": {
"name": {
"type": "keyword",
"index": false
}
}
}
- 元資料_source欄位
在一個搜尋請求體裡,如果我們只想要_source中的指定欄位,可以這樣查詢
GET /us/_search
{
"query": {
"match": {
"tweet": "API"
}
},
"_source": ["date", "tweet"]
}
這些欄位值會從_source欄位提取和返回,而不是返回整個_source
注意:在es中對個別欄位設定儲存的方法總不是最優的,整個文件已經被儲存為_source欄位,
使用_source欄位提取你想要的欄位才是最好的
動態對映
- 當es遇到文件中以前未遇到的欄位時,他用dynamic mapping來確定欄位的資料型別,
並自動把新的欄位新增到型別對映中去
索引別名和零停機
- 前面提到的重建索引的問題就是必須更新應用中的索引名稱,索引別名就是用來解決這個問題的
索引別名就像一個快捷方式或者軟連線,可以指向一個或者多個索引,也可以給任何一個需要索引名的API來使用
- 在執行的叢集中可以無縫從一個索引切換到另一個索引
- 給多個索引分組
- 給索引的一個子集建立檢視
- 看一下在零停機下從舊索引切換到新索引
有兩種方式管理別名:_alias用於管理單個操作,_aliases用於執行多個原子操作
我們假設你有一個應用名叫my_index的索引,事實上my_index是指向真實索引的別名
真實索引包含一個版本號my_index_v1,my_index_v2 - 首先建立索引my_index_v1,然後將別名my_index指向它
PUT /my_index_v1
PUT /my_index_v1/_alias/my_index
建立索引my_index_v1,然後將索引別名my_index指向my_index_v1
可以檢測這個別名指向哪一個索引
GET //_alias/my_index
或者哪些別名指向這一個索引
GET /my_index_v1/_alias/
兩者都會返回同樣的結果
{
"my_index_v1": {
"aliases": {
"my_index": {}
}
}
}
然後我們決定修改索引中一個欄位的對映,當然我們不能修改現存的對映,所以我們必須重新索引資料
首先我們用新對映建立索引my_index_v2
/my_index_v2
{
"mappings": {
"properties": {
"tags": {
"type": "keyword",
"index": false
}
}
}
}
然後我們將資料從my_index_v1遷移到my_index_v2,一旦我們確定文件已經被正確的重新索引了,
我們就將別名指向新的索引,一個別名可以指向多個索引,所以我們在新增別名到新的索引時必須從舊的索引中移除掉
這個操作需要原子化,這意味著我們需要使用_aliases操作
POST /_aliases
{
"actions": [
{
"remove": {"index": "my_index_v1", "alias": "my_index"}
},
{
"add": {"index": "my_index_v2", "alias": "my_index"}
}
]
}
你的應用已經在零停機的情況下從舊索引遷移到了新索引了,即使你認為現在的索引已經設計的很完美了,
在生產環境中還是有可能需要做一些修改的
- 做好準備:在你的應用中使用別名而不是索引名,然後你就可以在任何時候重建索引
- 別名的開銷很小,應該廣泛使用