本篇为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方法,完成数据的落地。