什么是文档

  1. 在Elasticsearch中,文档(document)这个术语有着特殊含义。它特指最顶层结构或者根对象(root object)序列化成的JSON数据(以唯一ID标识并存储于Elasticsearch中)
  2. 文档元数据
节点 说明
_index 文档存储的地方
_type 文档代表的对象的类
_id 文档的唯一标识
  1. _index

    • 索引(index)类似于关系型数据库里的“数据库”——它是我们存储和索引关联数据的地方。
  2. _type

    • 在应用中,我们使用对象表示一些“事物”,例如一个用户、一篇博客、一个评论,或者一封邮件。每个对象都属于一个类(class),这个类定义了属性或与对象关联的数据。user类的对象可能包含姓名、性别、年龄和Email地址。
    • 每个类型(type)都有自己的映射(mapping)或者结构定义,就像传统数据库表中的列一样。
    • _type的名字可以是大写或小写,不能包含下划线或逗号。
  3. _id

    • id仅仅是一个字符串,它与_index和_type组合时,就可以在Elasticsearch中唯一标识一个文档。
    • 当创建一个文档,你可以自定义_id,也可以让Elasticsearch帮你自动生成。

索引一个文档

  1. 使用自己的ID
PUT /{index}/{type}/{id}
{
"field": "value",
...
}
  1. 例如我们的索引叫做“website”,类型叫做“blog”,我们选择的ID是“123”
PUT /website/blog/123
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}
响应
{
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 1,
"created": true
}
  1. 自增ID
POST /website/blog/
{
"title": "My second blog entry",
"text": "Still trying this out...",
"date": "2014/01/01"
}
响应
{
"_index": "website",
"_type": "blog",
"_id": "wM0OSFhDQXGZAWDf0-drSA",
"_version": 1,
"created": true
}

自动生成的ID有22个字符长

检索文档

  1. GET /website/blog/123?pretty
{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"found" : true,
"_source" : {
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}
}

pretty

在任意的查询字符串中增加pretty参数,类似于上面的例子。会让Elasticsearch美化输出(pretty-print)JSON响应以便更加容易阅读

  1. 检索文档的一部分 GET /website/blog/123?_source=title,text

    • _source字段现在只包含我们请求的字段
    {
    "_index" : "website",
    "_type" : "blog",
    "_id" : "123",
    "_version" : 1,
    "exists" : true,
    "_source" : {
    "title": "My first blog entry" ,
    "text": "Just trying this out..."
    }
    }
  2. 或者你只想得到_source字段而不要其他的元数据,你可以这样请求:
GET /website/blog/123/_source

{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}

检查文档是否存在

  1. 只是检查文档是否存在——你对内容完全不感兴趣——使用HEAD方法来代替GET。HEAD请求不会返回响应体,只有HTTP头:
curl -i -XHEAD http://localhost:9200/website/blog/123

Elasticsearch将会返回200 OK状态如果你的文档存在:

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 0

如果不存在返回404 Not Found:

curl -i -XHEAD http://localhost:9200/website/blog/124

更新整个文档

  1. 文档在Elasticsearch中是不可变的——我们不能修改他们。如果需要更新已存在的文档,我们可以使用《索引文档》章节提到的index API 重建索引(reindex) 或者替换掉它
PUT /website/blog/123
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"
}

在响应中,我们可以看到Elasticsearch把_version增加了。

{
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"created": false
}

created标识为false因为同索引、同类型下已经存在同ID的文档

2. 在内部,Elasticsearch已经标记旧文档为删除并添加了一个完整的新文档。旧版本文档不会立即消失,但你也不能去访问它。Elasticsearch会在你继续索引更多数据时清理被删除的文档。

创建一个新文档

POST /website/blog/
{ ... }
  1. 如果想使用自定义的_id

    第一种方法使用op_type查询参数
PUT /website/blog/123?op_type=create
{ ... }

第二种方法是在URL后加/_create做为端点:

PUT /website/blog/123/_create
{ ... }
  1. 请求成功响应状态码是201 Created
  2. 如果包含相同的_index、_type和_id的文档已经存在,Elasticsearch将返回409 Conflict响应状态码
{
"error" : "DocumentAlreadyExistsException[[website][4] [blog][123]:
document already exists]",
"status" : 409
}

删除文档

  1. DELETE /website/blog/123
成功,返回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
}

处理冲突

  1. 当使用index API更新文档的时候,我们读取原始文档,做修改,然后将整个文档(whole document)一次性重新索引。最近的索引请求会生效——Elasticsearch中只存储最后被索引的任何文档。如果其他人同时也修改了这个文档,他们的修改将会丢失。
  2. 乐观并发控制
    • Elasticsearch使用_version保证所有修改都被正确排序。当一个旧版本出现在新版本之后,它会被简单的忽略。
    • 比如,创建一个新的博文,响应体告诉我们这是一个新建的文档,它的_version是1
    PUT /website/blog/1/_create
    {
    "title": "My first blog entry",
    "text": "Just trying this out..."
    }
    • 当我们通过重新索引文档保存修改时,我们这样指定了version参数,我们只希望文档的_version是1时更新才生效
    PUT /website/blog/1?version=1
    {
    "title": "My first blog entry",
    "text": "Starting to get the hang of this..."
    }
    • 成功
    {
    "_index": "website",
    "_type": "blog",
    "_id": "1",
    "_version": 2 //成功版本+1
    "created": false
    }
    • 失败
    {
    "error" : "VersionConflictEngineException[[website][2] [blog][1]:
    version conflict, current [2], provided [1]]",
    "status" : 409
    }
  3. 使用外部版本控制系统
    • 外部版本号与之前说的内部版本号在处理的时候有些不同。它不再检查_version是否与请求中指定的一致,而是检查是否小于指定的版本。如果请求成功,外部版本号就会被存储到_version中。
    • 创建一个包含外部版本号5的新博客
    PUT /website/blog/2?version=5&version_type=external
    {
    "title": "My first external blog entry",
    "text": "Starting to get the hang of this..."
    }
    响应
    {
    "_index": "website",
    "_type": "blog",
    "_id": "2",
    "_version": 5,
    "created": true
    }

文档局部更新

  1. 文档是不可变的——它们不能被更改,只能被替换。update API必须遵循相同的规则。表面看来,我们似乎是局部更新了文档的位置,内部却是像我们之前说的一样简单的使用update API处理相同的检索-修改-重建索引流程,我们也减少了其他进程可能导致冲突的修改。
  2. 为博客添加一个tags字段和一个views字段:
POST /website/blog/1/_update
{
"doc" : {
"tags" : [ "testing" ],
"views": 0
}
}
  1. 使用脚本局部更新

    • Elasticsearch允许你使用脚本实现自己的逻辑。脚本支持非常多的API,例如搜索、排序、聚合和文档更新。脚本可以通过请求的一部分、检索特殊的.scripts索引或者从磁盘加载方式执行。
    • 默认的脚本语言是Groovy,一个快速且功能丰富的脚本语言,语法类似于Javascript。它在一个沙盒(sandbox)中运行,以防止恶意用户毁坏Elasticsearch或攻击服务器。
    • 例如,我们可以使用脚本增加博客的views数量:
    POST /website/blog/1/_update
    {
    "script" : "ctx._source.views+=1"
    }
  2. 更新可能不存在的文档

    • 想象我们要在Elasticsearch中存储浏览量计数器。每当有用户访问页面,我们增加这个页面的浏览量。但如果这是个新页面,我们并不确定这个计数器存在与否。当我们试图更新一个不存在的文档,更新将失败。

      在这种情况下,我们可以使用upsert参数定义文档来使其不存在时被创建。
    POST /website/pageviews/1/_update
    {
    "script" : "ctx._source.views+=1",
    "upsert": {
    "views": 1
    }
    }

    第一次执行这个请求,upsert值被索引为一个新文档,初始化views字段为1.接下来文档已经存在,所以script被更新代替,增加views数量。

  3. 更新和冲突

    • 对于多用户的局部更新,文档被修改了并不要紧。例如,两个进程都要增加页面浏览量,增加的顺序我们并不关心——如果冲突发生,我们唯一要做的仅仅是重新尝试更新既可。
    • 这些可以通过retry_on_conflict参数设置重试次数来自动完成,这样update操作将会在发生错误前重试——这个值默认为0。
    POST /website/pageviews/1/_update?retry_on_conflict=5 //在错误发生前重试更新5次
    {
    "script" : "ctx._source.views+=1",
    "upsert": {
    "views": 0
    }
    }
    • 这适用于像增加计数这种顺序无关的操作

检索多个文档

  1. 像Elasticsearch一样,检索多个文档依旧非常快。合并多个请求可以避免每个请求单独的网络开销。如果你需要从Elasticsearch中检索多个文档,相对于一个一个的检索,更快的方式是在一个请求中使用multi-get或者mget API。
POST /_mget
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : 2
},
{
"_index" : "website",
"_type" : "pageviews",
"_id" : 1,
"_source": "views"
}
]
}

响应体也包含一个docs数组,每个文档还包含一个响应,它们按照请求定义的顺序排列。每个这样的响应与单独使用get request响应体相同:

{
"docs" : [
{
"_index" : "website",
"_id" : "2",
"_type" : "blog",
"found" : true,
"_source" : {
"text" : "This is a piece of cake...",
"title" : "My first external blog entry"
},
"_version" : 10
},
{
"_index" : "website",
"_id" : "1",
"_type" : "pageviews",
"found" : true,
"_version" : 2,
"_source" : {
"views" : 2
}
}
]
}
  1. 如果你想检索的文档在同一个_index中(甚至在同一个_type中),你就可以在URL中定义一个默认的/_index或者/_index/_type。
POST /website/blog/_mget
{
"docs" : [
{ "_id" : 2 },
{ "_type" : "pageviews", "_id" : 1 }
]
}
  1. 如果所有文档具有相同_index和_type,你可以通过简单的ids数组来代替完整的docs数组
POST /website/blog/_mget
{
"ids" : [ "2", "1" ]
}

我们请求的第二个文档并不存在。我们定义了类型为blog,但是ID为1的文档类型为pageviews。这个不存在的文档会在响应体中被告知。

{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : "2",
"_version" : 10,
"found" : true,
"_source" : {
"title": "My first external blog entry",
"text": "This is a piece of cake..."
}
},
{
"_index" : "website",
"_type" : "blog",
"_id" : "1",
"found" : false //没被找到
}
]
}

事实上第二个文档不存在并不影响第一个文档的检索。每个文档的检索和报告都是独立的

更新时的批量操作

  1. 就像mget允许我们一次性检索多个文档一样,bulk API允许我们使用单一请求来实现多个文档的create、index、update或delete。这对索引类似于日志活动这样的数据流非常有用,它们可以以成百上千的数据为一个批次按序进行索引。
  2. 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 删除一个文档
  1. 例如删除请求看起来像这样:
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
  1. bulk请求表单是这样的
POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} }
  • 注意delete行为(action)没有请求体,它紧接着另一个行为(action)
  • 记得最后一个换行符
  1. Elasticsearch响应包含一个items数组,它罗列了每一个请求的结果,结果的顺序与我们请求的顺序相同:
{
"took": 4,
"errors": false, <1>
"items": [
{ "delete": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 2,
"status": 200,
"found": true
}},
{ "create": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 3,
"status": 201
}},
{ "create": {
"_index": "website",
"_type": "blog",
"_id": "EiwfApScQiiy7TIKFxRCTw",
"_version": 1,
"status": 201
}},
{ "update": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 4,
"status": 200
}}
]
}}

每个子请求都被独立的执行,所以一个子请求的错误并不影响其它请求。如果任何一个请求失败,顶层的error标记将被设置为true,然后错误的细节将在相应的请求中被报告

  1. 演示错误情况
POST /_bulk
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "Cannot create - it already exists" }
{ "index": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "But we can update it" }

响应中我们将看到create文档123失败了,因为文档已经存在,但是后来的在123上执行的index请求成功了:

{
"took": 3,
"errors": true, //错误标识
"items": [
{ "create": {
"_index": "website",
"_type": "blog",
"_id": "123",
"status": 409,//错误状态
"error": "DocumentAlreadyExistsException //错误信息
[[website][4] [blog][123]:
document already exists]"
}},
{ "index": {
"_index": "website",
"_type": "blog",
"_id": "123",
"_version": 5,
"status": 200 //正确状态
}}
]
}
  1. 多大才算太大?

    • 整个批量请求需要被加载到接受我们请求节点的内存里,所以请求越大,给其它请求可用的内存就越小。有一个最佳的bulk请求大小。超过这个大小,性能不再提升而且可能降低
    • 最佳大小,当然并不是一个固定的数字。它完全取决于你的硬件、你文档的大小和复杂度以及索引和搜索的负载
    • 试着批量索引标准的文档,随着大小的增长,当性能开始降低,说明你每个批次的大小太大了。开始的数量可以在1000~5000个文档之间,如果你的文档非常大,可以使用较小的批次。
    • 通常着眼于你请求批次的物理大小是非常有用的。一千个1kB的文档和一千个1MB的文档大不相同。一个好的批次最好保持在5-15MB大小间

ElasticSearch权威指南学习(文档)的更多相关文章

  1. ElasticSearch权威指南学习(分布式文档存储)

    路由文档到分片 当你索引一个文档,它被存储在单独一个主分片上.Elasticsearch是如何知道文档属于哪个分片的呢?当你创建一个新文档,它是如何知道是应该存储在分片1还是分片2上的呢? 进程不能是 ...

  2. ElasticSearch权威指南学习(排序)

    排序方式 相关性排序 默认情况下,结果集会按照相关性进行排序 -- 相关性越高,排名越靠前. 相关性分值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集以_score进行倒序排列. ...

  3. ElasticSearch权威指南学习(结构化查询)

    请求体查询 简单查询语句(lite)是一种有效的命令行adhoc查询.但是,如果你想要善用搜索,你必须使用请求体查询(request body search)API. 空查询 我们以最简单的 sear ...

  4. ElasticSearch权威指南学习(映射和分析)

    概念 映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型(string, number, booleans, date等).+ 分析(analysis)机制用于进行全文 ...

  5. ElasticSearch权威指南学习(分布式集群)

    空集群 只有一个空节点的集群 一个节点(node)就是一个Elasticsearch实例,而一个集群(cluster)由一个或多个节点组成,它们具有相同的cluster.name,它们协同工作,分享数 ...

  6. ElasticSearch权威指南学习(索引管理)

    创建索引 当我们需要确保索引被创建在适当数量的分片上,在索引数据之前设置好分析器和类型映射. 手动创建索引,在请求中加入所有设置和类型映射,如下所示: PUT /my_index { "se ...

  7. ElasticSearch权威指南学习(分布式搜索)

    查询阶段 在初始化查询阶段(query phase),查询被向索引中的每个分片副本(原本或副本)广播. 每个分片在本地执行搜索并且建立了匹配document的优先队列(priority queue). ...

  8. HTTP权威指南-学习笔记

    目录 HTTP权威指南-学习笔记 HTTP: Web的基础 URL与资源 HTTP报文 连接管理 HTTP结构 Web服务器 代理 缓存 集成点: 网关,隧道及中继 Web机器人 识别,认证与安全 客 ...

  9. 初识Elastic search—附《Elasticsearch权威指南—官方guide的译文》

    本文作为Elastic search系列的开篇之作,简要介绍其简要历史.安装及基本概念和核心模块. 简史 Elastic search基于Lucene(信息检索引擎,ES里一个index—索引,一个索 ...

随机推荐

  1. javascript隐式原型

    上图是js原型关系图. javascript是一种基于对象的编程语言,但它与一般面向对象的编程语言不同,因为它没有class类的概念 什么是原型?? 我们每创建一个函数,它就会自带一个原型函数,这个原 ...

  2. php 二维数组按照某个键排序

    $date = array_column($arr, 'run_date'); //上面得到的结果:array(0=>'2017-11-21',1=>'2017-11-20',3=> ...

  3. Windows 配置nginx服务器 运行php项目

    1下载 http://nginx.org/en/download.html 选择稳定版下载. 2 解压后 直接双击nginx.exe 双击后一个黑色的弹窗一闪而过 3 修改配置文件nginx.conf ...

  4. java集合框架(1) hashMap 简单使用以及深度分析(转)

    java.util 类 HashMap<K,V>java.lang.Object  java.util.AbstractMap<K,V>      java.util.Hash ...

  5. 工欲善其事,必先利其器-ecplise配置和优化

    1.eclipse下的编码设置:eclipse 中使用模板新建 JSP,xhtml等 文件时,默认的编码为:ISO-8859-1. ISO-8859-1 编码对于中文的显示是不支持的,如果要支持简体中 ...

  6. Android后台监控指定app的输入内容,抢红包,模拟点击原理

    Android开启辅助功能之后可以用AccessibilityService 去后台监控指定的app的输入内容,也可以监控到app的动作 以及通知栏的动作, 抢红包其实就根据通知栏出现了红包的通知消息 ...

  7. linux下反弹shell

    01 前言 CTF中一些命令执行的题目需要反弹shell,于是solo一波. 02 环境 win10      192.168.43.151       监听端    装有nc kali        ...

  8. bittorrent 学习(一) 种子文件分析与bitmap位图

    终于抽出时间来进行 BITTORRENT的学习了 BT想必大家都很熟悉了,是一种文件分发协议.每个下载者在下载的同时也在向其他下载者分享文件. 相对于FTP HTTP协议,BT并不是从某一个或者几个指 ...

  9. 【project】【Maven】dynamic web module 3.1 requires 1.7

    Maven导入和新建java web 项目时可能报的错. 解决方案: 1.保证 在eclipse 构建 web中关于java版本有三处需要修改统一:  右击项目,选择“propertie”===> ...

  10. 【算法】map的应用

    map使用参考链接http://www.cnblogs.com/KID-XiaoYuan/articles/7297709.html 题目 在ACM比赛中,你每解决一道题,你就可以获得一个气球,不同颜 ...