ELK入門及基本使用


預備知識-Restful

起源

  在沒有前后端分離概念之前,一個網站的完成總是“all in one”,在這個階段,頁面、數據、渲染全部在服務端完成,這樣做的最大的弊端是后期維護,擴展極其痛苦,開發人員必須同時具備前后端知識。於是后來慢慢的興起了前后端分離的思想:即后端負責數據編造,而前端則負責數據渲染,前端靜態頁面調用指定 api 獲取到有固定格式的數據,再將數據展示出來,這樣呈現給用戶的就是一個”動態“的過程。

  而關於 api 這部分的設計則成了一個問題。如何設計出一個便於理解,容易使用的 api 則成了一個問題,而所謂的 RESTful 就是用來規范我們的 API 的一種約束。

REST

  作為 REST,其實是 Representational State Transfer(表象層狀態轉變)三個單詞的縮寫,它由 Roy Fielding(Fielding 是 HTTP 協議(1.0 版和 1.1 版)的主要設計者、Apache 服務器軟件的作者之一、Apache 基金會的第一任主席)於2000 年論文中提出,他在論文中提到:"我這篇文章的寫作目的,就是想在符合架構原理的前提下,理解和評估以網絡為基礎的應用軟件的架構設計,得到一個功能強、性能好、適宜通信的架構。REST 指的是一組架構約束條件和原則。"如果一個架構符合 REST 的約束條件和原則,我們就稱它為 RESTful 架構。

  要理解 RESTful 架構,最好的方法就是去理解 Representational StateTransfer 這個詞組到底是什么意思,它的每一個詞代表了什么涵義。如果你把這個名稱搞懂了,也就不難體會 REST 是一種什么樣的設計。

資源(Resources)

REST 的名稱"表現層狀態轉化"中,省略了主語。"表現層"其實指的是"資源"(Resources)的"表現層"。

所謂"資源",就是網絡上的一個實體,或者說是網絡上的一個具體信息。它可以是一段文本、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在。

要讓一個資源可以被識別,需要有個唯一標識, Web 中這個唯一標識就是URI(Uniform Resource Identifier)。

URI 既可以看成是資源的地址,也可以看成是資源的名稱。如果某些信息沒有使用 URI 來表示,那它就不能算是一個資源,只能算是資源的一些信息而已。

你可以用一個 URI(統一資源定位符)指向它,每種資源對應一個特定的 URI。

要獲取這個資源,訪問它的 URI 就可以,因此 URI 就成了每一個資源的地址或獨一無二的識別符。

所謂"上網",就是與互聯網上一系列的"資源"互動,調用它的 URI。

 

URI 設計技巧

1、使用 _  - 來讓 URI 可讀性更好

曾經 Web 上的 URI 都是冰冷的數字或者無意義的字符串,但現在越來越多的網站使用_或-來分隔一些單詞, URI 看上去更為人性化。例如國內比較出名的開源中國社區,它上面的新聞地址就采用這種風格,如

http://www.oschina.net/news/38119/oschina-translate-reward-plan。

2、使用 / 來表示資源的層級關系

例如上述/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08就表示了一個多級的資源,指的是 git 用戶的 git 項目的某次提交記錄,又例如/orders/2012/10 可以用來表示 2012 年 10 月的訂單記錄。

3、使用 ? 用來過濾資源

很多人只是把?簡單的當做是參數的傳遞,很容易造成 URI 過於復雜、難以理解。可以把?用於對資源的過濾,例如/git/git/pulls 用來表示 git 項目的所有推入請求,/pulls?state=closed 用來表示 git 項目中已經關閉的推入請求,這種 URL 通常對應的是一些特定條件的查詢結果或算法運算結果。

; 可以用來表示同級資源的關系

有時候我們需要表示同級資源的關系時,可以使用,或;來進行分割。例如哪天github 可以比較某個文件在隨意兩次提交記錄之間的差異,或許可以使用/git/git

/block-sha1/sha1.h/compare/e3af72cdafab5993d18fae056f87e1d675913d08;bd63e61bdf38e872d5215c07b264dcc16e4febca 作為 URI。不過,現在 github 是使用…來做這個事情的,例如/git/git/compare/master…next。

4、URI 不應該包含動詞

因為"資源"表示一種實體,所以應該是名詞,URI 不應該有動詞,動詞應該放在 HTTP 協議中。

舉例來說,某個 URI 是/posts/show/1,其中 show 是動詞,這個 URI 就設計錯了,正確的寫法應該是/posts/1,然后用 GET 方法表示 show。

如果某些動作是 HTTP 動詞表示不了的,你就應該把動作做成一種資源。比如網上匯款,從賬戶 1向賬戶 2匯款 500 元,錯誤的 URI 是:

POST /accounts/1/transfer/500/to/2

正確的寫法是把動詞 transfer 改成名詞 transaction,資源不能是動詞,但是可以是一種服務。

5、URI 中不宜加入版本號

例如:

http://www.example.com/app/1.0/foo

http://www.example.com/app/1.1/foo

http://www.example.com/app/2.0/foo

 

因為不同的版本,可以理解成同一種資源的不同表現形式,所以應該采用同一個 URI。版本號可以在 HTTP 請求頭信息的 Accept 字段中進行區分。

 

表現層(Representation)

  "資源"是一種信息實體,它可以有多種外在表現形式。我們把"資源"具體呈現出來的形式,叫做它的"表現層"(Representation)。

比如,文本可以用 txt 格式表現,也可以用 HTML 格式、XML 格式、JSON 格式表現,甚至可以采用二進制格式;圖片可以用 JPG 格式表現,也可以用 PNG格式表現。

URI 只代表資源的實體,不代表它的形式。嚴格地說,有些網址最后的".html"后綴名是不必要的,因為這個后綴名表示格式,屬於"表現層"范疇,URI 應該只代表"資源"的位置。它的具體表現形式,應該在 HTTP 請求的頭信息中用 Accept 和 Content-Type 字段指定,這兩個字段才是對"表現層"的描述。

 

狀態轉化(State Transfer)

  訪問一個網站,就代表了客戶端和服務器的一個互動過程。在這個過程中,勢必涉及到數據和狀態的變化。

互聯網通信協議 HTTP 協議,是一個無狀態協議。這意味着,所有的狀態都保存在服務器端。因此,如果客戶端想要操作服務器,必須通過某種手段,讓服務器端發生"狀態轉化"(State Transfer)。而這種轉化是建立在表現層之上的,所以就是"表現層狀態轉化"。

客戶端用到的手段,目前來說只能是 HTTP 協議。具體來說,就是 HTTP 協議里面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET 用來獲取資源,POST 用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE 用來刪除資源。GET、PUT 和 DELETE 請求都是冪等的,無論對資源操作多少次,結果總是一樣的, POST 不是冪等的。

 

什么是 RESTful 架構

  綜合上面的解釋,我們總結一下什么是 RESTful 架構:

  1.架構里,每一 URI 代表一種資源;

  2.客戶端和服務器之間,傳遞這種資源的某種表現層;

  3.客戶端通過四個 HTTP 動詞(get、post、put、delete),對服務器端資源進行操作,實現”表現層狀態轉化”。

  注意:REST 架構風格並不是綁定在 HTTP 上,只不過目前 HTTP 是唯一與 REST相關的實例。所以我們這里描述的 REST 也是通過 HTTP 實現的 REST。

 

辨析 URI、URL、URN

RFC 3986 中是這樣說的:

A Uniform Resource Identifier (URI) 是一個緊湊的字符串用來標示抽象或物理資源。一 URI 可以進一步被分為定位符、名字或兩者都是. 術語“Uniform Resource Locator”(URL) 是 URI 的子集, 除了確定一個資源,還提供一種定位該資源的主要訪問機制。

所以,URI = Universal Resource Identifier 統一資源標志符,包含 URL和URN,支持的協議有 http、https、ftp、mailto、magnet、telnet、data、file、nfs、gopher、ldap 等,java 還大量使用了一些非標准的定制模式, rmi,jar、jndi 和 doc,來實現各種不同用途。

URL = Universal Resource Locator 統一資源定位符,URL 唯一地標識一個資源在 Internet 上的位置。不管用什么方法表示,只要能定位一個資源,就叫URL。

URN = Universal Resource Name 統一資源名稱,URN 它命名資源但不指定如何定位資源,比如:只告訴你一個人的姓名,不告訴你這個人在哪。

對於一個資源來說,URN 就好比他的名字, URL 就好比是資源的街道住址。

換句話說,URN 標識了一個資源項目, URL 則提供了一種找到他的方法。

比如同時指定基本的獲取機制和網絡位置。舉個例子,

http://example.org/wiki/Main_Page,指向了一個被識別為/wike/Main_Page的資源,這個資源的表現形式是 HTML 和相關的代碼。而獲取這個資源的方法是在網絡中從一個名為 example.org 的主機上,通過 HTTP( Hypertext TransferProtocol)獲得。

URN 則是一種在特定的名稱空間中通過通過名字來標識資源的 URI。當討論一種資源而不需要知道它的位置或者如何去獲得它的時候,就可以使用 URN。

例如, International Standard Book Number (ISBN)系統中,* ISBN

0-486-27557-4 用來指定莎士比亞的作品《羅密歐與朱麗葉》的一個特定版本。

指示這一版本的 URN 是 urn:isbn:0-486-27557-4*,但是如果想要獲得這個版本的書,就需要知道它的位置,這樣就必須知道它的 URL。

 

什么是 ELK

為什么需要 ELK

官網的說法:Elasticsearch 是一個開源的分布式 RESTful 搜索和分析引擎,能夠解決越來越多不同的應用場景。

看一個應用場景,常見的 WEB 應用日志分析。一般我們會怎么做?

登錄到每台服務器上,直接在日志文件中 grep、awk 就可以獲得自己想要的信息。但在規模較大的場景中,此方法效率低下,面臨問題包括日志量太大如何歸檔、文本搜索太慢怎么辦、如何多維度查詢。

這個時候我們希望集中化的日志管理,所有服務器上的日志收集匯總。常見解決思路是建立集中式日志收集系統,將所有節點上的日志統一收集,管理,訪問。

這樣對於大型系統來說,都是一個分布式部署的架構,不同的服務模塊部署在不同的服務器上,問題出現時,大部分情況需要根據問題暴露的關鍵信息,定位到具體的服務器和服務模塊,構建一套集中式日志系統,可以提高定位問題的效率。

一個完整的集中式日志系統,需要包含以下幾個主要特點:

收集-能夠采集多種來源的日志數據

傳輸-能夠穩定的把日志數據傳輸到中央系統

存儲-如何存儲日志數據分析-可以支持

UI 分析警告-能夠提供錯誤報告,監控機制

ELK就是這樣一整套解決方案,並且都是開源軟件,之間互相配合使用,完美銜接,高效的滿足了很多場合的應用,而不僅僅是日志分析。

什么是 ELK

ELK是三個開源軟件的縮寫,分別表示:Elasticsearch , Logstash, Kibana , 它們都是開源軟件

Elasticsearch是個開源分布式搜索引擎,提供搜集、分析、存儲數據三大功能。它的特點有:分布式,零配置,自動發現,索引自動分片,索引副本機制,restful風格接口,多數據源,自動搜索負載等。

Logstash 主要是用來日志的搜集、分析、過濾日志的工具,支持大量的數據獲取方式。一般工作方式為 c/s 架構,client端安裝在需要收集日志的主機上,server端負責將收到的各節點日志進行過濾、修改等操作在一並發往 elasticsearch上去。

Kibana 也是一個開源和免費的工具,Kibana 可以為 Logstash 

ElasticSearch 提供的日志分析友好的 Web 界面,可以幫助匯總、分析和搜索重要數據日志。

新增了一個 Beats 系列組件,它是一個輕量級的日志收集處理工具(Agent),Beats 占用資源少,適合於在各個服務器上搜集日志或信息后傳輸給 Logstash。

加入 Beats 系列組件后,官方名稱就變為了 Elastic Stack,產品如下:

安裝,啟動和 HelloWorld

環境和安裝

運行環境為 Linux,演示服務器操作系統版本情況如下:

 

因為 Elastic Stack中主要組件都是用 Java 寫的,所以操作系統上還應該安裝好 Java,本次以 Elasticsearch 7 版本為主,所以,需要安裝 JDK1.8 以上

 

而 Elastic Stack系列產品我們可以到 Elastic的官網上去下載:

https://www.elastic.co/cn/downloads

 

選擇 7.7.0版本為本次版本,從具體的下載頁面可以看到 Elastic Stack支持各種形式的安裝。

 

 

選擇以免安裝的壓縮包的形式。下載后上傳到服務器解壓縮即可運行。

 

運行

  Elasticsearch 默認不允許用 root用戶運行,會報錯,而且從服務器安全的角度來說,也不應該以 root用戶來做日常工作,因此我們新建一個用戶 elk並以elk用戶登錄。

Elasticsearch

  用 tar -xvf命令解壓壓縮包elasticsearch-7.7.0-linux-x86_64.tar.gzip后進入elasticsearch-7.7.0文件夾中的 bin文件夾,並執行命令./elasticsearch。

待啟動完成.....

 

 

 

 

輸入 curl http://localhost:9200

顯示:

表示Elasticsearch運行成功了,我們試着在本地瀏覽器進行訪問

 

 

 

 

卻顯示“拒絕了我們的連接請求”,因此我們還需要配置一下 Elasticsearch以允許我們進行外網訪問,進入 elasticsearch-7.7.0下的 config目錄,編輯elasticsearch.yml文件,刪除 network.host前的#字符,並寫入服務器的地址並保存。

再次運行,但是這次卻出了錯

從錯誤提示我們可以知道,還需對 Elasticsearch配置做適當修改,重新編輯elasticsearch.yml文件,並做如下修改:

 

 

 

再次啟動,並在瀏覽器中訪問

顯示 Elasticsearch運行並訪問成功!

我們知道,Elasticsearch提供的是 restful風格接口,我們用瀏覽器訪問不是很方便,除非我們自行編程訪問 restful接口。這個時候,就可以用上 Kibana ,它已經為我們提供了友好的 Web 界面,方便我們后面對 Elasticsearch的學習。

接下來我們安裝運行 Kibana。

Kibana

同樣用 tar -xvf命令解壓壓縮包,進入解壓后的目錄。為了方便我們的訪問和連接 Elasticsearch,也需要進入 Kibana的 config 目錄對 Kibana 進行配置

 

然后進入 Kibana的 bin 目錄運行./kibana,kibana因為是用 node.js 編寫的,所以啟動和運行較慢,需要等待一段時間:

 

 

 

從提示我們可以看出,kibana的訪問端口是 5601,我們依然在本地瀏覽器中訪問:

 

 

 

等候幾分鍾以后,就會進入 kibana的主界面

 

 

 

TIPS:如何檢測系統中是否啟動了 kibana

我們一般會用ps -ef來查詢某個應用是否在 Linux系統中啟動,比如Elasticsearch,

我們用 ps -ef|grep java 或者 ps -ef|grep elasticsearch均可

但是當我們嘗試 ps -ef|grep kibana,卻是不行的

因為 kibana  node 寫的,所以 kibana 運行的時候是運行在 node 里面,我們要查詢的話,只能 ps -ef|grep node

或者使用 netstat -tunlp|grep 5601

 

 

 

因為我們的kibana開放的端口是5601,所以看到5601端口被 Listen (監聽),說明 kibana啟動成功。

附:netstat參數說明:

  -t (tcp)僅顯示 tcp相關選項

  -u (udp)僅顯示 udp相關選項

  -n 拒絕顯示別名,能顯示數字的全部轉化成數字。

  -l 僅列出有在 Listen (監聽) 的服務狀態

  -p 顯示建立相關鏈接的程序名

更多 netstat的相關說明,自行查閱 Linux手冊

HelloWorld

點擊面板中的“Dev Tools”按鈕,進入 Dev 工具,開始我們的 Elasticsearch初次訪問之旅。

 

 

 

創建索引

在左邊命令窗口中輸入 put enjoy_test,並點擊相關按鈕 ,於是看到右

邊的結果窗口中 es給我們返回了處理結果,表示我們在 es中創建索引成功。

 

 

 

查看索引

要查看我們剛剛創建的索引,執行“get enjoy_test”

添加文檔

往這個索引中添加文檔,執行:

PUT /enjoy_test/_doc/1

{

"msg":"Hello World!"

}

查看文檔

查詢我們剛剛加入的文檔,執行“get /enjoy_test/_doc/1”

 

 

 

Elasticsearch 基本原理和概念

 

從上面的例子中,我們看到了很多熟悉又陌生的概念,比如索引、文檔等等。這些概念和我們平時看到的數據庫里的比如索引有什么區別呢?

舉個例子,現在我們要保存唐宋詩詞,數據庫中我們們會怎么設計?詩詞表我們可能的設計如下:

朝代

作者

詩詞年代

標題

詩詞全文

李白

 

靜夜思

床前明月光,疑是地上霜。舉頭望明月,低頭思故鄉。

李清照

 

如夢令

常記溪亭日暮,沉醉不知歸路,興盡晚回舟,誤入藕花深處。爭渡,爭渡,驚起一灘鷗鷺。

….

….

….

…….

要根據朝代或者作者尋找詩,都很簡單,比如“select 詩詞全文 from 詩詞表where作者=‘李白’”,如果數據很多,查詢速度很慢,怎么辦?我們可以在對應的查詢字段上建立索引加速查詢。

但是如果我們現在有個需求:要求找到包含“望”字的詩詞怎么辦?用

“select 詩詞全文 from 詩詞表 where 詩詞全文 like‘%望%’”,這個意味着

要掃描庫中的詩詞全文字段,逐條比對,找出所有包含關鍵詞“望”字的記錄,。

基本上,數據庫中一般的 SQL 優化手段都是用不上的。數量少,大概性能還能接受,如果數據量稍微大點,就完全無法接受了,更何況在互聯網這種海量數據的情況下呢?

怎么解決這個問題呢,用倒排索引。

倒排索引 Inverted index

比如現在有:

  蜀道難(唐)李白 蜀道之難難於上青天,側身西望長咨嗟。

  靜夜思(唐)李白 舉頭望明月,低頭思故鄉。

  春台望(唐)李隆基 暇景屬三春,高台聊四望。

  鶴沖天(宋)柳永 黃金榜上,偶失龍頭望。明代暫遺賢,如何向?未遂風雲便,爭不恣狂盪。何須論得喪?才子詞人,自是白衣卿相。煙花巷陌,依約丹青屏障。

  幸有意中人,堪尋訪。且恁偎紅翠,風流事,平生暢。青春都一餉。忍把浮名,換了淺斟低唱!

都有望字,於是我們可以這么保存

序號

關鍵字

蜀道難

靜夜思

春台望

鶴沖天

1

 

 

 

 

 

 

如果查哪個詩詞中包含上,怎么辦,上述的表格可以繼續填入新的記錄

序號

關鍵字

蜀道難

靜夜思

春台望

鶴沖天

1

2

 

 

其實,上述詩詞的中每個字都可以作為關鍵字,然后建立關鍵字和文檔之間的對應關系,也就是標識關鍵字被哪些文檔包含。

所以,倒排索引就是,將文檔中包含的關鍵字全部提取處理,然后再將關鍵字和文檔之間的對應關系保存起來,最后再對關鍵字本身做索引排序。用戶在檢索某一個關鍵字是,先對關鍵字的索引進行查找,再通過關鍵字與文檔的對應關系找到所在文檔。

在存儲在關系型數據庫中的數據,需要我們事先分析將數據拆分為不同的字段,而在 es 這類的存儲中,需要應用程序根據規則自動提取關鍵字,並形成對應關系。

這些預先提取的關鍵字,在全文檢索領域一般被稱為 term(詞項),文檔的詞項提取在 es 中被稱為文檔分析,這是全文檢索很核心的過程,必須要區分哪些是詞項,哪些不是,比如很多場景下,apple和 apples 是同一個東西,望和看其實是同一個動作。

Elasticsearch 基本概念

Elasticsearch 中比較關鍵的基本概念有索引、文檔、映射、映射類型、文檔字段概念,為了方便理解,可以和關系數據庫中的相關概念進行個比對:

Elasticsearch 索引

  Elasticsearch 索引是映射類型的容器。一個 Elasticsearch 索引非常像關系型世界的數據庫,是獨立的大量文檔集合。

  當然在底層,肯定用到了倒排索引,最基本的結構就是“keyword”和“PostingList”,Posting list就是一個 int的數組,存儲了所有符合某個 term的文檔 id。

  另外,這個倒排索引相比特定詞項出現過的文檔列表,會包含更多其它信息。

  它會保存每一個詞項出現過的文檔總數,在對應的文檔中一個具體詞項出現的總次數,詞項在文檔中的順序,每個文檔的長度,所有文檔的平均長度等等相關信息。

文檔 (Document)

  文檔是 es 中所有可搜索數據的最小單位,比如日志文件中的日志項、一部電影的具體信息等等。

  文檔會被序列化 JSON格式保存到 ElasticSearch ,JSON 對象由字段組成,每個字段都有對象的字段類型(字符串,數值,布爾,日期,二進制,范圍類型)。

  同時每個文檔都有一個 Unique ID,可以自己指定 ID,或者通過 ElasticSearch 自動生成

  所以嚴格來說,es 中存儲的文檔是一種半結構化的數據

映射

  映射(mapping)定義了每個字段的類型、字段所使用的分詞器等。

  get /enjoy_test/_mapping

可以顯式映射,由我們在索引映射中進行預先定義;也可以動態映射,在添加文檔的時候,由 es 自動添加到索引,這個過程不需要事先在索引進行字段數據類型匹配等等,es 會自己推斷數據類型

既然說到了字段類型,當然就離不開字段的數據類型了。

文檔字段

文檔中的一個字段 field就相當於關系型數據庫中的一列 column,那么它肯定有數據類型,es 提供的數據類型包括至少有

數據類型

核心數據類型

字符串類型:string,字符串類還可被分為 text和 keyword 類型,如果我們讓 es自動映射數據,那么 es 會把字符串定義為 text,並且還加了一個 keyword類型字段。

text文本數據類型,用於索引全文值的字段。使用文本數據類型的字段,它們會被分詞,在索引之前將字符串轉換為單個術語的列表(倒排索引),分詞過程允許 ES 搜索每個全文字段中的單個單詞。什么情況適合使用 text,只要不具備唯一性的字符串一般都可以使用 text。

keyword,關鍵字數據類型,用於索引結構化內容的字段。使用 keyword 類型的字段,其不會被分析,給什么值就原封不動地按照這個值索引,所以關鍵字字段只能按其確切值進行搜索。什么情況下使用 keyword,具有唯一性的字符串,例如:電子郵件地址、MAC 地址、身份證號、狀態代碼...等等。

數字型數據類型:long、integer、short、byte、double、float

日期類型:date

布爾類型:boolean

復雜數據類型

數組:無需專門的數據類型

對象數據類型:單獨的 JSON對象

嵌套數據類型:nested,關於 JSON對象的數組

地理數據類型

地理點數據類型

地理形狀數據類型

專門數據類型

# IPv4 數據類型

單詞計數數據類型 token_count

我們結合前面的映射來看看:

創建一個新的索引:put /open-soft

顯式映射

put /open-soft/_mapping

{

"properties" : {

"corp" : {

"type" : "text"

},

"lang" : {

"type" : "text"

},

"name" : {

"type" : "text"

}

 

索引或者說入庫個文檔,注意這個文檔的字段,比我們顯示映射的字段要多個 star字段:

put /open-soft/_doc/1

{

"name": "Apache Hadoop",

"lang": "Java",

"corp": "Apache",

"stars":200

}

通過 get /open-soft/_mapping,我們可以看到 es 自動幫我們新增了 stars這個字段。

修改映射,增加一個新的字段:

put /open-soft/_mapping

{

"properties" : {

"year" : {

"type" : "integer"

}

}

}

數組

  不需要特殊配置,一個字段如果被配置為基本數據類型,就是天生支持數組類型的。任何字段都可以有 0個或多個值,但是在一個數組中數據類型必須一樣。

比如:

put /open-soft/_doc/2

{

"name": ["Apache Activemq","Activemq Artemis"],

"lang": "Java",

"corp": "Apache",

"stars":[500,200]

}

是沒問題的,但是如果:

put /open-soft/_doc/3

{

"name": ["Apache Kafka"],

"lang": "Java",

"corp": "Apache",

"stars":[500,"kafka"]

}

則會出錯。

對象

JSON文檔是有層次結構的,一個文檔可能包含其他文檔,如果一個文檔包含其他文檔,那么該文檔值是對象類型,其數據類型是對象。當然 ElasticSearch中是沒有所謂對象類型的,比如:

put /open-soft/_doc/object

{

"name": ["Apache ShardingSphere"],

"lang": "Java",

"corp": "JingDong",

"stars":400,

"address":{

"city":"BeiJing",

"country":"亦庄"

}

}

對象類型可以在定義索引的映射關系時進行指定。

多數據類型

  如果說數組允許你使用同一個設置索引多項數據,那么多數據類型允許使用不同的設置,對同一項數據索引多次。帶來的好處就是可以同一文本有多種不同的索引方式,比如一個字符串類型的字段,可以使用 text類型做全文檢索,使用keyword 類型做聚合和排序。我們可以看到 es 的動態映射生成的字段類型里,往往字符串類型都使用了多數據類型。當然,我們一樣也可以自己定義:

put /open-soft/_mapping

{

"properties" : {

"name" : {

"type" : "text",

"fields":{

"raw":{

"type" : "keyword"

},

"length":{

"type" : "token_count",

"analyzer":"standard"

}

}

}

}

}

  在上面的代碼里,我們使用"fields"就把 name字段擴充為多字段類型,為name新增了兩個子字段 raw和 length,raw設置類型為 keyword,length 設置類型為 token_count,告訴 es 這個字段在保存還需要做詞頻統計

  通過 fields字段設置的子字段 raw  length,在我們添加文檔時,並不需要單獨設置值,他們 name共享相同的值,只是 es 會以不同的方式處理字段值

  同樣在檢索文檔的時候,它們也不會顯示在結果中,所以它們一般都是在檢索中以查詢條件的形式出現,以減少檢索時的性能開銷。

字段參數 

 在上面的代碼里出現了analyzer這個詞,這是什么?這個叫字段參數,和 type一樣,可以用來對字段進行配置。常用的字段參數和作用如下:

analyzer

  指定分詞器。elasticsearch是一款支持全文檢索的分布式存儲系統,對於 text類型的字段,首先會使用分詞器進行分詞,然后將分詞后的詞根一個一個存儲在倒排索引中,后續查詢主要是針對詞根的搜索。

analyzer該參數可以在每個查詢、每個字段、每個索引中使用,其優先級如下(越靠前越優先):

  1、字段上定義的分詞器

  2、索引配置中定義的分詞器

  3、默認分詞器(standard)

 

normalizer

  規范化,主要針對 keyword 類型,在索引該字段或查詢字段之前,可以先對原始數據進行一些簡單的處理,然后再將處理后的結果當成一個詞根存入倒排索引中,默認為 null,比如:

PUT index

{

"settings": {

"analysis": {

"normalizer": {

"my_normalizer": { // 1

"type": "custom",

"char_filter": [],

"filter": ["lowercase", "asciifolding"] // 2

}

}

}

},

"mappings": {

"_doc": {

"properties": {

"foo": {

"type": "keyword",

"normalizer": "my_normalizer" // 3

}

}

}

}

}

代碼 1:首先在 settings中的 analysis 屬性中定義 normalizer。

代碼 2:設置標准化過濾器,示例中的處理器為小寫、asciifolding。

代碼 3:在定義映射時,如果字段類型為 keyword,可以使用 normalizer

引用定義好的 normalizer

 

boost

權重值,可以提升在查詢時的權重,對查詢相關性有直接的影響,其默認值為1.0。其影響范圍為詞根查詢(team query),對前綴、范圍查詢。5.0 版本后已廢止

 

coerce

數據不總是我們想要的,由於在轉換 JSON body 為真正 JSON 的時候,整型數字5有可能會被寫成字符串"5"或者浮點數 5.0,這個參數可以將數值不合法的部分去除。默認為 true。

例如:將字符串會被強制轉換為整數、浮點數被強制轉換為整數。

例如存在如下字段類型:

"number_one": {

"type": "integer"

}

聲明 number_one字段的類型為數字類型,那是否允許接收“6”字符串形式的數據呢?因為在 JSON中“6”用來賦給 int類型的字段,也是能接受的,默認 coerce  true,表示允許這種賦值,但如果 coerce 設置為 false,此時 es只能接受不帶雙引號的數字,如果在 coerce=false ,將“6”賦值給 number_one時會拋出類型不匹配異常。

 

copy_to

copy_to參數允許您創建自定義的_all字段。換句話說,多個字段的值可以復制到一個字段中。

例如,first_name和 last_name 字段可以復制到 full_name 字段如下:

PUT my_index

{

"mappings": {

"_doc": {

"properties": {

"first_name": {

"type": "text",

"copy_to": "full_name"

},

"last_name": {

"type": "text",

"copy_to": "full_name"

 

表示字段 full_name的值來自 first_name + last_name。

關於 copy_to重點說明:

1、字段的復制是原始值。

2、同一個字段可以復制到多個字段,寫法如下“copy_to”: [ “field_1”,

“field_2”]

doc_values

  Doc values 的存在是因為倒排索引只對某些操作是高效的。倒排索引的優勢在於查找包含某個項的文檔,而對於從另外一個方向的相反操作並不高效,即:確定哪些項是否存在單個文檔里,聚合需要這種次級的訪問模式。

  對於以下倒排索引:

  如果我們想要獲得所有包含 檔的詞的完整列表,倒排索引是根據項來排序的,所以我們首先在詞 ,然后掃描所有列,找到包含 brown 的文檔。我們可以快速 和 包含 brown 這個 token。

  然后,對於聚合部分,我們需要找到 Doc_1  Doc_2 里所有唯一的詞項。用倒排索引做這件事情代價很高:我們會迭代索引里的每個詞項並收集 Doc_1  Doc_2 列里面 token。這很慢而且難以擴展:隨着詞項和文檔的數量增加,執行時間也會增加。

  Doc values 通過轉置兩者間的關系來解決這個問題。倒排索引將詞項映射到包含它們的文檔,doc values 將文檔映射到它們包含的詞項

當數據被轉置之后,想要收集到 Doc_1  Doc_2 的唯一 token 會非常容易。獲得每個文檔行,獲取所有的詞項,然后求兩個集合的並集。

doc_values缺省是 true,即是開啟的,並且只適用於非 text類型的字段。

dynamic

  是否允許動態的隱式增加字段。在執行 index api 或更新文檔 API ,對於_source字段中包含一些原先未定義的字段采取的措施,根據 dynamic 的取值,會進行不同的操作:

  true,默認值,表示新的字段會加入到類型映射中。

  false,新的字段會被忽略,即不會存入_souce字段中,即不會存儲新字段,也無法通過新字段進行查詢。

  strict,會顯示拋出異常,需要新使用 put mapping api 先顯示增加字段映射

enabled

  是否建立索引,默認情況下為 true,es 會嘗試為你索引所有的字段,但有時候某些類型的字段,無需建立索引,只是用來存儲數據即可。也就是說,

ELasticseaech默認會索引所有的字段,enabled設為 false的字段,elasicsearch 會跳過字段內容,該字段只能從_source 中獲取,但是不可搜。只有映射類型(type)和object 類型的字段可以設置 enabled屬性。

eager_global_ordinals

  表示是否提前加載全局順序號。Global ordinals 一個建立在 doc values fielddata基礎上的數據結構, 它為每一個精確詞按照字母順序維護遞增的編號每一個精確詞都有一個獨一無二的編號 並且 精確詞 A 小於精確詞 B 的編號.Global ordinals 只支持 keyword  text 型字段,在 keyword 字段中默認是啟用的 而在 text 型字段中 只有 fielddata 和相關屬性開啟的狀態下才是可用的

fielddata

  為了解決排序與聚合,elasticsearch 提供了 doc_values 屬性來支持列式存儲,但doc_values 不支持 text 字段類型。因為 text 字段是需要先分析(分詞),會影響 doc_values 列式存儲的性能

  es 為了支持 text字段高效排序與聚合,引入了一種新的數據結構(fielddata),使用內存進行存儲。默認構建時機為第一次聚合查詢、排序操作時構建,主要存儲倒排索引中的詞根與文檔的映射關系,聚合,排序操作在內存中執行。因此fielddata需要消耗大量的 JVM 堆內存。一旦 fielddata加載到內存后,它將永久存在。

  通常情況下,加載 fielddata 一個昂貴的操作,故默認情況下,text 字段的字段默認是不開啟 fielddata機制。在使用 fielddata 之前請慎重考慮為什么要開啟fielddata。

format

  在 JSON文檔中,日期表示為字符串。Elasticsearch 使用一組預先配置的格式來識別和解析這些字符串,並將其解析為 long類型的數值(毫秒),支持自定義格式,也有內置格式。

比如:

 

PUT my_index

{

"mappings": {

"_doc": {

"properties": {

"date": {

"type": "date",

"format": "yyyy-MM-dd HH:mm:ss"

}}}}}

elasticsearch為我們內置了大量的格式,如下:

epoch_millis

時間戳,單位,毫秒,范圍受限於 Java Long.MIN_VALUE和 Long.MAX_VALUE。

epoch_second

時間戳,單位,秒,范圍受限於 Java的限制 Long.MIN_VALUE  Long.

MAX_VALUE 除以 1000(一秒中的毫秒數)。

date_optional_time或者 strict_date_optional_time

日期必填,時間可選,其支持的格式如下:

date-opt-time = date-element ['T' [time-element] [offset]]

date-element = std-date-element | ord-date-element | week-date-element

std-date-element = yyyy ['-' MM ['-' dd]]

ord-date-element = yyyy ['-' DDD]

week-date-element = xxxx '-W' ww ['-' e]

time-element = HH [minute-element] | [fraction]

minute-element = ':' mm [second-element] | [fraction]

second-element = ':' ss [fraction]

比如"yyyy-MM-dd"、"yyyyMMdd"、"yyyyMMddHHmmss"、

"yyyy-MM-ddTHH:mm:ss"、"yyyy-MM-ddTHH:mm:ss.SSS"、

"yyyy-MM-ddTHH:mm:ss.SSSZ"格式,不支持常用的"yyyy-MM-dd HH:mm:ss"等格式。

 

注意,"T"和"Z"是固定的字符。

tips:如果看到“strict_”前綴的日期格式要求,表示 date_optional_time 的嚴格級別,這個嚴格指的是年份、月份、天必須分別以 4位、2 、2 位表示,不足兩位的話第一位需用 0補齊。

   basic_date

其格式表達式為 yyyyMMdd

basic_date_time

其格式表達式為yyyyMMddTHHmmss.SSSZ

basic_date_time_no_millis

其格式表達式為yyyyMMddTHHmmssZ

basic_ordinal_date

4位數的年 + 3 (day of year)其格式字符串為 yyyyDDD

basic_ordinal_date_time

其格式字符串為 yyyyDDDTHHmmss.SSSZ

basic_ordinal_date_time_no_millis

其格式字符串為 yyyyDDDTHHmmssZ

basic_time

其格式字符串為 HHmmss.SSSZ

basic_time_no_millis

其格式字符串為 HHmmssZ

basic_t_time

其格式字符串為THHmmss.SSSZ

basic_t_time_no_millis

其格式字符串為THHmmssZ

basic_week_date

其格式字符串為 xxxxWwwe4 為年 然后用W, 2  week of year(所在年里周序號)1 day of week

basic_week_date_time

其格式字符串為 xxxxWwweTHH:mm:ss.SSSZ.

basic_week_date_time_no_millis

其格式字符串為 xxxxWwweTHH:mm:ssZ.

date

其格式字符串為 yyyy-MM-dd

date_hour

其格式字符串為 yyyy-MM-ddTHH

date_hour_minute

其格式字符串為 yyyy-MM-ddTHH:mm

date_hour_minute_second

其格式字符串為 yyyy-MM-ddTHH:mm:ss

date_hour_minute_second_fraction

其格式字符串為 yyyy-MM-ddTHH:mm:ss.SSS

date_hour_minute_second_millis

其格式字符串為 yyyy-MM-ddTHH:mm:ss.SSS

date_time

其格式字符串為 yyyy-MM-ddTHH:mm:ss.SSS

date_time_no_millis

其格式字符串為 yyyy-MM-ddTHH:mm:ss

hour

其格式字符串為 HH

hour_minute

其格式字符串為 HH:mm

hour_minute_second

其格式字符串為 HH:mm:ss

hour_minute_second_fraction

其格式字符串為 HH:mm:ss.SSS

hour_minute_second_millis

其格式字符串為 HH:mm:ss.SSS

ordinal_date

其格式字符串為 yyyy-DDD,其中 DDD day of year

ordinal_date_time

其格式字符串為 yyyy-DDDTHH:mm:ss.SSSZZ,其中 DDD day of year

ordinal_date_time_no_millis

其格式字符串為 yyyy-DDDTHH:mm:ssZZ

time

其格式字符串為 HH:mm:ss.SSSZZ

time_no_millis

其格式字符串為 HH:mm:ssZZ

t_time

其格式字符串為THH:mm:ss.SSSZZ

t_time_no_millis

其格式字符串為THH:mm:ssZZ

week_date

其格式字符串為 xxxx-'Www-e,4 位年份ww 表示 week of yeare 表示 dayof week

week_date_time

其格式字符串為 xxxx-'Www-eTHH:mm:ss.SSSZZ

week_date_time_no_millis

其格式字符串為 xxxx-'Www-eTHH:mm:ssZZ

weekyear

其格式字符串為 xxxx

weekyear_week

其格式字符串為 xxxx-'Www,其中 ww  week of year

weekyear_week_day

其格式字符串為 xxxx-'Www-e,其中 ww  week of year,e day of week

year

  其格式字符串為 yyyy

  year_month

  其格式字符串為 yyyy-MM

year_month_day

  其格式字符串為 yyyy-MM-dd

ignore_above

ignore_above用於指定字段索引和存儲的長度最大值超過最大值的會被忽略。

ignore_malformed

 ignore_malformed可以忽略不規則數據對於 login 字段有人可能填寫的是date類型也有人填寫的是郵件格式個字段索引不合適的數據類型發生異常導致整個文檔索引失敗如果 ignore_malformed參數設為 true異常會被忽

出異常的字段不會被索引其它字段正常索引

   

index

index 屬性指定字段是否索引,不索引也就不可搜索,取值可以為 true 或者false,缺省為 true。

 

index_options

index_options 控制索引時存儲哪些信息到倒排索引中,,用於搜索和突出顯示目的。

docs 只存儲文檔編號

freqs 存儲文檔編號和詞項頻率

positions 文檔編號、詞項頻率、詞項的位置被存儲

offsets 文檔編號、詞項頻率、詞項的位置、詞項開始和結束的字符位置都被存儲。

 

fields

fields可以讓同一文本有多種不同的索引方式,比如一個 String 類型的字段,可以使用 text類型做全文檢索,使用 keyword 類型做聚合和排序

 

norms

norms參數用於標准化文檔,以便查詢時計算文檔的相關性。norms 雖然對評分有用,但是會消耗較多的磁盤空間,如果不需要對某個字段進行評分,最好不要開啟 norms。

 

null_value

一般來說值為 null的字段不索引也不可以搜索,null_value參數可以讓值為null的字段顯式的可索引、可搜索。

PUT my_index

{

"mappings": {

"my_type": {

"properties": {

"status_code": {

"type": "keyword",

"null_value": "NULL"

}

}

}

}

 

}

 

 

 

 

 

 

GET my_index/_search

 

{

 

"query": {

 

"term": {

 

"status_code": "NULL"

 

}

 

}

 

}

 

文檔 1可以被搜索到,因為 status_code的值為 null,文檔 2 不可以被搜索到,因為 status_code為空數組,但是不是 null。

 

 

 

position_increment_gap

 

文本數組元素之間位置信息添加的額外值。

 

舉例,一個字段的值為數組類型:"names": [ "John Abraham", "Lincoln Smith"]為了區別第一個字段和第二個字段,Abraham和 Lincoln在索引中有一個間

 

距,默認是 100。例子如下,這是查詢”Abraham Lincoln”是查不到的:

 

PUT my_index/groups/1

 

{

 

"names": [ "John Abraham", "Lincoln Smith"]

 

}

 

 

 

GET my_index/groups/_search

{

"query": {

"match_phrase": {

"names": {

"query": "Abraham Lincoln"

}}}}

指定間距大於 10 0 可以查詢到

GET my_index/groups/_search

{

"query": {

"match_phrase": {

"names": {

"query": "Abraham Lincoln",

"slop": 101

}}}}

想要調整這個值,在 mapping中通過 position_increment_gap 參數指定間距即可

 

properties

Object或者 nested類型,下面還有嵌套類型,可以通過 properties 參數指定

比如:

PUT my_index

{

"mappings": {

"my_type": {

"properties": {

"manager": {

"properties": {

"age": { "type": "integer" },

"name": { "type": "text" }

}

},

"employees": {

"type": "nested",

"properties": {

"age": { "type": "integer" },

"name": { "type": "text" }

}}}}}}

對應的文檔結構:

PUT my_index/my_type/1

{

"region": "US",

"manager": {

"name": "Alice White",

"age": 30

},

"employees": [

{

"name": "John Smith",

"age": 34

},

{

"name": "Peter Brown",

"age": 26

}

]

}

search_analyzer

通常,在索引時和搜索時應用相同的分析器,以確保查詢中的術語與反向索引中的術語具有相同的格式,如果想要在搜索時使用與存儲時不同的分詞器,則使用 search_analyzer屬性指定,通常用於 ES 實現即時搜索(edge_ngram)。

 

similarity

指定相似度算法,其可選值:

BM25

當前版本的默認值,使用 BM25算法。

classic

使用 TF/IDF算法,曾經是 es,lucene 的默認相似度算法

boolean

一個簡單的布爾相似度,當不需要全文排序時使用,並且分數應該只基於查詢條件是否匹配。布爾相似度為術語提供了一個與它們的查詢boost相等的分數。

 

store

默認情況下,字段值被索引以使其可搜索,但它們不存儲。這意味着可以查詢字段,但無法檢索原始字段值。通常這並不重要。字段值已經是_source字段的一部分,該字段默認存儲。如果您只想檢索單個字段或幾個字段的值,而不是整個_source,那么這可以通過字段過濾上下文 source filting context來實現。

在某些情況下,存儲字段是有意義的。例如,如果您有一個包含標題、日期和非常大的內容字段的文檔,您可能只想檢索標題和日期,而不需要從大型_source字段中提取這些字段,可以將標題和日期字段的 store定義為 ture。

 

term_vector

Term vectors 包含分析過程產生的索引詞信息,包括:

索引詞列表

每個索引詞的位置(或順序)

索引詞在原始字符串中的原始位置中的開始和結束位置的偏移量。

term vectors 會被存儲,索引它可以作為一個特使的文檔返回。

term_vector可取值:

不存儲 term_vector信息,默認值。

yes

只存儲字段中的值。

with_positions

存儲字段中的值與位置信息。

with_offsets

存儲字段中的值、偏移量

with_positions_offsets

存儲字段中的值、位置、偏移量信息。

 

元字段 meta-fields

一個文檔根據我們定義的業務字段保存有數據之外,它還包含了元數據字段

(meta-fields)。元字段不需要用戶定義,在任一文檔中都存在,有點類似於數據庫的表結構數據。在名稱上有個顯著的特征,都是以下划線“_”開頭。

我們可以看看:get /open-soft/_doc/1

大體分為五種類型:身份(標識)元數據、索引元數據、文檔元數據、路由元數據以及其他類型的元數據,當然不是每個文檔這些元字段都有的。

身份(標識)元數據

_index:文檔所屬索引 , 自動被索引,可被查詢,聚合,排序使用,或者腳本里訪問

_type:文檔所屬類型,自動被索引,可被查詢,聚合,排序使用,或者腳本里訪問

_id:文檔的唯一標識,建索引時候傳入 不被索引,可通過_uid被查詢,腳本里使用,不能參與聚合或排序

_uid:由_type和_id字段組成,自動被索引 可被查詢,聚合,排序使用,或者腳本里訪問,6.0.0版本后已廢止。

 

索引元數據

_all:自動組合所有的字段值,以空格分割,可以指定分器詞索引,但是整個值不被存儲,所以此字段僅僅能被搜索,不能獲取到具體的值。6.0.0版本后已廢止。

_field_names:索引了每個字段的名字,可以包含 null值,可以通過 exists查詢或 missing查詢方法來校驗特定的字段

 

文檔元數據

_source  個 doc的原生的 json 數據,不會被索引,用於獲取提取字段值,啟動此字段,索引體積會變大,如果既想使用此字段又想兼顧索引體積,可以開啟索引壓縮。

_source是可以被禁用的,不過禁用之后部分功能不再支持,這些功能包括:部分 update api、運行時高亮搜索結果

索引重建、修改 mapping以及分詞、索引升級

debug查詢或者聚合語句

索引自動修復

_size:整個_source 字段的字節數大小,需要單獨安裝一個 mapper-size插件才能展示。

 

路由元數據

_routing:一個 doc可以被路由到指定的 shard上。

_meta:一般用來存儲應用相關的元信息。

 

其他

例如:

put /open-soft/_mapping

{

"_meta": {

"class": "cn.enjoyedu.User",

"version": {"min": "1.0", "max": "1.3"}

}

}

管理 Elasticsearch 索引和文檔

  在 es ,索引和文檔是 REST 接口操作的最基本資源,所以對索引和文檔的管理也是我們必須要知道的。索引一般是以索引名稱出現在 REST請求操作的資源路徑上,而文檔是以文檔 ID 為標識出現在資源路徑上。映射類型_doc 也可以認為是一種資源,但在 es7 中廢除了映射類型,所以可以_doc 也視為一種接口。

 

索引的管理

在前面的學習中我們已經知道,GET 用來獲取資源,PUT 用來更新資源,DELETE用來刪除資源。所以對索引,GET用來查看索引,PUT用來創建索引,DELETE用來刪除索引,還有一 HEAD 請求,用來檢驗索引是否存在。除此之外,對索引的管理還有

 

列出所有索引

GET /_cat/indices?v

 

關閉索引和打開

POST /open-soft/_close、、

 

除了刪除索引,還可以選擇關閉它們。如果關閉了一個索引,就無法通過Elasticsearch來讀取和寫人其中的數據,直到再次打開它。

在現實世界中,最好永久地保存應用日志,以防要查看很久之前的信息。另一方面,在 Elasticsearch 中存放大量數據需要增加資源。對於這種使用案例,關閉舊的索引非常有意義。你可能並不需要那些數據,但是也不想刪除它們。

一旦索引被關閉,它在 Elasticsearch 內存中唯-的痕跡是其元數據,如名字

以及分片的位置。如果有足夠的磁盤空間,而且也不確定是否需要在那個數據中再次搜索,關閉索引要比刪除索引更好。關閉它們會讓你非常安心,永遠可以重新打開被關閉的索引,然后在其中再次搜索。

重新打開 POST /open-soft/_open

配置索引

通過 settings參數配置索引,索引的所有配置項都以“index”開頭。索引的管理分為靜態設置和動態設置兩種。

 

靜態設置

只能在索引創建時或在狀態為 closed index(閉合索引)上設置,主要配置索引主分片、壓縮編碼、路由等相關信息

index.number_of_shards主分片數,默認為 5.只能在創建索引時設置,不能修改

index.shard.check_on_startup 是否應在索引打開前檢查分片是否損壞,當檢查到分片損壞將禁止分片被打開。false:默認值;checksum:檢查物理損壞;true:檢查物理和邏輯損壞,這將消耗大量內存和 CPU;fix:檢查物理和邏輯損壞。

有損壞的分片將被集群自動刪除,這可能導致數據丟失

index.routing_partition_size 自定義路由值可以轉發的目的分片數。默認為 1,只能在索引創建時設置。此值必須小於 index.number_of_shards

index.codec 默認使用 LZ4壓縮方式存儲數據,也可以設置為

best_compression,它使用 DEFLATE 方式以犧牲字段存儲性能為代價來獲得更高的壓縮比例

如:

put test1{

"settings":{

"index.number_of_shards":3,

"index.codec":"best_compression"

}

}

 

動態設置

通過接口“_settings”進行,同時查詢配置也通過這個接口進行,比如:get _settings

get /open-soft/_settings

get /open-soft,test1/_settings

配置索引則通過:

put test1/_settings

{

"refresh_interval":"2s"

}

常用的配置參數如下:

index.number_of_replicas 每個主分片的副本數。默認為 1

index.auto_expand_replicas 基於可用節點的數量自動分配副本數量,默認為false(即禁用此功能)

index.refresh_interval 執行刷新操作的頻率。默認為 1s。可以設置為 -1 以禁用刷新

index.max_result_window 用於索引搜索的 from+size 的最大值。默認為10000

index.blocks.read_only 設置為 true 使索引和索引元數據為只讀,false 為允許寫入和元數據更改

index.blocks.read 設置為 true 可禁用對索引的讀取操作

index.blocks.write 設置為 true 可禁用對索引的寫入操作

index.blocks.metadata 設置為 true 可禁用索引元數據的讀取和寫入

index.max_refresh_listeners 索引的每個分片上可用的最大刷新偵聽器數index.max_docvalue_fields_search 一次查詢最多包含開啟 doc_values 字段

的個數,默認為 100

index.max_script_fields 查詢中允許的最大 script_fields數量。默認為 32。

index.max_terms_count 可以在 terms 查詢中使用的術語的最大數量。默認為65536。

index.routing.allocation.enable 控制索引分片分配。All(所有分片)、primaries(主分片)、new_primaries(新創建分片)、none(不分片)

index.routing.rebalance.enable 索引的分片重新平衡機制。all、primaries、replicas、none

index.gc_deletes 文檔刪除后(刪除后版本號)還可以存活的周期,默認

為 60s

index.max_regex_length用於正在表達式查詢(regex query)正在表達式長度,默認為 1000

 

配置映射

通過_mapping 接口進行,在我們前面的章節中,已經展示過了。

get /open-soft/_mapping

或者只看某個字段的屬性:

get /open-soft/_mapping/field/lang

修改映射,當然就是通過 put或者 post方法了。但是要注意,已經存在的映射只能添加字段或者字段的多類型。但是字段創建后就不能刪除,大多數參數也不能修改,可以改的是 ignore_above。所以設計索引時要做好規划,至少初始時的必要字段要規划好。

 

增加文檔

增加文檔,我們在前面的章節已經知道了,比如:

put /open-soft/_doc/1

 {

"name": "Apache Hadoop",

"lang": "Java",

"corp": "Apache",

"stars":200

}

如果增加文檔時,在 Elasticsearch中如果有相同 ID的文檔存在,則更新此文檔,比如執行

put /open-soft/_doc/1

{

"name": "Apache Hadoop2",

"lang": "Java8",

"corp": "Apache",

"stars":300

}

則會發現已有文檔的內容被更新了

 

文檔的 id

當創建文檔的時候,如果不指定 ID,系統會自動創建 ID。自動生成的 ID 是一個不會重復的隨機數。使用 GUID 算法,可以保證在分布式環境下,不同節點同一時間創建的_id一定是不沖突的。比如:

post /open-soft/_doc

{

"message":"Hello"

}

 

查詢文檔

get /open-soft/_doc/

 

更新文檔

前面我們用 put方法更新了已經存在的文檔,但是可以看見他是整體更新文檔,如果我們要更新文檔中的某個字段怎么辦?需要使用_update接口。

post /open-soft/_update/1/

{

"doc":{

"year": 2016

}

}

如果文檔中存在 year字段,更新 year 字段的值,如果不存在 year 字段,則會新增 year字段,並將值設為 2016。

update 接口在文檔不存在時提示錯誤,如果希望在文檔不存在時創建文檔,則可以在請求中添加 upsert參數或 doc_as_upsert 參數,例如:

POST /open-soft/_update/5

{

"doc": {

"year": "2020"

},

"upsert":{

"name" : "Enjoyedu Framework",

"corp" : "enjoyedu "

}

}

 

POST /open-soft/_update/6

{

"doc": {

"year": "2020"

},

"doc_as_upsert" : true

}

upsert參數定義了創建新文檔使用的文檔內容,而 doc_as_upsert 參數的含義是直接使用 doc參數中的內容作為創建文檔時使用的文檔內容。

 

刪除文檔

delete /open-soft/_doc/1

 

數據檢索和分析

為了方便我們學習我們導入 kibana 為我們提供的范例數據

目前為止,我們已經探索了如何將數據放入 Elasticsearch,現在來討論下如何將數據從 Elasticsearch中拿出來,那就是通過搜索。畢竟,如果不能搜索數據,那么將其放入搜索引擎的意義又何在呢?幸運的是,Elasticsearch 提供了豐富的接口來搜索數據,涵蓋了 Lucene 所有的搜索功能。因為 Elasticsearch允許構建搜索請求的格式很靈活,請求的構建有無限的可能性。要了解哪些查詢和過濾器的組合適用於你的數據,最佳的方式就是進行實驗,因此不要害怕在項目的數據上嘗試這些組合,這樣才能弄清哪些更適合你的需求。

 

_search 接口

所有的 REST搜索請求使用_search 接口,既可以是 GET請求,也可以是 POST請求,也可以通過在搜索 URL 中指定索引來限制范圍

_search 接口有兩種請求方法,一種是基於 URI 的請求方式,另一種是基於請求體的方式,無論哪種,他們執行的語法都是基於 DSL(ES 為我們定義的查詢語言,基於 JSON的查詢語言),只是形式上不同。我們會基於請求體的方式來學習。比如說:

get kibana_sample_data_flights/_search

{

"query":{

"match_all":{}

}

}

get kibana_sample_data_flights/_search

{

"query":{

"match_none":{}

}

}

當然上面的查詢沒什么太多的用處,因為他們分別代表匹配所有和全不匹配。

所以我們經常要使用各種語法來進行查詢,一旦選擇了要搜索的索引,就需要配置搜索請求中最為重要的模塊。這些模塊涉及文檔返回的數量,選擇最佳的文檔返回,以及配置不希望哪些文檔出現在結果中等等。

■ query-這是搜索請求中最重要的組成部分,它配置了基於評分返回的最佳文檔,也包括了你不希望返回哪些文檔。

■ size-代表了返回文檔的數量。

■ from-和 size 一起使用,from 用於分頁操作。需要注意的是,為了確定第2頁的 10 項結果,Elasticsearch 必須要計算前 20 個結果。如果結果集合不斷增加,獲取某些靠后的翻頁將會成為代價高昂的操作。

■ _source指定_ source 字段如何返回。默認是返回完整的_ source字段。

通過配置_ source,將過濾返回的字段。如果索引的文檔很大,而且無須結果中的全部內容,就使用這個功能。請注意,如果想使用它,就不能在索引映射中關閉_source 字段

■ sort默認的排序是基於文檔的得分。如果並不關心得分,或者期望許多文檔的得分相同,添加額外的 sort將幫助你控制哪些文檔被返回。

結果起始和頁面大小

命名適宜的 from和 size字段,用於指定結果的開始點,以及每“頁"結果的數量。舉個例子,如果發送的 from 值是 7,size值是 5,那么 Elasticsearch 將返回第8、9、10、11  12項結果(由於 from 參數是從 0開始,指定 7 就是從第 8項結果開始)。如果沒有發送這兩個參數,Elasticsearch 默認從第一項結果開始(第 0 項結果),在回復中返回 10項結果。

例如

get kibana_sample_data_flights/_search

{

"from":100,

"size":20,

"query":{

"term":{

"DestCountry":"CN"

}

}

}

但是注意,from與 size 的和不能超過 index. max_result_window 這個索引配置項設置的值。默認情況下這個配置項的值為 10000,所以如果要查詢 10000 條以后的文檔,就必須要增加這個配置值。例如,要檢索第 10000 條開始的 200條數據,這個參數的值必須要大於 10200,否則將會拋出類似“Result window is toolarge'的異常。

由此可見,Elasticsearch 在使用 from  size處理分頁問題時會將所有數據全部取出來,然后再截取用戶指定范圍的數據返回。所以在查詢非常靠后的數據時,即使使用了 from和 size定義的分頁機制依然有內存溢出的可能,而 max_result_ window設置的 10000條則是對 Elastiesearch 的一.種保護機制。

那么 Elasticsearch 為什么要這么設計呢?首先,在互聯網時代的數據檢索應該通過相似度算法,提高檢索結果與用戶期望的附和度,而不應該讓用戶在檢索結果中自己挑選滿意的數據。以互聯網搜索為例,用戶在瀏覽搜索結果時很少會看到第 3頁以后的內容。假如用戶在翻到第 10000 條數據時還沒有找到需要的結果,那么他對這個搜索引擎一定會非常失望。

 

_source 參數

 

元字段_source 中存儲了文檔的原始數據。如果請求中沒有指定_source,Elasticsearch 默認返回整個_ source,或者如果_ source沒有存儲,那么就只返回匹配文檔的元數據:_ id、_type、_index _score。

例如:

get kibana_sample_data_flights/_search

{

"query":{

"match_all":{}

},

"_source":["OriginCountry","DestCountry"]

}

你不僅可以返回字段列表,還可以指定通配符。例如,如果想同時返回"

DestCountry "和" DestWeather "字段,可以這樣配置_ source: "Dest*"。也可以使用通配字符串的數組來指定多個通配符,例如_ source:[" Origin*", "* Weather "]。

get kibana_sample_data_flights/_search

{

"query":{

"match_all":{}

},

"_source":["Origin*","*Weather"]

}

不僅可以指定哪些字段需要返回,還可以指定哪些字段無須返回。比如:get kibana_sample_data_flights/_search

{

"_source":{

"includes":["*.lon","*.lat"],

"excludes":"DestLocation.*"

}

}

 

排序

大多搜索最后涉及的元素都是結果的排序( sort )。如果沒有指定 sort 排序選項,Elasticsearch返回匹配的文檔的時候,按照_ score 取值的降序來排列,這樣最為相關的(得分最高的)文檔就會排名在前。為了對字段進行升序或降序排列,

 

指定映射的數組,而不是字段的數組。通過在 sort 中指定字段列表或者是字段映射,可以在任意數量的字段上進行排序。

 

例如:

 

get kibana_sample_data_flights/_search

 

{

 

"from":100,

 

"size":20,

 

"query":{

 

"match_all":{}

 

},

 

"_source":["Origin*","*Weather"],

 

"sort":[{"DistanceKilometers":"asc"},{"FlightNum":"desc"}]

 

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM