Elasticsearch Document Index API 详解、原理与示例
3、Index BytesReference source 构造详解
下面是 4 中构建 JSON document 的 4 种形式:
java 的 json 字符串的 byte[]或 json 字符串
java.util.Map
使用第三方 JSON 类库构建 json 字符串或其 byte[]。
使用 Elasticsearch 自身提供的 XContentFactory.jsonBuilder()类库。
3.1、json 字符串
String json = "{" +
""user":"kimchy"," +
""postDate":"2013-01-30"," +
""message":"trying out Elasticsearch"" +
"}";
IndexResponse response = client.prepareIndex("twitter", "tweet")
.setSource(json, XContentType.JSON)
.get();
3.2、Map
Map<String, Object> json = new HashMap<String, Object>();
json.put("user","kimchy");
json.put("postDate",new Date());
json.put("message","trying out Elasticsearch");
IndexResponse response = client.prepareIndex("twitter", "tweet")
.setSource(json)
.get();
3.3、使用第三方类库
import com.fasterxml.jackson.databind.*;
// instance a json mapper
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
// generate json
byte[] json = mapper.writeValueAsBytes(yourbeaninstance);
IndexResponse response = client.prepareIndex("twitter", "tweet")
.setSource(json, XContentType.JSON)
.get();
3.4、使用 ElasticSearch 自带类库
import static org.elasticsearch.common.xcontent.XContentFactory.*;
IndexResponse response = client.prepareIndex("twitter", "tweet", "1")
.setSource(jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", new Date())
.field("message", "trying out Elasticsearch")
.endObject()
)
.get();
4、Index API 使用 Demo
当前 ElasticSearch 为单机版。
package persistent.prestige.elasticsearchdemo;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
public class IndexApiDemo {
public static void main(String[] args) {
RestHighLevelClient client = EsClient.getClient();
try {
IndexRequest request = new IndexRequest();
request.index("twitter");
request.type("_doc");
request.id("1");
Map<String, String> source = new HashMap<>();
source.put("user", "dingw");
source.put("post_date", "2009-11-16T14:12:12");
source.put("message", "trying out Elasticsearch");
request.source(source);
try {
IndexResponse result = client.index(request, RequestOptions.DEFAULT);
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
} finally {
EsClient.close(client);
}
}
}
Index API 返回结果:
{
"_shards" : {
"total" : 2,
"failed" : 0,
"successful" : 1
},
"_index" : "twitter",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"result" : "created"
}
接下来的内容将详细介绍 Index API 返回结果相关的扩展知识,让大家更加全面的了解 Index API 内部运行的机制。
5、Index API 内部实现机制
5.1 _shards 返回字段概述
_shards 结构体将反馈索引在副本级的复制信息。
total:表示本次请求应该在多少个分片上执行(包含主分片 + 副本)。
successful:表示本次请求成功执行的分片个数。
failed:表示本次请求为成功执行请求的分片个数。
注:索引操作成功的标志是 successful 大于 0。当索引操作成功返回时,复制分片(副本)可能不会全部启动(默认情况下,只有主服务器是必需的,但是这种行为可以被更改)。
当前单机环境,total 为 2 表示,一个分片存在 1 主一从,但同一个复制组内的分片不会分布在同一个机器上,故只启动了主分片,复制分片未启动;successful 为 1 表示在主分片上已成功执行,failed 为 0 表示没有执行失败的分片。
5.2 自动创建索引
使用 Index API,如果索引不存在,则会自动创建对应的索引(类型映射类型为动态映射机制,具体关于字段映射,将会在 Mapping 章节中详细介绍)。Elasticsearch 数据的组织形式为(index/type/document)。索引的管理(增删改查等 API 在后续文中会描述)。
自动索引创建可以通过配置来禁用。通过在所有节点的配置文件中添加 action.auto_create_index=false 来禁用。通过配置 index.mapper.dynamic=false 可以禁用索引的映射自动创建。
配置是否禁用自动创建索引可基于模式的白名单/黑名单列表模式,例如,action.auto_create_index=aaa*,-bbb*,+ccc*,-* 分别代表 aaa 开头的索引自动创建,bbb 开头的索引禁止自动创建,禁用索引自动创建。
5.3 版本工作机制
每个索引文档都有一个版本号。关联的版本号作为对索引 API 请求的响应的一部分返回。索引请求如果指定了版本号这个参数(IndexRequest#version)时,索引 API 可选择性地允许乐观并发控制机制,所谓乐观并发控制就是如果待操作的索引文档的版本号如果与 IndexRequest#version 版本不相同,则本次操作失败。版本控制完全是实时的,如果未提供版本,则无需验证版本信息而立即执行。
默认情况下使用内部版本控制,从 1 开始,每次更新自增 1,(包含删除)。可选地,版本号可以用外部值来补充(例如,如果在数据库中维护)。为了启用这个功能,IndexRequest#versionType 应该被设置为外部(VersionType.EXTERNAL 或 VersionType.EXTERNAL_GTE)。外部版本号的取值范围为[0,9.2 e+18)。如果使用外部版本号,系统会检查传递给索引请求的版本号是否大于当前存储文档的版本号,而不是检查匹配的版本号。如果所提供的值小于或等于存储文档的版本号,则会出现版本冲突,索引操作将失败。
警告:外部版本控制支持 0 作为有效版本号。这允许版本与外部版本控制系统同步,其中版本号从 0 开始,而不是 1。它有一个副作用,即版本号为零的文档不能使用更新的查询 API 进行更新,也不能使用查询 API 的 Delete 来删除,只要它们的版本号等于零。
外部版本号一个最佳实践,使用源数据库中数据的版本号,就不需要维护对源数据库的更改所执行的异步索引操作的严格排序。即使使用来自数据库的数据来更新 Elasticsearch 索引的简单情况,如果使用外部版本控制,也会简化,因为如果索引操作出于某种原因而不正常,则只使用最新的版本即可。
5.4 版本类型
ElasticSearch 支持如下版本类型:
internal
内部版本号,只有当请求版本号与数据版本号想等时才可以执行对应的动作。
external or external_gt
默认外部版本号,当请求版本号大于数据存储版本号时才可以执行对应动作,如果数据不存在,则使用指定版本号。
external_gte
外部版本号,当请求版本号大于等于数据存储版本号时可以执行对应动作,如果数据不存在,则使用指定版本号。
注意,外部版本号通常基于数据库,其思想更是基于乐观锁,对于版本号相等的更新动作需要特别谨慎,故外部版本号通常建议 external( external_gt)。外部版本号的取值范围[0,9.2 e+18)。
5.5 操作类型(IndexRequest#opType)
索引 API 也接受一个 opType,它可以用来强制创建动作。当使用 create 时,如果该 id 中的文档已经存? ? 在于索引中,索引操作将会失败。OpType 如下可选值:
OpType.INDEX
索引,如果文档已存在,覆盖,内部版本号+1。
O
pType.CREATE
创建,如果文档已存在,返回错误。
OpType.UPDATE
更新操作。
OpType.DELETE
删除操作。
5.6 自动 ID 生成
索引动作可以不指定文档 ID,ElasticSearch 会自动创建 ID,此时的 opType 属性会自动设置为 OpType.CREATE。其 Restfull 请求又原先的 PUT 变更为 POST,当然我们在使用 Rest Hign Level API 时无需关注 restfull 请求类型,都是通过 index 方法发生调用,内部会自动封装相应的 http 请求。
评论