elasticsearch索引和映射
目錄
- 1. elasticsearch如何實現搜索
- 1.1 搜索實例
- 1.2 es中數據的類型
- 1.3 倒排索引
- 1.4 分析與分析器
- 1.4.1 什么是分析器
- 1.4.2 內置分析器種類
- 1.4.3 分析行為(開篇實例解答)
- 1.4.4 測試分析器
- 1.4.5 指定分析器
- 1.5 映射
- 1.5.1 簡單核心域類型
- 1.5.2 復雜核心域類型
- 2. 索引
- 2.1 什么是索引
- 2.2 創建一個默認配置的索引
- 2.3 索引的設置(settings部分)
- 2.4 索引的映射配置(mappings部分)
- 2.4.1 映射寫法
- 2.4.2 類型
- 2.4.3 根對象
- 2.4.4 動態映射
- 2.4.5 自定義動態映射
- 2.4.6 缺省映射
- 2.5 索引的管理
- 2.5.1 創建索引
- 2.5.2 查看索引
- 2.5.3 刪除索引
- 2.5.4 重構索引
1. elasticsearch如何實現搜索
我們使用sql數據庫的時候,要先創建數據庫,然后創建表,之后才可以將數據存入到表中,這個表規定了數據的構成結構。雖然elasticsearch是一個無模式的搜索引擎并且可以自動匹配數據的結構(ES 會盡量根據 JSON 源數據的基礎類型猜測你想要的字段類型映射),但是我們認為人為定義和控制數據結構是更好的方式。所以我們有必要學習如何創建索引和如何創建映射。
1.1 搜索實例
在mysql中我們查詢created_at = '2014-09-15'那么該created_at字段只有是2014-09-15和不是兩種情況,但是在elsaticsearch中則很有趣,看下下面的例子
索引中有12條推文,其中只有一條包含日期 2014-09-15 ,但是看一看下面查詢命中的 總數 (total):
GET /_search?q=2014 # 12 results GET /_search?q=2014-09-15 # 12 results ! GET /_search?q=date:2014-09-15 # 1 result GET /_search?q=date:2014 # 0 results !分析:
第一個和第二個搜索是全文搜索,起作用的是 _all字段 ,這里都返回了12條推文,但是我們提到了只有一條包含了日期 2014-09-15,為什么12條數據都能匹配?
第三和第四條數據時在 data字段 搜索,不難理解,第三條數據一條命中,第四條只是個年份,不可能有匹配項。
為什么會出現上面的結果呢,全文搜索好像有點不一般啊,推測起來,這可能是數據在 _all 字段與 date 字段的索引方式不同。帶著這個疑問我們一起分析下。
可以查看下索引的類型映射
GET /gb/_mapping/tweet結果如下
{"gb": {"mappings": {"tweet": {"properties": {"date": {"type": "date","format": "strict_date_optional_time||epoch_millis"},"name": {"type": "string"},"tweet": {"type": "string"},"user_id": {"type": "long"}}}}} }盡管我們沒有定義該索引的映射,但是es動態為我們產生了一個映射,這個響應告訴我們 date 字段被認為是 date 類型的。由于 _all 是默認字段,所以沒有提及它。但是我們知道 _all 字段是 string 類型的。所以 date 字段和 string 字段 索引方式不同,數據類型不同,因此搜索結果也不一樣,但這只是表象,深層次原因呢?
1.2 es中數據的類型
Elasticsearch 中的數據可以概括的分為兩類:『精確值』和 『全文』。
?『精確值』 如它們聽起來那樣精確。例如日期或者用戶 ID,但字符串也可以表示精確值,例如用戶名或郵箱地址。對于精確值來講,Foo 和 foo 是不同的,2014 和 2014-09-15 也是不同的。
精確值很容易查詢。結果是二進制的:要么匹配查詢,要么不匹配。這種查詢很容易用 SQL 表示:
WHERE name = "John Smith"AND user_id = 2AND date > "2014-09-15"?『全文』 是指文本數據(通常以人類容易識別的語言書寫),例如一個推文的內容或一封郵件的內容。
查詢全文數據要微妙的多。我們問的不只是“這個文檔匹配查詢嗎”,而是“該文檔匹配查詢的程度有多大?”。
我們很少對全文類型的域做精確匹配。相反,我們希望在文本類型的域中搜索。不僅如此,我們還希望搜索能夠理解我們的 意圖 :
- 搜索 UK ,會返回包含 United Kindom 的文檔。
- 搜索 jump ,會匹配 jumped , jumps , jumping ,甚至是 leap 。
- 搜索 johnny walker 會匹配 Johnnie Walker , johnnie depp 應該匹配 Johnny Depp 。
- fox news hunting 應該返回福克斯新聞( Foxs News )中關于狩獵的故事,同時, fox hunting news 應該返回關于獵狐的故事。
es是如何做到以上的想法的呢?
Elasticsearch 首先會 分析文檔,之后根據結果創建 倒排索引 ,接下來一起討論分析過程和倒排索引
1.3 倒排索引
一個倒排索引由文檔中所有不重復詞的列表構成,對于其中每個詞,有一個包含它的文檔列表。
例如,假設我們有兩個文檔,每個文檔的 content 域包含如下內容:
The quick brown fox jumped over the lazy dog Quick brown foxes leap over lazy dogs in summer為了創建倒排索引,我們首先將每個文檔的 content 域拆分成單獨的 詞(我們稱它為 詞條 或 tokens ),創建一個包含所有不重復詞條的排序列表,然后列出每個詞條出現在哪個文檔。結果如下所示:
Term Doc_1 Doc_2 ------------------------- Quick | | X The | X | brown | X | X dog | X | dogs | | X fox | X | foxes | | X in | | X jumped | X | lazy | X | X leap | | X over | X | X quick | X | summer | | X the | X | ------------------------現在,如果我們想搜索 quick brown ,我們只需要查找包含每個詞條的文檔:
Term Doc_1 Doc_2 ------------------------- brown | X | X quick | X | ------------------------ Total | 2 | 1兩個文檔都匹配,但是第一個文檔比第二個匹配度更高。如果我們使用僅計算匹配詞條數量的簡單 相似性算法 ,那么,我們可以說,對于我們查詢的相關性來講,第一個文檔比第二個文檔更佳。
但是,我們目前的倒排索引有一些問題:
- Quick 和 quick 以獨立的詞條出現,然而用戶可能認為它們是相同的詞。
- fox 和 foxes 非常相似, 就像 dog 和 dogs ;他們有相同的詞根。
- jumped 和 leap, 盡管沒有相同的詞根,但他們的意思很相近。他們是同義詞。
使用前面的索引搜索 +Quick +fox 不會得到任何匹配文檔。(記住,+ 前綴表明這個詞必須存在。)只有同時出現 Quick 和 fox 的文檔才滿足這個查詢條件,但是第一個文檔包含 quick fox ,第二個文檔包含 Quick foxes 。
我們的用戶可以合理的期望兩個文檔與查詢匹配。我們可以做的更好。
如果我們將詞條規范為標準模式,那么我們可以找到與用戶搜索的詞條不完全一致,但具有足夠相關性的文檔。例如:
- Quick 可以小寫化為 quick 。
- foxes 可以 詞干提取 --變為詞根的格式-- 為 fox 。類似的, dogs 可以為提取為 dog 。
- jumped 和 leap 是同義詞,可以索引為相同的單詞 jump 。
現在索引看上去像這樣:
這還遠遠不夠。我們搜索 +Quick +fox 仍然 會失敗,因為在我們的索引中,已經沒有 Quick 了。但是,如果我們對搜索的字符串使用與 content 域相同的標準化規則,查詢字符串就會變成查詢 +quick +fox ,這樣兩個文檔都會匹配!
注意:這非常重要。我們要用相同標準處理兩部分的數據 查詢字符串 和 索引文本 ,你只能搜索在索引中出現的詞條,所以索引文本和查詢字符串必須標準化為相同的格式。
1.4 分析與分析器
1.4.1 什么是分析器
首先,將一塊文本分成適合于倒排索引的獨立的 詞條 ,
之后,將這些詞條統一化為標準格式以提高它們的“可搜索性”,或者 recall
分析器執行上面的工作。 分析器 實際上是將三個功能封裝到了一個包里:
- 字符過濾器
首先,字符串按順序通過每個 字符過濾器 。字符過濾器 用來 整理 一個尚未被分詞的字符串。例如,如果我們的文本是HTML格式的,它會包含像 <p> 或者 <div> 這樣的HTML標簽,這些標簽是我們不想索引的。我們可以使用 html清除 字符過濾器 來移除掉所有的HTML標簽,并且像把 Á 轉換為相對應的Unicode字符 á 這樣,轉換HTML實體。
一個分析器可能有0個或者多個字符過濾器。
- 分詞器
其次,字符串被 分詞器 分為單個的詞條。 分詞器把字符串分解成單個詞條或者詞匯單元。 標準 分析器 把一個字符串根據單詞邊界分解成單個詞條,并且移除掉大部分的標點符號,然而還有其他不同行為的分詞器存在。
例如, 關鍵詞 分詞器 完整地輸出 接收到的同樣的字符串,并不做任何分詞。 空格 分詞器 只根據空格分割文本 。 正則 分詞器 根據匹配正則表達式來分割文本 。
一個分析器 必須 有一個唯一的分詞器。
- 詞單元過濾器
最后,詞條按順序通過每個 token 過濾器 。這個過程可能會改變詞條(例如,小寫化 Quick ),刪除詞條(例如, 像 a,and,the 等無用詞),或者增加詞條(例如,像 jump 和 leap 這種同義詞)。
Elasticsearch提供了開箱即用的字符過濾器、分詞器和詞單元過濾器。 這些可以組合起來形成自定義的分析器以用于不同的目的。
1.4.2 內置分析器種類
但是, Elasticsearch還附帶了可以直接使用的預包裝的分析器。 接下來我們會列出最重要的分析器。為了證明它們的差異,我們看看每個分析器會從下面的字符串得到哪些詞條:
"Set the shape to semi-transparent by calling set_trans(5)"- 標準分析器
標準分析器是Elasticsearch默認使用的分析器。它是分析各種語言文本最常用的選擇。它根據 Unicode 聯盟 定義的 單詞邊界 劃分文本。刪除絕大部分標點。最后,將詞條小寫。它會產生
set, the, shape, to, semi, transparent, by, calling, set_trans, 5- 簡單分析器
簡單分析器在任何不是字母的地方分隔文本,將詞條小寫。它會產生
set, the, shape, to, semi, transparent, by, calling, set, trans- 空格分析器
空格分析器在空格的地方劃分文本。它會產生
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)- 語言分析器
特定語言分析器可用于 很多語言。它們可以考慮指定語言的特點。例如, 英語 分析器附帶了一組英語無用詞(常用單詞,例如 and 或者 the ,它們對相關性沒有多少影響),它們會被刪除。 由于理解英語語法的規則,這個分詞器可以提取英語單詞的 詞干 。
英語 分詞器會產生下面的詞條:
set, shape, semi, transpar, call, set_tran, 5注意看 transparent、 calling 和 set_trans 已經變為詞根格式。
1.4.3 分析行為(開篇實例解答)
當我們 索引 一個文檔,它的全文域被分析成詞條以用來創建倒排索引。 但是,當我們在全文域 搜索 的時候,我們需要將查詢字符串通過 相同的分析過程 ,以保證我們搜索的詞條格式與索引中的詞條格式一致。
全文查詢,理解每個域是如何定義的,因此它們可以做 正確的事:
- 當你查詢一個 全文 域時, 會對查詢字符串應用相同的分析器,以產生正確的搜索詞條列表。
- 當你查詢一個 精確值 域時,不會分析查詢字符串, 而是搜索你指定的精確值。
現在你可以理解在 開始章節 的查詢為什么返回那樣的結果:
- date 域包含一個精確值:單獨的詞條 2014-09-15。
- _all 域是一個全文域,所以分詞進程將日期(2014-09-15)轉化為三個詞條: 2014, 09, 和 15。
當我們在 _all 域查詢 2014,它匹配所有的12條推文,因為它們都含有 2014 :
當我們在 _all 域查詢 2014-09-15,它首先分析查詢字符串,產生匹配 2014, 09, 或 15 中 任意 詞條的查詢。這也會匹配所有12條推文,因為它們都含有 2014 :
GET /_search?q=2014-09-15 # 12 results !當我們在 date 域查詢 2014-09-15,它尋找 精確 日期,只找到一個推文:
GET /_search?q=date:2014-09-15 # 1 result當我們在 date 域查詢 2014,它找不到任何文檔,因為沒有文檔含有這個精確日志:
GET /_search?q=date:2014 # 0 results !1.4.4 測試分析器
可以使用 analyze API 來看文本是如何被分析的。在消息體里,指定分析器和要分析的文本:
GET /_analyze {"analyzer": "standard","text": "Text to analyze" }結果
{"tokens": [{"token": "text","start_offset": 0,"end_offset": 4,"type": "<ALPHANUM>","position": 1},{"token": "to","start_offset": 5,"end_offset": 7,"type": "<ALPHANUM>","position": 2},{"token": "analyze","start_offset": 8,"end_offset": 15,"type": "<ALPHANUM>","position": 3}] }token 是實際存儲到索引中的詞條。 position 指明詞條在原始文本中出現的位置。 start_offset 和 end_offset 指明字符在原始字符串中的位置。
1.4.5 指定分析器
當Elasticsearch在你的文檔中檢測到一個新的字符串域 ,它會自動設置其為一個全文 字符串 域,使用 標準 分析器對它進行分析。
你不希望總是這樣。可能你想使用一個不同的分析器,適用于你的數據使用的語言。有時候你想要一個字符串域就是一個字符串域--不使用分析,直接索引你傳入的精確值,例如用戶ID或者一個內部的狀態域或標簽。
要做到指定數據類型和指定鎖使用的分析器,我們必須手動指定這些域的映射。關于如何配置和指定分析器,將在索引的構建中講解
1.5 映射
上面已經知道了倒排索引,分析和分析器內容,那么如何才能夠是es實現以上特性呢,就是編寫映射規則,我們配置映射的時候會規定數據的類型、是否使用分析器、使用何種分析器等內容。
為了能夠將時間域視為時間,數字域視為數字,字符串域視為全文或精確值字符串, Elasticsearch 需要知道每個域中數據的類型。映射定義了類型中的域,每個域的數據類型,以及Elasticsearch如何處理這些域。映射也用于配置與類型有關的元數據。我們這里先了解下映射的概念,下一章節會講解如何編寫映射。
1.5.1 簡單核心域類型
簡單域類型:
- 字符串: string
- 整數 : byte, short, integer, long
- 浮點數: float, double
- 布爾型: boolean
- 日期: date
如果沒有定義數據的類型,也沒有使用定義動態映射規則,那么會通過JSON中基本數據類型,嘗試猜測域類型,使用如下規則:
| 布爾型: true 或者 false | boolean |
| 整數: 123 | long |
| 浮點數: 123.45 | double |
| 字符串,有效日期: 2014-09-15 | date |
| 字符串: foo bar | string |
1.5.2 復雜核心域類型
除了簡單標量數據類型, JSON 還有 null 值,數組,和對象,這些 Elasticsearch 都是支持的。
- 多值域
對于數組,沒有特殊的映射需求,在es中沒有專門的數組類型。任何域都可以包含0、1或者多個值,就像全文域分析得到多個詞條。
數組中所有的值必須是相同數據類型的 。你不能將日期和字符串混在一起。如果你通過索引數組來創建新的域,Elasticsearch 會用數組中第一個值的數據類型作為這個域的 類型 。
數據:
{ "tag": [ "search", "nosql" ]}- 空域
當然,數組可以為空。 這相當于存在零值。 事實上,在 Lucene 中是不能存儲 null 值的,所以我們認為存在 null 值的域為空域。
下面三種域被認為是空的,它們將不會被索引:
"null_value": null, "empty_array": [], "array_with_null_value": [ null ]- 多層級對象
數據:
{"tweet": "Elasticsearch is very flexible","user": {"id": "@johnsmith","gender": "male","age": 26,"name": {"full": "John Smith","first": "John","last": "Smith"}} }映射:
{"gb": {"tweet": { "properties": {"tweet": { "type": "string" },"user": { "type": "object","properties": {"id": { "type": "string" },"gender": { "type": "string" },"age": { "type": "long" },"name": { "type": "object","properties": {"full": { "type": "string" },"first": { "type": "string" },"last": { "type": "string" }}}}}}}} }type 映射(tweet)只是一種特殊的 對象 映射,我們稱之為 根對象。
Lucene 不理解內部對象。 Lucene 文檔是由一組鍵值對列表組成的。為了能讓 Elasticsearch 有效地索引內部類,它把我們的文檔轉化成這樣:
{"tweet": [elasticsearch, flexible, very],"user.id": [@johnsmith],"user.gender": [male],"user.age": [26],"user.name.full": [john, smith],"user.name.first": [john],"user.name.last": [smith] }內部域 可以通過名稱引用(例如, first )。為了區分同名的兩個域,我們可以使用全 路徑 (例如, user.name.first ) 或 type 名加路徑( tweet.user.name.first )。
- 內部對象數組
假設我們有個 followers 數組:
{"followers": [{ "age": 35, "name": "Mary White"},{ "age": 26, "name": "Alex Jones"},{ "age": 19, "name": "Lisa Smith"}] }這個文檔會像我們之前描述的那樣被扁平化處理,結果如下所示:
{"followers.age": [19, 26, 35],"followers.name": [alex, jones, lisa, smith, mary, white] }{age: 35} 和 {name: Mary White} 之間的相關性已經丟失了,因為每個多值域只是一包無序的值,而不是有序數組。這足以讓我們問,“有一個26歲的追隨者?”
但是我們不能得到一個準確的答案:“是否有一個26歲 名字叫 Alex Jones 的追隨者?”
相關內部對象被稱為 nested 嵌套對象,可以回答上面的查詢,這里暫不做研究。
2. 索引
2.1 什么是索引
索引是es中存儲數據的一種邏輯,大部分人對mysql會更熟悉一些,可以對比下
(1)關系型數據庫中的數據庫(DataBase),等價于ES中的索引(Index)
(2)一個數據庫下面有N張表(Table),等價于1個索引Index下面有N多類型(Type)
(3)一個數據庫表(Table)下的數據由多行(ROW)多列(column,屬性)組成,等價于1個Type由多個文檔(Document)和多Field組成。
(4)在一個關系型數據庫里面,schema定義了表、每個表的字段,還有表和字段之間的關系。 與之對應的,在ES中:Mapping定義索引下的Type的字段處理規則,即索引如何建立、索引類型、是否保存原始索引JSON文檔、是否壓縮原始JSON文檔、是否需要分詞處理、如何進行分詞處理等。
2.2 創建一個默認配置的索引
curl -XPOST 'http://localhost:9200/posts'以上索引采用的是默認配置,新的字段通過『動態映射』的方式被添加到類型映射。當然我們可以做更多的控制,手動創建索引,在請求體里傳入設置或類型映射:
PUT /my_index {"settings": { ... any settings ... },"mappings": {"type_one": { ... any mappings ... },"type_two": { ... any mappings ... },...} }上面分為兩部分,第一部分是settings,第二部分是mappings
2.3 索引的設置(settings部分)
可以通過修改配置來自定義索引行為,但是除非你理解這些配置的作用并且知道為什么要去修改,否則不要隨意修改,Elasticsearch 已經提供了優化好的默認配置。
配置:
? 1、number_of_shards
每個索引的主分片數,默認值是 5 。這個配置在索引創建后不能修改。
? 2、number_of_replicas
每個主分片的副本數,默認值是 1 。對于活動的索引庫,這個配置可以隨時修改。
例如,我們可以創建只有 一個主分片,沒有副本的小索引:
PUT /my_temp_index {"settings": {"number_of_shards" : 1,"number_of_replicas" : 0} }? 3、配置分析器
第三個重要的索引設置是 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 }] }? ?自定義分析器
和我們之前配置 es_std 分析器一樣,我們可以在 analysis 下的相應位置設置 字符過濾器 、 分詞器 和 詞單元過濾器:
PUT /my_index {"settings": {"analysis": {"char_filter": { ... custom character filters ... },"tokenizer": { ... custom tokenizers ... },"filter": { ... custom token filters ... },"analyzer": { ... custom analyzers ... }}} }作為示范,讓我們一起來創建一個自定義分析器吧,字符過濾器 實現1、2、 分詞器 實現3, 詞單元過濾器實現4、5:
1、使用 html清除 字符過濾器移除HTML部分。(html_strip)
2、使用一個自定義的 映射 字符過濾器把 & 替換為 " and " :(_to_and)
"char_filter": {"&_to_and": {"type": "mapping","mappings": [ "&=> and "]} }3、使用 標準 分詞器分詞。(standard)
4、小寫詞條,使用 小寫 詞過濾器處理。(lowercase)
5、使用自定義 停止 詞過濾器移除自定義的停止詞列表中包含的詞:(my_stopwords)
"filter": {"my_stopwords": {"type": "stop","stopwords": [ "the", "a" ]} }一個完整的示例
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"}} }2.4 索引的映射配置(mappings部分)
2.4.1 映射寫法
比如索引gb下有tweet和user類型,那么映射應該如何定義呢,類似于下面
{"gb": {"mappings": {"tweet": {"properties": {"date": {"type": "date","format": "strict_date_optional_time||epoch_millis"},"name": {"type": "string"},"tweet": {"type": "string"},"user_id": {"type": "long"}}},"user":{...}}} }上面json數據層次如下
索引gb-> mappings-> 類型tweet-> properites-> 字段date字段name......類型user-> properites-> 字段aa字段bb......接下來梳理下映射的配置項
2.4.2 類型
關于配置中類型怎么處理很簡單,如果有多個類型,那么就并列的嵌套在mappings對象下。
但是,這里我們有必要進一步了解下類型
類型實際上是個邏輯區分,每個文檔的類型名被存儲在一個叫 _type 的元數據字段上。 當我們要檢索某個類型的文檔時, Elasticsearch 通過在 _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"}}} }結論:
多個類型可以在相同的索引中存在,只要它們的字段不沖突,類型可以很好的區分同一個集合中的不同細分,
類型不適合 完全不同類型的數據 。如果兩個類型的字段集是互不相同的,這就意味著索引中將有一半的數據是空的(字段將是 稀疏的 ),最終將導致性能問題。在這種情況下,最好是使用兩個單獨的索引。
2.4.3 根對象
映射的最高一層被稱為 根對象 ,它可能包含下面幾項:
- 一個 properties 節點,列出了文檔中可能包含的每個字段的映射
- 各種元數據字段,它們都以一個下劃線開頭,例如 _type 、 _id 和 _source
- 設置項,控制如何動態處理新的字段,例如 analyzer 、 dynamic_date_formats 和 dynamic_templates
- 其他設置,可以同時應用在根對象和其他 object 類型的字段上,例如 enabled 、 dynamic 和 include_in_all
在一個映射配置中的部分選項的位置示例:
{"gb": {"mappings": {"people": {"_source": {"enabled": false},"_all": {"enabled": false},"properties": {"name": {"type": "string","index": "analyzed","analyzer": "english"},"address": {"type": "string"}}},}} }? 1、屬性
- type屬性
字段的數據類型,例如 string 或 date
對于不是 string 的域,你一般只需要設置 type :
{"number_of_clicks": {"type": "integer"} }默認, string 類型域會被認為包含全文。就是說,它們的值在索引前,會通過 一個分析器,針對于這個域的查詢在搜索前也會經過一個分析器。
- index屬性
字段是否應當被當成全文來搜索( analyzed ),或被當成一個準確的值( not_analyzed ),還是完全不可被搜索( no )
index 屬性控制怎樣索引字符串。它可以是下面三個值:
analyzed 首先分析字符串,然后索引它。換句話說,以全文索引這個域。
not_analyzed 索引這個域,所以它能夠被搜索,但索引的是精確值。不會對它進行分析。
no 不索引這個域。這個域不會被搜索到。
string 域 index 屬性默認是 analyzed 。如果我們想映射這個字段為一個精確值,我們需要設置它為 not_analyzed :
{"tag": {"type": "string","index": "not_analyzed"} }其他簡單類型(例如 long , double , date 等)也接受 index 參數,但有意義的值只有 no 和 not_analyzed , 因為它們永遠不會被分析。
- analyzer屬性
對于 analyzed 字符串域,用 analyzer 屬性指定在搜索和索引時使用的分析器。上面我們用了很多篇幅介紹了分析器內容,在這里就可以使用這些分析器了。默認, Elasticsearch 使用 standard 分析器, 但你可以指定一個內置的分析器替代它,例如 whitespace 、 simple 和 english:
{"tweet": {"type": "string","analyzer": "english"} }- multi_field類型
有時候需要將同一個值,存入到不同的字段,例如一個字段用于搜索,另一個字段用于統計。這時我們就可以使用multi_field來實現
{"gb": {"mappings": {"user": {"properties": {"name": {"type": "multi_field","fields": {"name": {"type": "string","index": "analyzed"},"facet": {"type": "string","index": "not_analyzed"}}},}},}} }上述定義會創建兩個字段,一個通過name來引用,另一個通過name.facet引用。當然創建索引的時候沒有必要專門指定兩個不同字段,一個name字段就可以了,es會自動完成剩余的工作。
? 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},"properties": {......}}} }在一個搜索請求里,你可以通過在請求體中指定 _source 參數,來達到只獲取特定的字段的效果:
GET /_search {"query": { "match_all": {}},"_source": [ "title", "created" ] }這些字段的值會從 _source 字段被提取和返回,而不是返回整個 _source 。
? 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 },"properties": {......}} }_all字段會增加索引的大小,因為在不需要使用的時候最好禁用。
通過 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" }} }2.4.4 動態映射
我們開頭就說過es會自動匹配數據結構,這種機制其實就是動態映射,當 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 }}}} }把 dynamic 設置為 false 一點兒也不會改變 _source 的字段內容。 _source 仍然包含被索引的整個JSON文檔。只是新的字段不會被加到映射中也不可搜索。
2.4.5 自定義動態映射
有時候你想增加新的字段,也想用動態映射,但是動態映射又不是很只能,幸運的是,es允許我們自己定義動態映射的規則。
通過動態模板,你可以完全控制 新檢測生成字段的映射。你甚至可以通過字段名稱或數據類型來應用不同的映射。
每個模板都有一個名稱, 你可以用來描述這個模板的用途, 一個 mapping 來指定映射應該怎樣使用,以及至少一個參數 (如 match) 來定義這個模板適用于哪個字段。
模板按照順序來檢測;第一個匹配的模板會被啟用。例如,我們給 string 類型字段定義兩個模板:
- es :以 _es 結尾的字段名需要使用 spanish 分詞器。
- en :所有其他字段使用 english 分詞器。
我們將 es 模板放在第一位,因為它比匹配所有字符串字段的 en 模板更特殊:
PUT /my_index {"mappings": {"my_type": {"dynamic_templates": [{ "es": {"match": "*_es", "match_mapping_type": "string","mapping": {"type": "string","analyzer": "spanish"}}},{ "en": {"match": "*", "match_mapping_type": "string","mapping": {"type": "string","analyzer": "english"}}}] }}}- match_mapping_type 允許你應用模板到特定類型的字段上,就像有標準動態映射規則檢測的一樣, (例如 string 或 long)。
- match 參數只匹配字段名稱
- path_match 參數匹配字段在對象上的完整路徑,所以 address.*.name 將匹配這樣的字段:
- unmatch 和 path_unmatch將被用于未被匹配的字段。
2.4.6 缺省映射
通常,一個索引中的所有類型共享相同的字段和設置。 default 映射更加方便地指定通用設置,而不是每次創建新類型時都要重復設置。 default 映射是新類型的模板。在設置 default 映射之后創建的所有類型都將應用這些缺省的設置,除非類型在自己的映射中明確覆蓋這些設置。
例如,我們可以使用 default 映射為所有的類型禁用 _all 字段, 而只在 blog 類型啟用:
PUT /my_index {"mappings": {"_default_": {"_all": { "enabled": false }},"blog": {"_all": { "enabled": true }}} }不難發現,default 映射也可以指定映射規則,所以_default_ 映射也是一個指定索引 dynamic templates 的好方法。
2.5 索引的管理
2.5.1 創建索引
創建一個使用默認配置的索引
curl -XPOST 'http://localhost:9200/posts'創建一個手動定義規則的索引
PUT /my_index {"settings": { ... any settings ... },"mappings": {"type_one": { ... any mappings ... },"type_two": { ... any mappings ... },...} }2.5.2 查看索引
GET /gb/_mapping/tweet通過 /_mapping ,我們可以查看 Elasticsearch 在一個或多個索引中的一個或多個類型的映射
{"gb": {"mappings": {"tweet": {"properties": {"date": {"type": "date","format": "strict_date_optional_time||epoch_millis"},"name": {"type": "string"},"tweet": {"type": "string"},"user_id": {"type": "long"}}}}} }2.5.3 刪除索引
# 刪除一個索引 DELETE /my_index# 刪除 多個 索引: DELETE /index_one,index_two DELETE /index_*# 刪除 全部 索引: DELETE /_all DELETE /*2.5.4 重構索引
- 如果索引中還沒有任何數據
最簡單的方法就是刪除索引,然后重新按照自己的需求建立。
- 如果已經有數據
對現有數據的這類改變最簡單的辦法就是重新索引:用新的設置創建新的索引并把文檔從舊的索引復制到新的索引。
字段 _source 的一個優點是在Elasticsearch中已經有整個文檔。你不必從源數據中重建索引,而且那樣通常比較慢。
為了有效的重新索引所有在舊的索引中的文檔,用 scroll 從舊的索引檢索批量文檔 , 然后用 bulk API (批量寫入)把文檔推送到新的索引中。
轉載于:https://www.cnblogs.com/redirect/p/8436072.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的elasticsearch索引和映射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: laravel5.5事件系统
- 下一篇: spring3: 4.4 使用路径通配符