日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解ElasticSearch(八):索引管理

發布時間:2024/1/17 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解ElasticSearch(八):索引管理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

索引管理

1、創建一個索引

到目前為止, 我們已經通過索引一篇文檔創建了一個新的索引 。這個索引采用的是默認的配置,新的字段通過動態映射的方式被添加到類型映射。現在我們需要對這個建立索引的過程做更多的控制:我們想要確保這個索引有數量適中的主分片,并且在我們索引任何數據 之前 ,分析器和映射已經被建立好。

為了達到這個目的,我們需要手動創建索引,在請求體里面傳入設置或類型映射,如下所示:

PUT /my_index {"settings": { ... any settings ... },"mappings": {"type_one": { ... any mappings ... },"type_two": { ... any mappings ... },...} }

如果你想禁止自動創建索引,你 可以通過在 config/elasticsearch.yml 的每個節點下添加下面的配置:

action.auto_create_index: false

2、刪除一個索引

用以下的請求來 刪除索引:

DELETE /my_index

你也可以這樣刪除多個索引:

DELETE /index_one,index_two DELETE /index_*

你甚至可以這樣刪除 全部 索引:

DELETE /_all DELETE /*

3、索引設置

下面是兩個 最重要的設置:

number_of_shards

每個索引的主分片數,默認值是 5 。這個配置在索引創建后不能修改。

number_of_replicas

每個主分片的副本數,默認值是 1 。對于活動的索引庫,這個配置可以隨時修改。?
例如,我們可以創建只有 一個主分片,沒有副本的小索引:

PUT /my_temp_index {"settings": {"number_of_shards" : 1,"number_of_replicas" : 0} }

然后,我們可以用 update-index-settings API 動態修改副本數:

PUT /my_temp_index/_settings {"number_of_replicas": 1 }

4、配置分析器

第三個重要的索引設置是 analysis 部分, 用來配置已存在的分析器或針對你的索引創建新的自定義分析器。

在 分析與分析器 ,我們介紹了一些內置的 分析器,用于將全文字符串轉換為適合搜索的倒排索引。

standard 分析器是用于全文字段的默認分析器, 對于大部分西方語系來說是一個不錯的選擇。 它包括了以下幾點:

  • standard 分詞器,通過單詞邊界分割輸入的文本。
  • standard 語匯單元過濾器,目的是整理分詞器觸發的語匯單元(但是目前什么都沒做)。
  • lowercase 語匯單元過濾器,轉換所有的語匯單元為小寫。
  • stop 語匯單元過濾器,刪除停用詞–對搜索相關性影響不大的常用詞,如 a , the , and , is 。

默認情況下,停用詞過濾器是被禁用的。如需啟用它,你可以通過創建一個基于 standard 分析器的自定義分析器并設置 stopwords 參數。 可以給分析器提供一個停用詞列表,或者告知使用一個基于特定語言的預定義停用詞列表。

在下面的例子中,我們創建了一個新的分析器,叫做 es_std , 并使用預定義的 西班牙語停用詞列表:

PUT /spanish_docs {"settings": {"analysis": {"analyzer": {"es_std": {"type": "standard","stopwords": "_spanish_"}}}} }

es_std 分析器不是全局的–它僅僅存在于我們定義的 spanish_docs 索引中。 為了使用 analyze API來對它進行測試,我們必須使用特定的索引名:

GET /spanish_docs/_analyze?analyzer=es_std El veloz zorro marrón

簡化的結果顯示西班牙語停用詞 El 已被正確的移除:

{"tokens" : [{ "token" : "veloz", "position" : 2 },{ "token" : "zorro", "position" : 3 },{ "token" : "marrón", "position" : 4 }] }

5、自定義分析器

雖然Elasticsearch帶有一些現成的分析器,然而在分析器上Elasticsearch真正的強大之處在于,你可以通過在一個適合你的特定數據的設置之中組合字符過濾器、分詞器、詞匯單元過濾器來創建自定義的分析器。

在 分析與分析器 我們說過,一個 分析器 就是在一個包里面組合了三種函數的一個包裝器, 三種函數按照順序被執行:

字符過濾器?
字符過濾器 用來 整理 一個尚未被分詞的字符串。例如,如果我們的文本是HTML格式的,它會包含像

或者

這樣的HTML標簽,這些標簽是我們不想索引的。我們可以使用 html清除 字符過濾器 來移除掉所有的HTML標簽,并且像把 á 轉換為相對應的Unicode字符 á 這樣,轉換HTML實體。

?

一個分析器可能有0個或者多個字符過濾器。

分詞器?
一個分析器 必須 有一個唯一的分詞器。 分詞器把字符串分解成單個詞條或者詞匯單元。 標準 分析器里使用的 標準 分詞器 把一個字符串根據單詞邊界分解成單個詞條,并且移除掉大部分的標點符號,然而還有其他不同行為的分詞器存在。

例如, 關鍵詞 分詞器 完整地輸出 接收到的同樣的字符串,并不做任何分詞。 空格 分詞器 只根據空格分割文本 。 正則 分詞器 根據匹配正則表達式來分割文本 。

詞單元過濾器?
經過分詞,作為結果的 詞單元流 會按照指定的順序通過指定的詞單元過濾器 。

詞單元過濾器可以修改、添加或者移除詞單元。我們已經提到過 lowercase 和 stop 詞過濾器 ,但是在 Elasticsearch 里面還有很多可供選擇的詞單元過濾器。 詞干過濾器 把單詞 遏制 為 詞干。 ascii_folding 過濾器移除變音符,把一個像 “très” 這樣的詞轉換為 “tres” 。 ngram 和 edge_ngram 詞單元過濾器 可以產生 適合用于部分匹配或者自動補全的詞單元。

在 深入搜索 ,我們討論了在哪里使用,以及怎樣使用分詞器和過濾器。但是首先,我們需要解釋一下怎樣創建自定義的分析器。

創建一個自定義分析器?
和我們之前配置 es_std 分析器一樣,我們可以在 analysis 下的相應位置設置字符過濾器、分詞器和詞單元過濾器:

PUT /my_index {"settings": {"analysis": {"char_filter": { ... custom character filters ... },"tokenizer": { ... custom tokenizers ... },"filter": { ... custom token filters ... },"analyzer": { ... custom analyzers ... }}} }

作為示范,讓我們一起來創建一個自定義分析器吧,這個分析器可以做到下面的這些事:

  • 1、使用 html清除 字符過濾器移除HTML部分。
  • 2、使用一個自定義的 映射 字符過濾器把 & 替換為 ” 和 ” :
"char_filter": {"&_to_and": {"type": "mapping","mappings": [ "&=> and "]} }
  • 3、使用 標準 分詞器分詞。
  • 4、小寫詞條,使用 小寫 詞過濾器處理。
  • 5、使用自定義 停止 詞過濾器移除自定義的停止詞列表中包含的詞:
"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" ]} }

匯總起來,完整的 創建索引 請求 看起來應該像這樣:

PUT /my_index {"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 The quick & brown fox

下面的縮略結果展示出我們的分析器正在正確地運行:

{"tokens" : [{ "token" : "quick", "position" : 2 },{ "token" : "and", "position" : 3 },{ "token" : "brown", "position" : 4 },{ "token" : "fox", "position" : 5 }] }

這個分析器現在是沒有多大用處的,除非我們告訴 Elasticsearch在哪里用上它。我們可以像下面這樣把這個分析器應用在一個 string 字段上:

PUT /my_index/_mapping/my_type {"properties": {"title": {"type": "string","analyzer": "my_analyzer"}} }

6、類型和映射

類型 在 Elasticsearch 中表示一類相似的文檔。 類型由 名稱 —比如 user 或 blogpost —和 映射 組成。

映射, 就像數據庫中的 schema ,描述了文檔可能具有的字段或 屬性 、 每個字段的數據類型—比如 string, integer 或 date —以及Lucene是如何索引和存儲這些字段的。

類型可以很好的抽象劃分相似但不相同的數據。但由于 Lucene 的處理方式,類型的使用有些限制。

6.1、Lucene 如何處理文檔

在 Lucene 中,一個文檔由一組簡單的鍵值對組成。 每個字段都可以有多個值,但至少要有一個值。 類似的,一個字符串可以通過分析過程轉化為多個值。Lucene 不關心這些值是字符串、數字或日期–所有的值都被當做 不透明字節 。

當我們在 Lucene 中索引一個文檔時,每個字段的值都被添加到相關字段的倒排索引中。你也可以將未處理的原始數據 存儲 起來,以便這些原始數據在之后也可以被檢索到。

6.2、類型是如何實現的

Elasticsearch 類型是 以 Lucene 處理文檔的這個方式為基礎來實現的。一個索引可以有多個類型,這些類型的文檔可以存儲在相同的索引中。

Lucene 沒有文檔類型的概念,每個文檔的類型名被存儲在一個叫 _type 的元數據字段上。 當我們要檢索某個類型的文檔時, Elasticsearch 通過在 _type 字段上使用過濾器限制只返回這個類型的文檔。

Lucene 也沒有映射的概念。 映射是 Elasticsearch 將復雜 JSON 文檔 映射 成 Lucene 需要的扁平化數據的方式。

例如,在 user 類型中, name 字段的映射可以聲明這個字段是 string 類型,并且它的值被索引到名叫 name 的倒排索引之前,需要通過 whitespace 分詞器分析:

"name": {"type": "string","analyzer": "whitespace" }

6.3、避免類型陷阱

這導致了一個有趣的思想實驗: 如果有兩個不同的類型,每個類型都有同名的字段,但映射不同(例如:一個是字符串一個是數字),將會出現什么情況?

簡單回答是,Elasticsearch 不會允許你定義這個映射。當你配置這個映射時,將會出現異常。

詳細回答是,每個 Lucene 索引中的所有字段都包含一個單一的、扁平的模式。一個特定字段可以映射成 string 類型也可以是 number 類型,但是不能兩者兼具。因為類型是 Elasticsearch 添加的 優于 Lucene 的額外機制(以元數據 _type 字段的形式),在 Elasticsearch 中的所有類型最終都共享相同的映射。

以 data 索引中兩種類型的映射為例:

{"data": {"mappings": {"people": {"properties": {"name": {"type": "string",},"address": {"type": "string"}}},"transactions": {"properties": {"timestamp": {"type": "date","format": "strict_date_optional_time"},"message": {"type": "string"}}}}} }

每個類型定義兩個字段 (分別是?"name"/"address"?和?"timestamp"/"message"?)。它們看起來是相互獨立的,但在后臺 Lucene 將創建一個映射,如:

{"data": {"mappings": {"_type": {"type": "string","index": "not_analyzed"},"name": {"type": "string"}"address": {"type": "string"}"timestamp": {"type": "long"}"message": {"type": "string"}}} }

注: 這不是真實有效的映射語法,只是用于演示

對于整個索引,映射在本質上被 扁平化 成一個單一的、全局的模式。這就是為什么兩個類型不能定義沖突的字段:當映射被扁平化時,Lucene 不知道如何去處理。

6.4、類型結論

那么,這個討論的結論是什么?技術上講,多個類型可以在相同的索引中存在,只要它們的字段不沖突(要么因為字段是互為獨占模式,要么因為它們共享相同的字段)。

重要的一點是: 類型可以很好的區分同一個集合中的不同細分。在不同的細分中數據的整體模式是相同的(或相似的)。

類型不適合 完全不同類型的數據 。如果兩個類型的字段集是互不相同的,這就意味著索引中將有一半的數據是空的(字段將是 稀疏的 ),最終將導致性能問題。在這種情況下,最好是使用兩個單獨的索引。

總結:

  • 正確: 將 kitchen 和 lawn-care 類型放在 products 索引中, 因為這兩種類型基本上是相同的模式
  • 錯誤: 將 products 和 logs 類型放在 data 索引中, 因為這兩種類型互不相同。應該將它們放在不同的索引中。

7、根對象

映射的最高一層被稱為 根對象 ,它可能包含下面幾項:

  • 一個 properties 節點,列出了文檔中可能包含的每個字段的映射?
    各種元數據字段,它們都以一個下劃線開頭,例如 _type 、 _id 和 _source
  • 設置項,控制如何動態處理新的字段,例如 analyzer 、 dynamic_date_formats 和 dynamic_templates
  • 其他設置,可以同時應用在根對象和其他 object 類型的字段上,例如 enabled 、 dynamic 和 include_in_all

7.1、屬性

我們已經在 核心簡單域類型 和 復雜核心域類型 章節中介紹過文檔字段和屬性的三個 最重要的設置:

  • type?
    字段的數據類型,例如 string 或 date
  • index?
    字段是否應當被當成全文來搜索( analyzed ),或被當成一個準確的值( not_analyzed ),還是完全不可被搜索( no )
  • analyzer?
    確定在索引和搜索時全文字段使用的 analyzer

我們將在本書的后續部分討論其他字段類型,例如 ip 、 geo_point 和 geo_shape 。

7.2、元數據: _source 字段

默認地,Elasticsearch 在 _source 字段存儲代表文檔體的JSON字符串。和所有被存儲的字段一樣, _source 字段在被寫入磁盤之前先會被壓縮。

這個字段的存儲幾乎總是我們想要的,因為它意味著下面的這些:

  • 搜索結果包括了整個可用的文檔——不需要額外的從另一個的數據倉庫來取文檔。
  • 如果沒有 _source 字段,部分 update 請求不會生效。
  • 當你的映射改變時,你需要重新索引你的數據,有了_source字段你可以直接從Elasticsearch這樣做,而不必從另一個(通常是速度更慢的)數據倉庫取回你的所有文檔。
  • 當你不需要看到整個文檔時,單個字段可以從 _source 字段提取和通過 get 或者 search 請求返回。
  • 調試查詢語句更加簡單,因為你可以直接看到每個文檔包括什么,而不是從一列id猜測它們的內容。

然而,存儲 _source 字段的確要使用磁盤空間。如果上面的原因對你來說沒有一個是重要的,你可以用下面的映射禁用 _source 字段:

PUT /my_index {"mappings": {"my_type": {"_source": {"enabled": false}}} }

在一個搜索請求里,你可以通過在請求體中指定 _source 參數,來達到只獲取特定的字段的效果:

GET /_search {"query": { "match_all": {}},"_source": [ "title", "created" ] }

這些字段的值會從 _source 字段被提取和返回,而不是返回整個 _source 。

7.3、元數據: _all 字段

在 輕量 搜索 中,我們介紹了 _all 字段:一個把其它字段值 當作一個大字符串來索引的特殊字段。 query_string 查詢子句(搜索 ?q=john )在沒有指定字段時默認使用 _all 字段。

_all 字段在新應用的探索階段,當你還不清楚文檔的最終結構時是比較有用的。你可以使用這個字段來做任何查詢,并且有很大可能找到需要的文檔:

GET /_search {"match": {"_all": "john smith marketing"} }

隨著應用的發展,搜索需求變得更加明確,你會發現自己越來越少使用 _all 字段。 _all 字段是搜索的應急之策。通過查詢指定字段,你的查詢更加靈活、強大,你也可以對相關性最高的搜索結果進行更細粒度的控制。如果你不再需要 _all 字段,你可以通過下面的映射來禁用:

PUT /my_index/_mapping/my_type {"my_type": {"_all": { "enabled": false }} }

通過 include_in_all 設置來逐個控制字段是否要包含在 _all 字段中,默認值是 true。在一個對象(或根對象)上設置include_in_all 可以修改這個對象中的所有字段的默認行為。

你可能想要保留 _all 字段作為一個只包含某些特定字段的全文字段,例如只包含 title,overview,summary 和 tags。 相對于完全禁用_all 字段,你可以為所有字段默認禁用 include_in_all 選項,僅在你選擇的字段上啟用:

PUT /my_index/my_type/_mapping {"my_type": {"include_in_all": false,"properties": {"title": {"type": "string","include_in_all": true},...}} }

記住,_all 字段僅僅是一個 經過分詞的 string 字段。它使用默認分詞器來分析它的值,不管這個值原本所在字段指定的分詞器。就像所有 string 字段,你可以配置 _all 字段使用的分詞器:

PUT /my_index/my_type/_mapping {"my_type": {"_all": { "analyzer": "whitespace" }} }

7.4、元數據:文檔標識

文檔標識與四個元數據字段 相關:

_id?
文檔的 ID 字符串?
_type?
文檔的類型名?
_index?
文檔所在的索引?
_uid?
_type 和 _id 連接在一起構造成 type#id?
默認情況下, _uid 字段是被存儲(可取回)和索引(可搜索)的。 _type 字段被索引但是沒有存儲, _id 和 _index 字段則既沒有被索引也沒有被存儲,這意味著它們并不是真實存在的。

盡管如此,你仍然可以像真實字段一樣查詢 _id 字段。Elasticsearch 使用 _uid 字段來派生出 _id 。 雖然你可以修改這些字段的 index 和 store 設置,但是基本上不需要這么做。

8、動態映射

當 Elasticsearch 遇到文檔中以前 未遇到的字段,它用 dynamic mapping 來確定字段的數據類型并自動把新的字段添加到類型映射。

有時這是想要的行為有時又不希望這樣。通常沒有人知道以后會有什么新字段加到文檔,但是又希望這些字段被自動的索引。也許你只想忽略它們。如果Elasticsearch是作為重要的數據存儲,可能就會期望遇到新字段就會拋出異常,這樣能及時發現問題。

幸運的是可以用 dynamic 配置來控制這種行為 ,可接受的選項如下:

true?
動態添加新的字段–缺省?
false?
忽略新的字段?
strict?
如果遇到新字段拋出異常?
配置參數 dynamic 可以用在根 object 或任何 object 類型的字段上。你可以將 dynamic 的默認值設置為 strict , 而只在指定的內部對象中開啟它, 例如:

PUT /my_index {"mappings": {"my_type": {"dynamic": "strict", "properties": {"title": { "type": "string"},"stash": {"type": "object","dynamic": true }}}} }

使用上述動態映射, 你可以給 stash 對象添加新的可檢索的字段:

PUT /my_index/my_type/1 {"title": "This doc adds a new field","stash": { "new_field": "Success!" } }

但是對根節點對象 my_type 進行同樣的操作會失敗:

PUT /my_index/my_type/1 {"title": "This throws a StrictDynamicMappingException","new_field": "Fail!" }

9、缺省映射

通常,一個索引中的所有類型共享相同的字段和設置。?default?映射更加方便地指定通用設置,而不是每次創建新類型時都要重復設置。?default?映射是新類型的模板。在設置?default?映射之后創建的所有類型都將應用這些缺省的設置,除非類型在自己的映射中明確覆蓋這些設置。

例如,我們可以使用?default?映射為所有的類型禁用 _all 字段, 而只在 blog 類型啟用:

PUT /my_index {"mappings": {"_default_": {"_all": { "enabled": false }},"blog": {"_all": { "enabled": true }}} }

default?映射也是一個指定索引 dynamic templates 的好方法。

10、重新索引你的數據

盡管可以增加新的類型到索引中,或者增加新的字段到類型中,但是不能添加新的分析器或者對現有的字段做改動。 如果你那么做的話,結果就是那些已經被索引的數據就不正確, 搜索也不能正常工作。

對現有數據的這類改變最簡單的辦法就是重新索引:用新的設置創建新的索引并把文檔從舊的索引復制到新的索引。

字段 _source 的一個優點是在Elasticsearch中已經有整個文檔。你不必從源數據中重建索引,而且那樣通常比較慢。

為了有效的重新索引所有在舊的索引中的文檔,用 scroll 從舊的索引檢索批量文檔 , 然后用 bulk API 把文檔推送到新的索引中。

從Elasticsearch v2.3.0開始, Reindex API 被引入。它能夠對文檔重建索引而不需要任何插件或外部工具。

批量重新索引

同時并行運行多個重建索引任務,但是你顯然不希望結果有重疊。正確的做法是按日期或者時間 這樣的字段作為過濾條件把大的重建索引分成小的任務:

GET /old_index/_search?scroll=1m {"query": {"range": {"date": {"gte": "2014-01-01","lt": "2014-02-01"}}},"sort": ["_doc"],"size": 1000 }

如果舊的索引持續會有變化,你希望新的索引中也包括那些新加的文檔。那就可以對新加的文檔做重新索引, 但還是要用日期類字段過濾來匹配那些新加的文檔。

11、索引別名和零停機

在前面提到的,重建索引的問題是必須更新應用中的索引名稱。 索引別名就是用來解決這個問題的!

索引 別名 就像一個快捷方式或軟連接,可以指向一個或多個索引,也可以給任何一個需要索引名的API來使用。別名 帶給我們極大的靈活性,允許我們做下面這些:

  • 在運行的集群中可以無縫的從一個索引切換到另一個索引
  • 給多個索引分組 (例如, last_three_months)
  • 給索引的一個子集創建 視圖

在后面我們會討論更多關于別名的使用。現在,我們將解釋怎樣使用別名在零停機下從舊索引切換到新索引。

有兩種方式管理別名: _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

你可以檢測這個別名指向哪一個索引:

GET /*/_alias/my_index

或哪些別名指向這個索引:

GET /my_index_v1/_alias/*

兩者都會返回下面的結果:

{"my_index_v1" : {"aliases" : {"my_index" : { }}} }

然后,我們決定修改索引中一個字段的映射。當然,我們不能修改現存的映射,所以我們必須重新索引數據。 首先, 我們用新映射創建索引 my_index_v2 :

PUT /my_index_v2 {"mappings": {"my_type": {"properties": {"tags": {"type": "string","index": "not_analyzed"}}}} }

然后我們將數據從 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" }}] }

你的應用已經在零停機的情況下從舊索引遷移到新索引了。

總結

以上是生活随笔為你收集整理的深入理解ElasticSearch(八):索引管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。