数据的输入和输出
数据的输入和输出
- es是分布式的文档存储,它能够存储和检索复杂的数据结构序列化成json文档
一旦一个文档被存储到es中,他就可以被集群中任意节点检索到 - 在es中,每个字段的所有数据默认都是被索引的,即每个字段都有为了快速检索而设置的专用倒排索引,
他不像其它多数数据库,他能在同一个查询中使用所有这些倒排索引,并以惊人的速度返回结果
什么是文档
- 通常情况下我们使用的术语对象和文档是可以相互替换的
- 在es中,文档有着特定的含义,它是指最顶层或者根对象,这个根对象被序列化成json并存储到es中
指定了唯一ID
文档元数据
- _index:
一个索引应该是因共同的特征分配到一起的文档的集合。
实际上,在es中,我们的数据是被存储和索引在分片中,而一个索引仅仅是逻辑上的命名空间
这个命名空间由一个或多个分片组成,我们只需要知道文档在哪个索引内,es能帮我们处理所有内部分片细节
- 索引名规范:索引名必须小写,不能以下划线开头,不能包含逗号
- _type:
es8.1中已经完全废弃了,不在讲解 - _id:
_id是字符串,当它和_index和_doc组合就可以唯一确定es中的一个文档,
创建文档时,可以自己提供_id,也可以让es自动生成
索引文档
- 一个文档的 _index、_doc、_id唯一标识一个文档
自动生成的 ID 是 URL-safe、 基于 Base64 编码且长度为20个字符的 GUID 字符串。
这些 GUID 字符串由可修改的 FlakeID 模式生成,这种模式允许多个节点并行生成唯一 ID ,
且互相之间的冲突概率几乎为零
取回一个文档
-
GET请求的响应体包含{"found": true},标识找到了,如果请求一个不存在的文档Id仍会返回json响应体
只不过found会是false -
返回文档的一部分
GET /website/_doc/123?_source=title,text -
只想要_source数据,不需要元数据
GET /website/_source/123/ -
只想要_source中的部分字段,元数据也不要
GET /website/_source/123/?_source=title,date
{
"title": "My first blog entry",
"date": "2014/01/01"
}
检索文档是否存在
- 检查一个文档是否存在使用HEAD方法即可
/website/_doc/123
/website/_source/123
更新整个文档
- 跟创建文档一致,只不过post方法改为put方法即可,必须传递要修改的文档_id
- 所谓的更新其实是把旧的文档标记为已删除,然后创建一个新的文档,当继续索引更多数据时,
es会在后台将这些已标记删除的文档清除掉
创建新文档
- 当我们索引一个文档,怎么确认我们正在创建一个全新的文档,而不是覆盖现有的呢
确保创建一个新文档的最简单办法就是post请求,让api自动生成_id - 然后如果已经有了自己的_id,那么我们必须告诉es,只有相同_index、_id不存在时才接收我们的索引请求
使用op_type查询字符串参数
POST /website/_doc/124?op_type=create
这样的话,website索引中不存在124id时才会创建成功status:201,否则抛出异常status:409
删除文档
-
DELETE /website/_doc/125
删除成功,status:200, "result": "deleted",
删除失败:status:404, "result": "not_found" -
即使文档不存在(result:not_found),_version值仍会增加,这是es内部记录本的一部分
用来确保这些改变在跨多节点时以正确的顺序执行 -
删除文档不会立即从磁盘中删除,而是将文档标记为已删除状态,随着后期es不断索引数据,在后台清除以标记删除的文档
乐观并发控制
-
es是分布式的,当文档创建、更新或删除时,新版本中的文档必须复制到其它节点
es也是异步和并发的,这意味着这些复制请求被并行发送,并且到达目的地时顺序是乱的
es需要一种方法确保文档的旧版本不会覆盖新版本 -
前面我们说过每一个文档都有一个_version版本号,当文档被修改时版本号递增,
es通过_version保证文档被正确执行,如果旧版本的文档在新版本之后到达,它可以被简单的忽略 -
乐观并发控制
PUT /website/_doc/1?if_seq_no=15&if_primary_term=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
- 通过外部系统使用版本控制
- 先查询出_seq_no和_primary_term
GET /website/_doc/1 - 然后更新带上获取的这两个参数
PUT /website/_doc/1?if_seq_no=27&if_primary_term=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
文档的部分更新
新版本暂时没找到解决方法...
取回多个文档
-
Elasticsearch 的速度已经很快了,但甚至能更快。 将多个请求合并成一个,避免单独处理每个请求花费的网络延时和开销。
如果你需要从 Elasticsearch 检索很多文档,那么使用 multi-get 或者 mget API 来将这些检索请求放在一个请求中,
将比逐个文档请求更快地检索到全部文档。 -
mget API要求有一个docs数组作为参数,每个元素包含需要检索文档的元数据,包括_index、_id
如果想检索一个或者多个特定的字段,可以通过_source参数来指定这些字段的名字
GET /_mget
{
"docs": [
{
"_index": "website",
"_id": 1
},
{
"_index": "website",
"_id": 123,
"_source": ["title", "date"]
}
]
}
如果想检索的数据在相同的_index中,则可以在URL中指定默认的/_index
同时仍然可以通过单独请求覆盖这些值
GET /website/_mget
{
"docs": [
{
"_id": 1
},
{
"_id": 123,
"_source": ["title", "date"]
},
{
"_index": "accounts",
"_id": 1
}
]
}
事实上,如果所有文档的_index都是相同的,可以只传递一个ids数组,而不是整个docs数组
GET /website/_mget
{
"ids": [1, 2, 3, 123]
}
找到的返回文档,同时found返回true;找不到的found返回false
事实上未找到的文档并不妨碍被找到的文档,每个文档都是单独检索和报告的,
即使文档都没有找到,状态码仍然是200,因为_mget请求本身已经成功执行,
为了确定某个文档是否成功找到,可以查看found标记