private static <R, S, P extends Message, Q extends Message, T extends Message>
    CompletableFuture<NavigableMap<byte[], S>>
    sumByRegion(AsyncTable<?> table, ColumnInterpreter<R, S, P, Q, T> ci, Scan scan) {
    CompletableFuture<NavigableMap<byte[], S>> future = new CompletableFuture<>();
    AggregateRequest req;
    try {
      req = validateArgAndGetPB(scan, ci, false, true);
    } catch (IOException e) {
      future.completeExceptionally(e);
      return future;
    }
    int firstPartIndex = scan.getFamilyMap().get(scan.getFamilies()[0]).size() - 1;
    AbstractAggregationCallback<NavigableMap<byte[], S>> callback =
      new AbstractAggregationCallback<>(future, req, AggregateService::getMedian) {

        private final NavigableMap<byte[], S> map =
          Collections.synchronizedNavigableMap(new TreeMap<>(Bytes.BYTES_COMPARATOR));

        @Override
        protected void aggregate(RegionInfo region, AggregateResponse resp) throws IOException {
          if (resp.getFirstPartCount() > 0) {
            map.put(region.getStartKey(), getPromotedValueFromProto(ci, resp, firstPartIndex));
          }
        }

        @Override
        protected NavigableMap<byte[], S> getFinalResult() {
          return map;
        }
      };
    table
      .coprocessorService(AggregateService::newStub,
        (stub, controller, rpcCallback) -> stub.getMedian(controller, req, rpcCallback), callback)
      .fromRow(nullToEmpty(scan.getStartRow()), scan.includeStartRow())
      .toRow(nullToEmpty(scan.getStopRow()), scan.includeStopRow()).execute();
    return future;
  }
This client class is for invoking the aggregate functions deployed on the Region Server side via
the AggregateService. This class will implement the supporting functionality for
summing/processing the individual results obtained from the AggregateService for each region.
hbase-endpoint/src/main/java/org/apache/hadoop/hbase/client/coprocessor/AsyncAggregationClient.java