在Elasticsearch中,文档(document)是全部可搜索数据的最小单位。它被序列化成JSON存储在Elasticsearch中。每一个文档都会有一个惟一ID,这个ID你能够本身指定或者交给Elasticsearch自动生成。 html
若是延续咱们以前不恰当的对比RDMS的话,我认为文档能够类比成关系型数据库中的表。node
前面咱们提到,每一个文档都有一个惟一ID来标识,获取文档时,“_id”字段记录的就是文档的惟一ID,它是元数据之一。固然,文档还有一些其余的元数据,下面咱们来一一介绍数据库
有了这三个,咱们就能够惟一肯定一个document了,固然,7.0版本之后咱们已经不须要_type了。接下来咱们再来看看其余的一些元数据json
建立文档有如下4种方法:api
这四种方法的区别是,若是不指定id,则Elasticsearch会自动生成一个id。若是使用_create的方法,则必须保证文档不存在,而使用_doc方法的话,既能够建立新的文档,也能够更新已存在的文档。安全
在建立文档时,还能够选择一些参数。bash
咱们在建立文档时,若是指定的索引不存在,则ES会自动为咱们建立索引。这一操做是能够经过设置中的action.auto_create_index字段来控制的,默认是true。你能够修改这个字段,实现指定某些索引能够自动建立或者全部索引都不能自动建立的目的。并发
了解了如何建立文档以后,咱们再来看看应该如何更新一个已经存在的文档。其实在建立文档时咱们就提到过,使用PUT /<index>/_doc/<id>的方法就能够更新一个已存在的文档。除此以外,咱们还有另外一种更新文档的方法:app
POST /<index>/_update/<_id>less
这两种更新有所不一样。_doc方法是先删除原有的文档,再建立新的。而_update方法则是增量更新,它的更新过程是先检索到文档,而后运行指定脚本,最后从新索引。
还有一个区别就是_update方法支持使用脚本更新,默认的语言是painless,你能够经过参数lang来进行设置。在请求参数方面,_update相较于_doc多了如下几个参数:
下面的一个例子是用脚原本更新文档
curl -X POST "localhost:9200/test/_update/1?pretty" -H 'Content-Type: application/json' -d' { "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } } } '
curl -X POST "localhost:9200/test/_update/1?pretty" -H 'Content-Type: application/json' -d' { "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } }, "upsert" : { "counter" : 1 } } '
当指定的文档不存在时,可使用upsert参数,建立一个新的文档,而当指定的文档存在时,该请求会执行script中的脚本。若是不想使用脚本,而只想新增/更新文档的话,可使用doc_as_upsert。
curl -X POST "localhost:9200/test/_update/1?pretty" -H 'Content-Type: application/json' -d' { "doc" : { "name" : "new_name" }, "doc_as_upsert" : true } '
这个API是用于批量更新检索出的文档的,具体能够经过一个例子来了解。
curl -X POST "localhost:9200/twitter/_update_by_query?pretty" -H 'Content-Type: application/json' -d' { "script": { "source": "ctx._source.likes++", "lang": "painless" }, "query": { "term": { "user": "kimchy" } } } '
ES获取文档用的是GET API,请求的格式是:
GET /<index>/_doc/<_id>
它会返回文档的数据和一些元数据,若是你只想要文档的内容而不须要元数据时,可使用
GET /<index>/_source/<_id>
获取文档的有几个请求参数以前已经提到过,这里再也不赘述,它们分别是:
而还有一些以前没提到过的参数,咱们来具体看一下
mget是批量获取的方法之一,请求的格式有两种:
第一种是在请求体中写index。第二种是把index放到url中,不过这种方式可能会触发ES的安全检查。
mget的请求参数和get相同,只是须要在请求体中指定doc的相关检索条件
request
GET /_mget { "docs" : [ { "_index" : "jackey", "_id" : "1" }, { "_index" : "jackey", "_id" : "2" } ] }
response
{ "docs" : [ { "_index" : "jackey", "_type" : "_doc", "_id" : "1", "_version" : 5, "_seq_no" : 6, "_primary_term" : 1, "found" : true, "_source" : { "user" : "ja", "tool" : "ES", "message" : "qwer" } }, { "_index" : "jackey", "_type" : "_doc", "_id" : "2", "_version" : 1, "_seq_no" : 2, "_primary_term" : 1, "found" : true, "_source" : { "user" : "zhe", "post_date" : "2019-11-15T14:12:12", "message" : "learning Elasticsearch" } } ] }
CURD操做只剩下最后一个D了,下面咱们就一块儿来看看ES中如何删除一个文档。
删除指定id使用的请求是
DELETE /<index>/_doc/<_id>
在并发量比较大的状况下,咱们在删除时一般会指定版本,以肯定删除的文档是咱们真正想要删除的文档。删除请求的参数咱们在以前也都介绍过,想要具体了解的同窗能够直接查看官方文档。
相似于update,delete也有一个delete by query的API。
POST /<index>/_delete_by_query
它也是要先按照条件来查询匹配的文档,而后删除这些文档。在执行查询以前,Elasticsearch会先为指定索引作一个快照,若是在执行删除过程当中,要索引起生改变,则会致使操做冲突,同时返回删除失败。
若是删除的文档比较多,也可使这个请求异步执行,只须要设置wait_for_completion=false便可。
这个API的refresh与delete API的refresh参数有所不一样,delete中的refresh参数是设置操做是否当即可见,即只刷新一个分片,而这个API中的refresh参数则是须要刷新受影响的全部分片。
最后,咱们再来介绍一种特殊的API,批量操做的API。它支持两种写法,能够将索引名写到url中,也能够写到请求体中。
POST /_bulk
POST /<index>/_bulk
在这个请求中,你能够任意使用以前的CRUD请求的组合。
curl -X POST "localhost:9200/_bulk?pretty" -H 'Content-Type: application/json' -d' { "index" : { "_index" : "test", "_id" : "1" } } { "field1" : "value1" } { "delete" : { "_index" : "test", "_id" : "2" } } { "create" : { "_index" : "test", "_id" : "3" } } { "field1" : "value3" } { "update" : {"_id" : "1", "_index" : "test"} } { "doc" : {"field2" : "value2"} } '
请求体中使用的语法是newline delimited JSON(NDJSON)。具体怎么用呢?其实咱们在上面的例子中已经有所展示了,对于index或create这样的请求,若是请求自己是有包体的,那么用换行符来表示下面的内容与子请求分隔,即为包体的开始。
例如上面例子中的index请求,它的包体就是{ "field1" : "value1" },因此它会在index请求的下一行出现。
对于批量执行操做来讲,单条操做失败并不会影响其余操做,而最终每条操做的结果也都会返回。
上面的例子执行完以后,咱们获得的结果应该是
{ "took": 30, "errors": false, "items": [ { "index": { "_index": "test", "_type": "_doc", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 201, "_seq_no" : 0, "_primary_term": 1 } }, { "delete": { "_index": "test", "_type": "_doc", "_id": "2", "_version": 1, "result": "not_found", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 404, "_seq_no" : 1, "_primary_term" : 2 } }, { "create": { "_index": "test", "_type": "_doc", "_id": "3", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 201, "_seq_no" : 2, "_primary_term" : 3 } }, { "update": { "_index": "test", "_type": "_doc", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 200, "_seq_no" : 3, "_primary_term" : 4 } } ] }
批量操做的执行过程相比屡次单个操做而言,在性能上会有必定的提高。但同时也会有必定的风险,因此咱们在使用的时候要很是的谨慎。
本文咱们先介绍了文档的基本概念和文档的元数据。接着又介绍了文档的CRUD操做和Bulk API。相信看完文章你对Elasticsearch的文档也会有必定的了解。那最后就请你启动你的Elasticsearch,而后亲自动手试一试这些操做,看看各类请求的参数究竟有什么做用。相信亲手实验过一遍以后你会对这些API有更深的印象。