更新文档
文档在Elasticsearch中是不可变的——我们不能修改他们。如果需要更新已存在的文档,我们可以使用《索引文档》章节提到的index API 重建索引(reindex) 或者替换掉它。
PUT /website/blog/123 { "title": "My first blog entry", "text": "I am starting to get the hang of this...", "date": "20 } 复制代码
其实所谓的更新,不过就是覆盖上面的一个文档,你看这个文档的版本也增加了1
删除文档
删除文档的语法模式与之前基本一致,只不过要使用DELETE方法:
DELETE /website/blog/123 复制代码
如果文档被找到,Elasticsearch将返回200 OK状态码和以下响应体。注意_version数字已经增加了。
{ "found" : true, "_index" : "website", "_type" : "blog", "_id" : "123", "_version" : 3 } 复制代码
如果文档未找到,我们将得到一个404 Not Found状态码,响应体是这样的:
{ "found" : false, "_index" : "website", "_type" : "blog", "_id" : "123", "_version" : 4 } 复制代码
直接根据状态码就能知道是否删除成功
乐观并发控制
Elasticsearch是分布式的。当文档被创建、更新或删除,文档的新版本会被复制到集群的其它节点。Elasticsearch即是同步的又是异步的,意思是这些复制请求都是平行发送的,并无序(out of sequence)的到达目的地。这就需要一种方法确保老版本的文档永远不会覆盖新的版本。 上文我们提到index、get、delete请求时,我们指出每个文档都有一个_version号码,这个号码在文档被改变时加一。Elasticsearch使用这个_version保证所有修改都被正确排序。当一个旧版本出现在新版本之后,它会被简单的忽略。
我们利用_version的这一优点确保数据不会因为修改冲突而丢失。我们可以指定文档的version来做想要的更改。如果那个版本号不是现在的,我们的请求就失败了。
用version 来保证并发的顺序一致性
文档局部更新(本质还是重新新建文档的操作,只是封装了)
在《更新文档》一章,我们说了一种通过检索,修改,然后重建整文档的索引方法来更新文档。这是对的。然而,使用update API,我们可以使用一个请求来实现局部更新,例如增加数量的操作。
我们也说过文档是不可变的——它们不能被更改,只能被替换。update API必须遵循相同的规则。表面看来,我们似乎是局部更新了文档的位置,内部却是像我们之前说的一样简单的使用update API处理相同的检索-修改-重建索引流程,我们也减少了其他进程可能导致冲突的修改。
最简单的update请求表单接受一个局部文档参数doc,它会合并到现有文档中——对象合并在一起,存在的标量字段被覆盖,新字段被添加。举个例子,我们可以使用以下请求为博客添加一个tags字段和一个views字段:
POST /website/blog/1/_update { "doc" : { "tags" : [ "testing" ], "views": 0 } } 复制代码
检索多个文档
像Elasticsearch一样,检索多个文档依旧非常快。合并多个请求可以避免每个请求单独的网络开销。如果你需要从Elasticsearch中检索多个文档,相对于一个一个的检索,更快的方式是在一个请求中使用multi-get或者mget API。
mget API参数是一个docs数组,数组的每个节点定义一个文档的_index、_type、_id元数据。如果你只想检索一个或几个确定的字段,也可以定义一个_source参数:
POST /_mget { "docs" : [ { "_index" : "website", "_type" : "blog", "_id" : 2 }, { "_index" : "website", "_type" : "pageviews", "_id" : 1, "_source": "views" } ] } 复制代码
结果
{ "docs": [ { "_index": "website", "_type": "blog", "_id": "1", "_version": 2, "_seq_no": 1, "_primary_term": 1, "found": true, "_source": { "doc": { "ada": [ "testing" ], "da": 0 } } }, { "_index": "website", "_type": "pageviews", "_id": "1", "found": false } ] } 复制代码
如果你想检索的文档在同一个_index中(甚至在同一个_type中),你就可以在URL中定义一个默认的/_index或者/_index/_type。
你依旧可以在单独的请求中使用这些值:
POST /website/blog/_mget { "docs" : [ { "_id" : 2 }, { "_type" : "pageviews", "_id" : 1 } ] } 复制代码
事实上,如果所有文档具有相同_index和_type,你可以通过简单的ids数组来代替完整的docs数组:
POST /website/blog/_mget { "ids" : [ "2", "1" ] } 复制代码
更新时的批量操作
就像mget允许我们一次性检索多个文档一样,bulk API允许我们使用单一请求来实现多个文档的create、index、update或delete。这对索引类似于日志活动这样的数据流非常有用,它们可以以成百上千的数据为一个批次按序进行索引。
bulk请求体如下,它有一点不同寻常:
{ action: { metadata }}\n { request body }\n { action: { metadata }}\n { request body }\n ... 复制代码
这种格式类似于用"\n"符号连接起来的一行一行的JSON文档流(stream)。两个重要的点需要注意:
- 每行必须以"\n"符号结尾,包括最后一行。这些都是作为每行有效的分离而做的标记。
- 每一行的数据不能包含未被转义的换行符,它们会干扰分析——这意味着JSON不能被美化打印。
action/metadata这一行定义了文档行为(what action)发生在哪个文档(which document)之上。
行为(action)必须是以下几种:
行为 | 解释 |
create | 当文档不存在时创建之。 |
index | 创建新文档或替换已有文档。 |
update | 局部更新文档。 |
delete | 删除一个文档。 |
说了那么多,大家可能有点懵,我们直接上代码
在索引、创建、更新或删除时必须指定文档的_index、_type、_id这些元数据(metadata)。 例如删除请求看起来像这样:
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} 复制代码
因为删除的话,就没有请求体了,就这样了
创建
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }} { "title": "My first blog post" } 复制代码
返回
{ "took": 5, "errors": false, "items": [ { "delete": { "_index": "website", "_type": "blog", "_id": "123", "_version": 1, "result": "not_found", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1, "status": 404 } } ] } 复制代码
结尾
其实今天就是把他的结构,和最简单的crud讲一下,大家照着做一遍就好了,明日我们用Java来操作一下增删个改查,其实最主要的查询,今天也没有细讲,还有很多要讲的