es中使用bulk进行批量数据操作与相关内容

bulk API可以帮助我们同时完成执行多个请求,比如:create,index, update以及delete。当你在处理类似于log等海量数据的时候,你就可以一下处理成百上千的请求,这个操作将会极大提高效率。

bulk的请求主体的格式稍微有些不同:

{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...

这种格式就类似于一个用"\n"字符来连接的单行json一样。下面是两点注意事项:

每一行都结尾处都必须有换行字符"\n",最后一行也要有。这些标记可以有效地分隔每行。

这些行里不能包含非转义字符,以免干扰数据的分析 — — 这也意味着JSON不能是pretty-printed样式。

action/metadata 行指定了将要在哪个文档中执行什么操作。

其中action必须是index, create, update或者delete。metadata 需要指明需要被操作文档的_index, _type以及_id,例如删除命令就可以这样填写:

{ “delete”: { “_index”: “website”, “_type”: “blog”, “_id”: “123” }}

在你进行index以及create操作时,request body 行必须要包含文档的_source数据——也就是文档的所有内容。

同样,在执行update API: doc, upsert,script的时候,也需要包含相关数据。而在删除的时候就不需要request body行。

{ "create":  { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "My first blog post" }

如果没有指定_id,那么系统就会自动生成一个ID:

{ "index": { "_index": "website", "_type": "blog" }}
{ "title":    "My second blog post" }

完成以上所有请求的bulk如下:

POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} <1>
{ "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"} } <2>

注意delete操作是如何处理request body的,你可以在它之后直接执行新的操作。

请记住最后有换行符

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,详细的错误信息也会出现在返回内容的下方:

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, <1>
   "items": [
      {  "create": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "status":   409, <2>
            "error":    "DocumentAlreadyExistsException <3>
                        [[website][4] [blog][123]:
                        document already exists]"
      }},
      {  "index": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 5,
            "status":   200 <4>
      }}
   ]
}

至少有一个请求错误发生。
这条请求的状态码为409 CONFLICT。
错误信息解释了导致错误的原因。
第二条请求的状态码为200 OK。

这也更好地解释了bulk请求是独立的,每一条的失败与否 都不会影响到其他的请求。
能省就省

或许你在批量导入大量的数据到相同的index以及type中。每次都去指定每个文档的metadata是完全没有必要的。在mget API中,bulk请求可以在URL中声明/_index 或者/_index/_type:

POST /website/_bulk
{ "index": { "_type": "log" }}
{ "event": "User logged in" }

你依旧可以在metadata行中使用_index以及_type来重写数据,未声明的将会使用URL中的配置作为默认值:

POST /website/log/_bulk
{ "index": {}}
{ "event": "User logged in" }
{ "index": { "_type": "blog" }}
{ "title": "Overriding the default type" }

最大有多大?

整个数据将会被处理它的节点载入内存中,所以如果请求量很大的话,留给其他请求的内存空间将会很少。bulk应该有一个最佳的限度。超过这个限制后,性能不但不会提升反而可能会造成宕机。

最佳的容量并不是一个确定的数值,它取决于你的硬件,你的文档大小以及复杂性,你的索引以及搜索的负载。幸运的是,这个平衡点 很容易确定:

试着去批量索引越来越多的文档。当性能开始下降的时候,就说明你的数据量太大了。一般比较好初始数量级是1000到5000个文档,或者你的文档很大,你就可以试着减小队列。有的时候看看批量请求的物理大小是很有帮助的。1000个1KB的文档和1000个1MB的文档的差距将会是天差地别的。比较好的初始批量容量是5-15MB。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用elasticsearch-sql框架,可以通过以下步骤将SQL数据插入ES: 1. 创建一个ES索引,定义字段映射 2. 使用ES-SQL框架连接ES,执行SQL查询获取数据 3. 遍历查询结果,使用ES-SQL框架提供的API将数据插入ES 下面是一个示例代码,演示如何使用ES-SQL框架将SQL数据插入ES: ```java import io.github.iamazy.elasticsearch.dsl.sql.parser.SqlParser; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.nlpcn.es4sql.exception.SqlParseException; import org.nlpcn.es4sql.query.QueryAction; import org.nlpcn.es4sql.query.SqlElasticRequestBuilder; import java.io.IOException; import java.sql.*; public class SqlToEs { // 定义ES索引名称 private static final String INDEX_NAME = "my_index"; // 定义ES连接客户端 private RestHighLevelClient client; // 定义SQL查询语句 private String sql = "SELECT * FROM my_table WHERE id > 100"; public SqlToEs() { // 初始化ES连接客户端 client = new RestHighLevelClient(); } public void insert() throws SQLException, IOException, SqlParseException { // 解析SQL查询语句 SqlParser sqlParser = new SqlParser(); QueryAction queryAction = sqlParser.parseSelect(sql); // 构建ES查询请求 SqlElasticRequestBuilder requestBuilder = queryAction.explain(); SearchSourceBuilder sourceBuilder = requestBuilder.getSourceBuilder(); sourceBuilder.query(QueryBuilders.matchAllQuery()); String query = sourceBuilder.toString(); // 执行SQL查询获取数据 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_database", "user", "password"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(query); // 遍历查询结果,将数据插入ES BulkRequest request = new BulkRequest(); while (rs.next()) { // 创建一个ES文档 Map<String, Object> document = new HashMap<>(); document.put("id", rs.getInt("id")); document.put("name", rs.getString("name")); document.put("age", rs.getInt("age")); // 添加到批量请求 request.add(new IndexRequest(INDEX_NAME).source(document)); } // 执行批量请求 BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT); if (bulkResponse.status() == RestStatus.OK) { System.out.println("数据插入成功!"); } } } ``` 这里使用ES-SQL框架解析SQL查询语句,并构建ES查询请求。然后执行SQL查询获取数据,并遍历查询结果,将数据插入ES。最后使用ES客户端执行批量请求,将数据插入ES

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值