@Override
 public void writeTo(StreamOutput out) throws IOException {
   super.writeTo(out);
   out.writeVInt(shards.length);
   for (ShardSegments shard : shards) {
     shard.writeTo(out);
   }
 }
 @Override
 public void readFrom(StreamInput in) throws IOException {
   super.readFrom(in);
   shards = new ShardSegments[in.readVInt()];
   for (int i = 0; i < shards.length; i++) {
     shards[i] = ShardSegments.readShardSegments(in);
   }
 }
  IndexSegments(String index, ShardSegments[] shards) {
    this.index = index;

    Map<Integer, List<ShardSegments>> tmpIndexShards = Maps.newHashMap();
    for (ShardSegments shard : shards) {
      List<ShardSegments> lst = tmpIndexShards.get(shard.shardRouting().id());
      if (lst == null) {
        lst = Lists.newArrayList();
        tmpIndexShards.put(shard.shardRouting().id(), lst);
      }
      lst.add(shard);
    }
    indexShards = Maps.newHashMap();
    for (Map.Entry<Integer, List<ShardSegments>> entry : tmpIndexShards.entrySet()) {
      indexShards.put(
          entry.getKey(),
          new IndexShardSegments(
              entry.getValue().get(0).shardRouting().shardId(),
              entry.getValue().toArray(new ShardSegments[entry.getValue().size()])));
    }
  }
  public Map<String, IndexSegments> getIndices() {
    if (indicesSegments != null) {
      return indicesSegments;
    }
    Map<String, IndexSegments> indicesSegments = Maps.newHashMap();

    Set<String> indices = Sets.newHashSet();
    for (ShardSegments shard : shards) {
      indices.add(shard.getIndex());
    }

    for (String index : indices) {
      List<ShardSegments> shards = Lists.newArrayList();
      for (ShardSegments shard : this.shards) {
        if (shard.getShardRouting().index().equals(index)) {
          shards.add(shard);
        }
      }
      indicesSegments.put(
          index, new IndexSegments(index, shards.toArray(new ShardSegments[shards.size()])));
    }
    this.indicesSegments = indicesSegments;
    return indicesSegments;
  }
  @Override
  public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
    builder.startObject(Fields.INDICES);

    for (IndexSegments indexSegments : getIndices().values()) {
      builder.startObject(indexSegments.getIndex(), XContentBuilder.FieldCaseConversion.NONE);

      builder.startObject(Fields.SHARDS);
      for (IndexShardSegments indexSegment : indexSegments) {
        builder.startArray(Integer.toString(indexSegment.getShardId().id()));
        for (ShardSegments shardSegments : indexSegment) {
          builder.startObject();

          builder.startObject(Fields.ROUTING);
          builder.field(Fields.STATE, shardSegments.getShardRouting().state());
          builder.field(Fields.PRIMARY, shardSegments.getShardRouting().primary());
          builder.field(Fields.NODE, shardSegments.getShardRouting().currentNodeId());
          if (shardSegments.getShardRouting().relocatingNodeId() != null) {
            builder.field(
                Fields.RELOCATING_NODE, shardSegments.getShardRouting().relocatingNodeId());
          }
          builder.endObject();

          builder.field(Fields.NUM_COMMITTED_SEGMENTS, shardSegments.getNumberOfCommitted());
          builder.field(Fields.NUM_SEARCH_SEGMENTS, shardSegments.getNumberOfSearch());

          builder.startObject(Fields.SEGMENTS);
          for (Segment segment : shardSegments) {
            builder.startObject(segment.getName());
            builder.field(Fields.GENERATION, segment.getGeneration());
            builder.field(Fields.NUM_DOCS, segment.getNumDocs());
            builder.field(Fields.DELETED_DOCS, segment.getDeletedDocs());
            builder.byteSizeField(Fields.SIZE_IN_BYTES, Fields.SIZE, segment.getSizeInBytes());
            builder.byteSizeField(
                Fields.MEMORY_IN_BYTES, Fields.MEMORY, segment.getMemoryInBytes());
            builder.field(Fields.COMMITTED, segment.isCommitted());
            builder.field(Fields.SEARCH, segment.isSearch());
            if (segment.getVersion() != null) {
              builder.field(Fields.VERSION, segment.getVersion());
            }
            if (segment.isCompound() != null) {
              builder.field(Fields.COMPOUND, segment.isCompound());
            }
            if (segment.getMergeId() != null) {
              builder.field(Fields.MERGE_ID, segment.getMergeId());
            }
            if (segment.ramTree != null) {
              builder.startArray(Fields.RAM_TREE);
              for (Accountable child : segment.ramTree.getChildResources()) {
                toXContent(builder, child);
              }
              builder.endArray();
            }
            builder.endObject();
          }
          builder.endObject();

          builder.endObject();
        }
        builder.endArray();
      }
      builder.endObject();

      builder.endObject();
    }

    builder.endObject();
    return builder;
  }