Пример #1
0
 public void testSimpleBulk3() throws Exception {
   String bulkAction =
       copyToStringFromClasspath("/org/elasticsearch/action/bulk/simple-bulk3.json");
   BulkRequest bulkRequest = new BulkRequest();
   bulkRequest.add(
       bulkAction.getBytes(StandardCharsets.UTF_8), 0, bulkAction.length(), null, null);
   assertThat(bulkRequest.numberOfActions(), equalTo(3));
 }
Пример #2
0
  @Test
  public void testBulkRequest() {
    Connection db = getConnection();
    long app = getAppId();
    try {
      Record record;
      List<Record> records = new ArrayList<Record>();
      List<Long> ids = insertRecords();

      ResultSet rs = db.select(app, "order by Record_number asc");
      if (rs.size() != 3) {
        fail("invalid count");
      }
      int i = 0;
      while (rs.next()) {
        record = new Record();
        record.setId(rs.getId());
        record.setRevision(rs.getRevision());
        record.setString("Single_line_text", "hoge" + i);

        records.add(record);
        i++;
      }

      BulkRequest bulk = new BulkRequest();
      bulk.updateByRecords(app, records);

      records = new ArrayList<Record>();

      record = new Record();
      record.setString("Single_line_text", "fuga");
      records.add(record);
      record = new Record();
      record.setString("Single_line_text", "piyo");
      records.add(record);
      bulk.insert(app, records);

      bulk.delete(app, ids.get(1));

      db.bulkRequest(bulk);

      rs = db.select(app, "order by Record_number asc");
      if (rs.size() != 4) {
        fail("invalid count");
      }
      i = 0;
      String[] values = {"hoge0", "hoge2", "fuga", "piyo"};
      while (rs.next()) {
        if (!rs.getString("Single_line_text").equals(values[i])) {
          fail("invalid value:" + values[i]);
        }
        i++;
      }

    } catch (Exception e) {
      fail("db exception:" + e.getMessage());
    }
  }
Пример #3
0
 // issue 15120
 public void testBulkNoSource() throws Exception {
   BulkRequest bulkRequest = new BulkRequest();
   bulkRequest.add(new UpdateRequest("index", "type", "id"));
   bulkRequest.add(new IndexRequest("index", "type", "id"));
   ActionRequestValidationException validate = bulkRequest.validate();
   assertThat(validate, notNullValue());
   assertThat(validate.validationErrors(), not(empty()));
   assertThat(
       validate.validationErrors(), contains("script or doc is missing", "source is missing"));
 }
Пример #4
0
 public void testSimpleBulk4() throws Exception {
   String bulkAction =
       copyToStringFromClasspath("/org/elasticsearch/action/bulk/simple-bulk4.json");
   BulkRequest bulkRequest = new BulkRequest();
   bulkRequest.add(
       bulkAction.getBytes(StandardCharsets.UTF_8), 0, bulkAction.length(), null, null);
   assertThat(bulkRequest.numberOfActions(), equalTo(4));
   assertThat(((UpdateRequest) bulkRequest.requests().get(0)).id(), equalTo("1"));
   assertThat(((UpdateRequest) bulkRequest.requests().get(0)).retryOnConflict(), equalTo(2));
   assertThat(
       ((UpdateRequest) bulkRequest.requests().get(0)).doc().source().toUtf8(),
       equalTo("{\"field\":\"value\"}"));
   assertThat(((UpdateRequest) bulkRequest.requests().get(1)).id(), equalTo("0"));
   assertThat(((UpdateRequest) bulkRequest.requests().get(1)).type(), equalTo("type1"));
   assertThat(((UpdateRequest) bulkRequest.requests().get(1)).index(), equalTo("index1"));
   Script script = ((UpdateRequest) bulkRequest.requests().get(1)).script();
   assertThat(script, notNullValue());
   assertThat(script.getScript(), equalTo("counter += param1"));
   assertThat(script.getLang(), equalTo("javascript"));
   Map<String, Object> scriptParams = script.getParams();
   assertThat(scriptParams, notNullValue());
   assertThat(scriptParams.size(), equalTo(1));
   assertThat(((Integer) scriptParams.get("param1")), equalTo(1));
   assertThat(
       ((UpdateRequest) bulkRequest.requests().get(1)).upsertRequest().source().toUtf8(),
       equalTo("{\"counter\":1}"));
 }
Пример #5
0
 public void testBulkAddIterable() {
   BulkRequest bulkRequest = Requests.bulkRequest();
   List<ActionRequest<?>> requests = new ArrayList<>();
   requests.add(new IndexRequest("test", "test", "id").source("field", "value"));
   requests.add(new UpdateRequest("test", "test", "id").doc("field", "value"));
   requests.add(new DeleteRequest("test", "test", "id"));
   bulkRequest.add(requests);
   assertThat(bulkRequest.requests().size(), equalTo(3));
   assertThat(bulkRequest.requests().get(0), instanceOf(IndexRequest.class));
   assertThat(bulkRequest.requests().get(1), instanceOf(UpdateRequest.class));
   assertThat(bulkRequest.requests().get(2), instanceOf(DeleteRequest.class));
 }
Пример #6
0
 public void testSimpleBulk8() throws Exception {
   String bulkAction =
       copyToStringFromClasspath("/org/elasticsearch/action/bulk/simple-bulk8.json");
   BulkRequest bulkRequest = new BulkRequest();
   try {
     bulkRequest.add(
         bulkAction.getBytes(StandardCharsets.UTF_8), 0, bulkAction.length(), null, null);
     fail("should have thrown an exception about the unknown parameter _foo");
   } catch (IllegalArgumentException e) {
     assertThat(
         "message contains error about the unknown parameter _foo: " + e.getMessage(),
         e.getMessage().contains("Action/metadata line [3] contains an unknown parameter [_foo]"),
         equalTo(true));
   }
 }
    @Override
    public void messageReceived(final BulkRequest request, final TransportChannel channel)
        throws Exception {
      // no need to use threaded listener, since we just send a response
      request.listenerThreaded(false);
      execute(
          request,
          new ActionListener<BulkResponse>() {
            @Override
            public void onResponse(BulkResponse result) {
              try {
                channel.sendResponse(result);
              } catch (Exception e) {
                onFailure(e);
              }
            }

            @Override
            public void onFailure(Throwable e) {
              try {
                channel.sendResponse(e);
              } catch (Exception e1) {
                logger.warn(
                    "Failed to send error response for action ["
                        + TransportActions.BULK
                        + "] and request ["
                        + request
                        + "]",
                    e1);
              }
            }
          });
    }
Пример #8
0
 public void testSimpleBulk9() throws Exception {
   String bulkAction =
       copyToStringFromClasspath("/org/elasticsearch/action/bulk/simple-bulk9.json");
   BulkRequest bulkRequest = new BulkRequest();
   try {
     bulkRequest.add(
         bulkAction.getBytes(StandardCharsets.UTF_8), 0, bulkAction.length(), null, null);
     fail("should have thrown an exception about the wrong format of line 3");
   } catch (IllegalArgumentException e) {
     assertThat(
         "message contains error about the wrong format of line 3: " + e.getMessage(),
         e.getMessage()
             .contains(
                 "Malformed action/metadata line [3], expected START_OBJECT or END_OBJECT but found [START_ARRAY]"),
         equalTo(true));
   }
 }
Пример #9
0
 // issue 7361
 public void testBulkRequestWithRefresh() throws Exception {
   BulkRequest bulkRequest = new BulkRequest();
   // We force here a "id is missing" validation error
   bulkRequest.add(
       new DeleteRequest("index", "type", null).setRefreshPolicy(RefreshPolicy.IMMEDIATE));
   // We force here a "type is missing" validation error
   bulkRequest.add(new DeleteRequest("index", null, "id"));
   bulkRequest.add(
       new DeleteRequest("index", "type", "id").setRefreshPolicy(RefreshPolicy.IMMEDIATE));
   bulkRequest.add(
       new UpdateRequest("index", "type", "id")
           .doc("{}")
           .setRefreshPolicy(RefreshPolicy.IMMEDIATE));
   bulkRequest.add(
       new IndexRequest("index", "type", "id")
           .source("{}")
           .setRefreshPolicy(RefreshPolicy.IMMEDIATE));
   ActionRequestValidationException validate = bulkRequest.validate();
   assertThat(validate, notNullValue());
   assertThat(validate.validationErrors(), not(empty()));
   assertThat(
       validate.validationErrors(),
       contains(
           "RefreshPolicy is not supported on an item request. Set it on the BulkRequest instead.",
           "id is missing",
           "type is missing",
           "RefreshPolicy is not supported on an item request. Set it on the BulkRequest instead.",
           "RefreshPolicy is not supported on an item request. Set it on the BulkRequest instead.",
           "RefreshPolicy is not supported on an item request. Set it on the BulkRequest instead."));
 }
Пример #10
0
  public BulkResponse bulk(BulkRequest bulkRequest) throws Exception {
    StringBuffer sbf = new StringBuffer();
    for (SingleBulkRequest request : bulkRequest.getRequests()) {
      sbf.append("{");
      String header = JsonUtil.serialize(request);
      if (request instanceof DeleteRequest) {
        sbf.append("\"delete\":").append(header).append("}\n");
      }
      if (request instanceof IndexRequest) {
        sbf.append("\"index\":").append(header).append("}\n");
        // Index Request: header line + body
        sbf.append(((IndexRequest) request).content().replaceAll("\n", "")).append("\n");
      }
    }

    logger.trace("going to send a bulk");
    logger.trace("{}", sbf);

    StringEntity entity = new StringEntity(sbf.toString(), Charset.defaultCharset());
    Response restResponse = client.performRequest("POST", "/_bulk", Collections.emptyMap(), entity);
    BulkResponse response = JsonUtil.deserialize(restResponse, BulkResponse.class);
    logger.debug("bulk response: {}", response);
    return response;
  }
Пример #11
0
 public void testSimpleBulk1() throws Exception {
   String bulkAction =
       copyToStringFromClasspath("/org/elasticsearch/action/bulk/simple-bulk.json");
   // translate Windows line endings (\r\n) to standard ones (\n)
   if (Constants.WINDOWS) {
     bulkAction = Strings.replace(bulkAction, "\r\n", "\n");
   }
   BulkRequest bulkRequest = new BulkRequest();
   bulkRequest.add(
       bulkAction.getBytes(StandardCharsets.UTF_8), 0, bulkAction.length(), null, null);
   assertThat(bulkRequest.numberOfActions(), equalTo(3));
   assertThat(
       ((IndexRequest) bulkRequest.requests().get(0)).source().toBytes(),
       equalTo(new BytesArray("{ \"field1\" : \"value1\" }").toBytes()));
   assertThat(bulkRequest.requests().get(1), instanceOf(DeleteRequest.class));
   assertThat(
       ((IndexRequest) bulkRequest.requests().get(2)).source().toBytes(),
       equalTo(new BytesArray("{ \"field1\" : \"value3\" }").toBytes()));
 }
Пример #12
0
 public void testCannotAddNullRequests() throws Exception {
   BulkRequest bulkRequest = new BulkRequest();
   expectThrows(NullPointerException.class, () -> bulkRequest.add((IndexRequest) null));
   expectThrows(NullPointerException.class, () -> bulkRequest.add((UpdateRequest) null));
   expectThrows(NullPointerException.class, () -> bulkRequest.add((DeleteRequest) null));
 }
  private void executeBulk(
      final BulkRequest bulkRequest,
      final long startTime,
      final ActionListener<BulkResponse> listener,
      final AtomicArray<BulkItemResponse> responses) {
    final ClusterState clusterState = clusterService.state();
    // TODO use timeout to wait here if its blocked...
    clusterState.blocks().globalBlockedRaiseException(ClusterBlockLevel.WRITE);

    final ConcreteIndices concreteIndices =
        new ConcreteIndices(clusterState, indexNameExpressionResolver);
    MetaData metaData = clusterState.metaData();
    for (int i = 0; i < bulkRequest.requests.size(); i++) {
      ActionRequest request = bulkRequest.requests.get(i);
      if (request instanceof DocumentRequest) {
        DocumentRequest req = (DocumentRequest) request;

        if (addFailureIfIndexIsUnavailable(
            req, bulkRequest, responses, i, concreteIndices, metaData)) {
          continue;
        }

        String concreteIndex = concreteIndices.resolveIfAbsent(req);
        if (request instanceof IndexRequest) {
          IndexRequest indexRequest = (IndexRequest) request;
          MappingMetaData mappingMd = null;
          if (metaData.hasIndex(concreteIndex)) {
            mappingMd = metaData.index(concreteIndex).mappingOrDefault(indexRequest.type());
          }
          try {
            indexRequest.process(metaData, mappingMd, allowIdGeneration, concreteIndex);
          } catch (ElasticsearchParseException | RoutingMissingException e) {
            BulkItemResponse.Failure failure =
                new BulkItemResponse.Failure(
                    concreteIndex, indexRequest.type(), indexRequest.id(), e);
            BulkItemResponse bulkItemResponse = new BulkItemResponse(i, "index", failure);
            responses.set(i, bulkItemResponse);
            // make sure the request gets never processed again
            bulkRequest.requests.set(i, null);
          }
        } else {
          concreteIndices.resolveIfAbsent(req);
          req.routing(
              clusterState
                  .metaData()
                  .resolveIndexRouting(req.parent(), req.routing(), req.index()));
        }
      }
    }

    // first, go over all the requests and create a ShardId -> Operations mapping
    Map<ShardId, List<BulkItemRequest>> requestsByShard = new HashMap<>();

    for (int i = 0; i < bulkRequest.requests.size(); i++) {
      ActionRequest request = bulkRequest.requests.get(i);
      if (request instanceof IndexRequest) {
        IndexRequest indexRequest = (IndexRequest) request;
        String concreteIndex = concreteIndices.getConcreteIndex(indexRequest.index());
        ShardId shardId =
            clusterService
                .operationRouting()
                .indexShards(
                    clusterState,
                    concreteIndex,
                    indexRequest.type(),
                    indexRequest.id(),
                    indexRequest.routing())
                .shardId();
        List<BulkItemRequest> list = requestsByShard.get(shardId);
        if (list == null) {
          list = new ArrayList<>();
          requestsByShard.put(shardId, list);
        }
        list.add(new BulkItemRequest(i, request));
      } else if (request instanceof DeleteRequest) {
        DeleteRequest deleteRequest = (DeleteRequest) request;
        String concreteIndex = concreteIndices.getConcreteIndex(deleteRequest.index());
        MappingMetaData mappingMd =
            clusterState.metaData().index(concreteIndex).mappingOrDefault(deleteRequest.type());
        if (mappingMd != null
            && mappingMd.routing().required()
            && deleteRequest.routing() == null) {
          // if routing is required, and no routing on the delete request, we need to broadcast
          // it....
          GroupShardsIterator groupShards =
              clusterService.operationRouting().broadcastDeleteShards(clusterState, concreteIndex);
          for (ShardIterator shardIt : groupShards) {
            List<BulkItemRequest> list = requestsByShard.get(shardIt.shardId());
            if (list == null) {
              list = new ArrayList<>();
              requestsByShard.put(shardIt.shardId(), list);
            }
            list.add(new BulkItemRequest(i, deleteRequest));
          }
        } else {
          ShardId shardId =
              clusterService
                  .operationRouting()
                  .indexShards(
                      clusterState,
                      concreteIndex,
                      deleteRequest.type(),
                      deleteRequest.id(),
                      deleteRequest.routing())
                  .shardId();
          List<BulkItemRequest> list = requestsByShard.get(shardId);
          if (list == null) {
            list = new ArrayList<>();
            requestsByShard.put(shardId, list);
          }
          list.add(new BulkItemRequest(i, request));
        }
      } else if (request instanceof UpdateRequest) {
        UpdateRequest updateRequest = (UpdateRequest) request;
        String concreteIndex = concreteIndices.getConcreteIndex(updateRequest.index());
        MappingMetaData mappingMd =
            clusterState.metaData().index(concreteIndex).mappingOrDefault(updateRequest.type());
        if (mappingMd != null
            && mappingMd.routing().required()
            && updateRequest.routing() == null) {
          BulkItemResponse.Failure failure =
              new BulkItemResponse.Failure(
                  updateRequest.index(),
                  updateRequest.type(),
                  updateRequest.id(),
                  new IllegalArgumentException("routing is required for this item"));
          responses.set(i, new BulkItemResponse(i, updateRequest.type(), failure));
          continue;
        }
        ShardId shardId =
            clusterService
                .operationRouting()
                .indexShards(
                    clusterState,
                    concreteIndex,
                    updateRequest.type(),
                    updateRequest.id(),
                    updateRequest.routing())
                .shardId();
        List<BulkItemRequest> list = requestsByShard.get(shardId);
        if (list == null) {
          list = new ArrayList<>();
          requestsByShard.put(shardId, list);
        }
        list.add(new BulkItemRequest(i, request));
      }
    }

    if (requestsByShard.isEmpty()) {
      listener.onResponse(
          new BulkResponse(
              responses.toArray(new BulkItemResponse[responses.length()]),
              buildTookInMillis(startTime)));
      return;
    }

    final AtomicInteger counter = new AtomicInteger(requestsByShard.size());
    for (Map.Entry<ShardId, List<BulkItemRequest>> entry : requestsByShard.entrySet()) {
      final ShardId shardId = entry.getKey();
      final List<BulkItemRequest> requests = entry.getValue();
      BulkShardRequest bulkShardRequest =
          new BulkShardRequest(
              bulkRequest,
              shardId,
              bulkRequest.refresh(),
              requests.toArray(new BulkItemRequest[requests.size()]));
      bulkShardRequest.consistencyLevel(bulkRequest.consistencyLevel());
      bulkShardRequest.timeout(bulkRequest.timeout());
      shardBulkAction.execute(
          bulkShardRequest,
          new ActionListener<BulkShardResponse>() {
            @Override
            public void onResponse(BulkShardResponse bulkShardResponse) {
              for (BulkItemResponse bulkItemResponse : bulkShardResponse.getResponses()) {
                // we may have no response if item failed
                if (bulkItemResponse.getResponse() != null) {
                  bulkItemResponse.getResponse().setShardInfo(bulkShardResponse.getShardInfo());
                }
                responses.set(bulkItemResponse.getItemId(), bulkItemResponse);
              }
              if (counter.decrementAndGet() == 0) {
                finishHim();
              }
            }

            @Override
            public void onFailure(Throwable e) {
              // create failures for all relevant requests
              for (BulkItemRequest request : requests) {
                if (request.request() instanceof IndexRequest) {
                  IndexRequest indexRequest = (IndexRequest) request.request();
                  responses.set(
                      request.id(),
                      new BulkItemResponse(
                          request.id(),
                          indexRequest.opType().toString().toLowerCase(Locale.ENGLISH),
                          new BulkItemResponse.Failure(
                              concreteIndices.getConcreteIndex(indexRequest.index()),
                              indexRequest.type(),
                              indexRequest.id(),
                              e)));
                } else if (request.request() instanceof DeleteRequest) {
                  DeleteRequest deleteRequest = (DeleteRequest) request.request();
                  responses.set(
                      request.id(),
                      new BulkItemResponse(
                          request.id(),
                          "delete",
                          new BulkItemResponse.Failure(
                              concreteIndices.getConcreteIndex(deleteRequest.index()),
                              deleteRequest.type(),
                              deleteRequest.id(),
                              e)));
                } else if (request.request() instanceof UpdateRequest) {
                  UpdateRequest updateRequest = (UpdateRequest) request.request();
                  responses.set(
                      request.id(),
                      new BulkItemResponse(
                          request.id(),
                          "update",
                          new BulkItemResponse.Failure(
                              concreteIndices.getConcreteIndex(updateRequest.index()),
                              updateRequest.type(),
                              updateRequest.id(),
                              e)));
                }
              }
              if (counter.decrementAndGet() == 0) {
                finishHim();
              }
            }

            private void finishHim() {
              listener.onResponse(
                  new BulkResponse(
                      responses.toArray(new BulkItemResponse[responses.length()]),
                      buildTookInMillis(startTime)));
            }
          });
    }
  }
  @Override
  protected void doExecute(
      final BulkRequest bulkRequest, final ActionListener<BulkResponse> listener) {
    final long startTime = System.currentTimeMillis();
    final AtomicArray<BulkItemResponse> responses = new AtomicArray<>(bulkRequest.requests.size());

    if (autoCreateIndex.needToCheck()) {
      // Keep track of all unique indices and all unique types per index for the create index
      // requests:
      final Map<String, Set<String>> indicesAndTypes = new HashMap<>();
      for (ActionRequest request : bulkRequest.requests) {
        if (request instanceof DocumentRequest) {
          DocumentRequest req = (DocumentRequest) request;
          Set<String> types = indicesAndTypes.get(req.index());
          if (types == null) {
            indicesAndTypes.put(req.index(), types = new HashSet<>());
          }
          types.add(req.type());
        } else {
          throw new ElasticsearchException(
              "Parsed unknown request in bulk actions: " + request.getClass().getSimpleName());
        }
      }
      final AtomicInteger counter = new AtomicInteger(indicesAndTypes.size());
      ClusterState state = clusterService.state();
      for (Map.Entry<String, Set<String>> entry : indicesAndTypes.entrySet()) {
        final String index = entry.getKey();
        if (autoCreateIndex.shouldAutoCreate(index, state)) {
          CreateIndexRequest createIndexRequest = new CreateIndexRequest();
          createIndexRequest.index(index);
          for (String type : entry.getValue()) {
            createIndexRequest.mapping(type);
          }
          createIndexRequest.cause("auto(bulk api)");
          createIndexRequest.masterNodeTimeout(bulkRequest.timeout());
          createIndexAction.execute(
              createIndexRequest,
              new ActionListener<CreateIndexResponse>() {
                @Override
                public void onResponse(CreateIndexResponse result) {
                  if (counter.decrementAndGet() == 0) {
                    try {
                      executeBulk(bulkRequest, startTime, listener, responses);
                    } catch (Throwable t) {
                      listener.onFailure(t);
                    }
                  }
                }

                @Override
                public void onFailure(Throwable e) {
                  if (!(ExceptionsHelper.unwrapCause(e) instanceof IndexAlreadyExistsException)) {
                    // fail all requests involving this index, if create didnt work
                    for (int i = 0; i < bulkRequest.requests.size(); i++) {
                      ActionRequest request = bulkRequest.requests.get(i);
                      if (request != null
                          && setResponseFailureIfIndexMatches(responses, i, request, index, e)) {
                        bulkRequest.requests.set(i, null);
                      }
                    }
                  }
                  if (counter.decrementAndGet() == 0) {
                    try {
                      executeBulk(bulkRequest, startTime, listener, responses);
                    } catch (Throwable t) {
                      listener.onFailure(t);
                    }
                  }
                }
              });
        } else {
          if (counter.decrementAndGet() == 0) {
            executeBulk(bulkRequest, startTime, listener, responses);
          }
        }
      }
    } else {
      executeBulk(bulkRequest, startTime, listener, responses);
    }
  }
Пример #15
0
  private void executeBulk(
      final BulkRequest bulkRequest,
      final long startTime,
      final ActionListener<BulkResponse> listener) {
    ClusterState clusterState = clusterService.state();
    for (ActionRequest request : bulkRequest.requests) {
      if (request instanceof IndexRequest) {
        IndexRequest indexRequest = (IndexRequest) request;
        indexRequest.routing(
            clusterState
                .metaData()
                .resolveIndexRouting(indexRequest.routing(), indexRequest.index()));
        indexRequest.index(clusterState.metaData().concreteIndex(indexRequest.index()));
        if (allowIdGeneration) {
          if (indexRequest.id() == null) {
            indexRequest.id(UUID.randomBase64UUID());
            // since we generate the id, change it to CREATE
            indexRequest.opType(IndexRequest.OpType.CREATE);
          }
        }
      } else if (request instanceof DeleteRequest) {
        DeleteRequest deleteRequest = (DeleteRequest) request;
        deleteRequest.index(clusterState.metaData().concreteIndex(deleteRequest.index()));
      }
    }
    final BulkItemResponse[] responses = new BulkItemResponse[bulkRequest.requests.size()];

    // first, go over all the requests and create a ShardId -> Operations mapping
    Map<ShardId, List<BulkItemRequest>> requestsByShard = Maps.newHashMap();
    for (int i = 0; i < bulkRequest.requests.size(); i++) {
      ActionRequest request = bulkRequest.requests.get(i);
      if (request instanceof IndexRequest) {
        IndexRequest indexRequest = (IndexRequest) request;
        // handle routing
        MappingMetaData mappingMd =
            clusterState.metaData().index(indexRequest.index()).mapping(indexRequest.type());
        if (mappingMd != null) {
          try {
            indexRequest.processRouting(mappingMd);
          } catch (ElasticSearchException e) {
            responses[i] =
                new BulkItemResponse(
                    i,
                    indexRequest.opType().toString().toLowerCase(),
                    new BulkItemResponse.Failure(
                        indexRequest.index(),
                        indexRequest.type(),
                        indexRequest.id(),
                        e.getDetailedMessage()));
            continue;
          }
        }

        ShardId shardId =
            clusterService
                .operationRouting()
                .indexShards(
                    clusterState,
                    indexRequest.index(),
                    indexRequest.type(),
                    indexRequest.id(),
                    indexRequest.routing())
                .shardId();
        List<BulkItemRequest> list = requestsByShard.get(shardId);
        if (list == null) {
          list = Lists.newArrayList();
          requestsByShard.put(shardId, list);
        }
        list.add(new BulkItemRequest(i, request));
      } else if (request instanceof DeleteRequest) {
        DeleteRequest deleteRequest = (DeleteRequest) request;
        MappingMetaData mappingMd =
            clusterState.metaData().index(deleteRequest.index()).mapping(deleteRequest.type());
        if (mappingMd != null
            && mappingMd.routing().required()
            && deleteRequest.routing() == null) {
          // if routing is required, and no routing on the delete request, we need to broadcast
          // it....
          GroupShardsIterator groupShards =
              clusterService
                  .operationRouting()
                  .broadcastDeleteShards(clusterState, deleteRequest.index());
          for (ShardIterator shardIt : groupShards) {
            List<BulkItemRequest> list = requestsByShard.get(shardIt.shardId());
            if (list == null) {
              list = Lists.newArrayList();
              requestsByShard.put(shardIt.shardId(), list);
            }
            list.add(new BulkItemRequest(i, request));
          }
        } else {
          ShardId shardId =
              clusterService
                  .operationRouting()
                  .deleteShards(
                      clusterState,
                      deleteRequest.index(),
                      deleteRequest.type(),
                      deleteRequest.id(),
                      deleteRequest.routing())
                  .shardId();
          List<BulkItemRequest> list = requestsByShard.get(shardId);
          if (list == null) {
            list = Lists.newArrayList();
            requestsByShard.put(shardId, list);
          }
          list.add(new BulkItemRequest(i, request));
        }
      }
    }

    if (requestsByShard.isEmpty()) {
      listener.onResponse(new BulkResponse(responses, System.currentTimeMillis() - startTime));
      return;
    }

    final AtomicInteger counter = new AtomicInteger(requestsByShard.size());
    for (Map.Entry<ShardId, List<BulkItemRequest>> entry : requestsByShard.entrySet()) {
      final ShardId shardId = entry.getKey();
      final List<BulkItemRequest> requests = entry.getValue();
      BulkShardRequest bulkShardRequest =
          new BulkShardRequest(
              shardId.index().name(),
              shardId.id(),
              bulkRequest.refresh(),
              requests.toArray(new BulkItemRequest[requests.size()]));
      bulkShardRequest.replicationType(bulkRequest.replicationType());
      bulkShardRequest.consistencyLevel(bulkRequest.consistencyLevel());
      shardBulkAction.execute(
          bulkShardRequest,
          new ActionListener<BulkShardResponse>() {
            @Override
            public void onResponse(BulkShardResponse bulkShardResponse) {
              synchronized (responses) {
                for (BulkItemResponse bulkItemResponse : bulkShardResponse.responses()) {
                  responses[bulkItemResponse.itemId()] = bulkItemResponse;
                }
              }
              if (counter.decrementAndGet() == 0) {
                finishHim();
              }
            }

            @Override
            public void onFailure(Throwable e) {
              // create failures for all relevant requests
              String message = ExceptionsHelper.detailedMessage(e);
              synchronized (responses) {
                for (BulkItemRequest request : requests) {
                  if (request.request() instanceof IndexRequest) {
                    IndexRequest indexRequest = (IndexRequest) request.request();
                    responses[request.id()] =
                        new BulkItemResponse(
                            request.id(),
                            indexRequest.opType().toString().toLowerCase(),
                            new BulkItemResponse.Failure(
                                indexRequest.index(),
                                indexRequest.type(),
                                indexRequest.id(),
                                message));
                  } else if (request.request() instanceof DeleteRequest) {
                    DeleteRequest deleteRequest = (DeleteRequest) request.request();
                    responses[request.id()] =
                        new BulkItemResponse(
                            request.id(),
                            "delete",
                            new BulkItemResponse.Failure(
                                deleteRequest.index(),
                                deleteRequest.type(),
                                deleteRequest.id(),
                                message));
                  }
                }
              }
              if (counter.decrementAndGet() == 0) {
                finishHim();
              }
            }

            private void finishHim() {
              listener.onResponse(
                  new BulkResponse(responses, System.currentTimeMillis() - startTime));
            }
          });
    }
  }