本篇爲elasticsearch源碼分析系列文章的第十一篇,本篇開始進入索引有關操做的講解。之後的若干篇咱們會連續討論文檔的建立,檢索,更新,刪除,版本控制等一系列內容。程序員
ElasticSearch存儲系統中的實體叫作文檔,document。若是用關係型數據庫來類比的話,一個文檔至關於數據庫中的一行記錄。ElasticSearch中的文檔有個特色,相同字段必須是相同的類型,也就是說全部包含title字段的文檔,title字段類型都必須同樣,要麼同爲string,要麼同爲int。數據庫
文檔由多個字段組成,每一個字段的類型能夠是,文本,數值,日期,還能夠是字符串數組這種複雜的類型。字段類型在ElasticSearch中很是重要,它涉及到各類分析和排序操做如何被執行的信息。Elastic官方推薦咱們使用Mapping映射來干預字段的類型。與關係型數據庫不一樣,ElasticSearch不須要有固定的結構,每一個文檔能夠有不一樣的字段,此外,在程序開發期間,沒必要肯定有哪些字段。數組
在ElasticSearch中,文檔類型可讓程序員輕鬆的區分單個索引中的不一樣對象。每一個文檔能夠有不一樣的結構,但在實際生產環境中咱們仍是推薦將文檔中的類型詳細化,這樣對之後的開發會有很大的幫助。app
上面提到的映射,指的是ElasticSearch在映射中存儲有關字段的信息,這種類型信息就是映射Mapping。每一個文檔類型都有本身的映射,即便在初始化時沒有提早定義。在涉及到全文搜索和倒排索引的內容中,會有對文檔分析的過程,在這個過程當中每一個字段都必須根據不一樣類型做相應的分析。舉例來講,對數值字段和文本字段的分析確定是不一樣的分析過程,數字的分析就不該該是按照字母的排序來分析。elasticsearch
在ElasticSearch中,全部文檔都是數據,全部數據都有定義好的索引和類型。如今咱們經過一個比較常見的例子來創建文檔:源碼分析
上面操做的意思是,咱們創建了一個名爲article的索引和名爲computer的類型,文檔的標示符爲1。ui
若是一切正常,那麼這種使用RESTfulAPI的建立方式會返回一個JSON響應,與以下輸出相似:spa
前面的相應包含了操做狀態的信息,顯示了建立的文檔放在什麼地方,還包含了文檔的惟一標示符**_id和當前版本_version**的信息。每次ElasticSearch的更新版本都會自動遞增。3d
並且ElasticSearch在建立文檔時,若是沒指定文檔標示符,那麼這個文檔的標示符會被自動建立。版本控制
這都是怎麼作到的呢?咱們會在下一節從源碼的角度解釋。
在之前文章中強調的Node實例化的過程當中,加載了ActionModule這個模塊,這個模塊是接收客戶端發送的RESTful請求的的模塊,ActionModule的加載以下:
ActionModule actionModule = new ActionModule(false, settings, clusterModule.getIndexNameExpressionResolver(), settingsModule.getIndexScopedSettings(), settingsModule.getClusterSettings(), settingsModule.getSettingsFilter(), threadPool, pluginsService.filterPlugins(ActionPlugin.class), client, circuitBreakerService, usageService);
在加載完了ActionModule後,會經過ActionModule的方法**initRestHandlers()**來初始化HTTP處理程序,這個handler就能解析客戶端經過http協議發送到ElasticSearch集羣中的RESTful請求。
加載RestIndexActionindex處理器,
registerHandler.accept(new RestIndexAction(settings, restController))
以下圖所示,註冊不一樣的REST處理程序路徑,以用來不一樣的匹配請求。
能夠看到控制器匹配路徑中,有index,type和id,若是不指定id,則id會被自動建立,並且不指定id必須用POST方法來發送請求。
由於ElasticSearch中的Controller底層都是Netty實現的。因此在端口綁定後,Netty4HttpChannel會去監聽端口收到的http請求。在ElasticSearch的Controller接收到Netty4HttpChannel轉發的請求後,會調用RestIndexAction中的方法prepareRequest()。該方法返回RestChannelConsumer類型的實例,該實例是虛擬類BaseRestHandler中的Functional接口。閱讀這個接口的定義的方法,能夠知道ElasticSearch中的REST請求是經過準備一個表示通道的請求執行的通道消費者(a channel consumer)來處理的。
接收到請求後開始構建IndexRequest,這個實例做用是將JSON類型的文檔轉換爲一個特定的和可搜索的索引。
IndexRequest回首先取得RestRequest中的三個構造實例必須的參數:
而後在依次取得一些附加參數:
參數詳情以下圖:
這參數都是NodeClient在索引文檔時候須要用到的數據,NodeClient在Node初始化時候就加載完成,他是用來在本地節點上執行操做的模擬客戶端。
方法prepareRequest最後返回channel -> client.index(indexRequest, new RestStatusToXContentListener<>(channel, r -> r.getLocation(indexRequest.routing())))
,由於該方法須要返回RestChannelConsumer類型的返回值,因此改寫成jdk7版本易於理解的代碼版本以下圖所示:
該段代碼中最重要的就是NodeClient的index()方法,此方法的關鍵是新建了一個Task,這個Task包含了id,type,action,description,parentTask,startTime等信息。
該task在老版本會被TransportIndexAction處理,可是6.0版本後TransportBulkAction已經取代了TransportIndexAction。task會被當作參數送入TransportBulkAction的doExecute方法中,另外兩個參數是BulkRequest和ActionListener
void doExecute(Task task, BulkRequest bulkRequest, ActionListener<BulkResponse> listener)
複製代碼
BulkRequest中包含了該文檔存儲的信息,而ActionListener則用來監聽action的響應或失敗,用以作回調操做。
doExecute方法主要作了如下操做:
而後執行TransportBulkAction類的executeBulk方法,完成數據的落地。