@Override
  public void getStd(RpcController controller, AggregateRequest request,
    RpcCallback<AggregateResponse> done) {
    InternalScanner scanner = null;
    AggregateResponse response = null;
    PartialResultContext partialResultContext = new PartialResultContext();
    try {
      ColumnInterpreter<T, S, P, Q, R> ci = constructColumnInterpreterFromRequest(request);
      S sumVal = null, sumSqVal = null, tempVal = null;
      long rowCountVal = 0L;
      Scan scan = ProtobufUtil.toScan(request.getScan());
      scanner = env.getRegion().getScanner(scan);
      byte[] colFamily = scan.getFamilies()[0];
      NavigableSet<byte[]> qualifiers = scan.getFamilyMap().get(colFamily);
      byte[] qualifier = null;
      if (qualifiers != null && !qualifiers.isEmpty()) {
        qualifier = qualifiers.pollFirst();
      }
      List<Cell> results = new ArrayList<>();

      boolean hasMoreRows = true;

      do {
        if (shouldBreakForThrottling(request, scan, partialResultContext)) {
          break;
        }
        tempVal = null;
        hasMoreRows = scanner.next(results);
        int listSize = results.size();
        for (int i = 0; i < listSize; i++) {
          tempVal =
            ci.add(tempVal, ci.castToReturnType(ci.getValue(colFamily, qualifier, results.get(i))));
        }
        postScanPartialResultUpdate(results, partialResultContext);
        results.clear();
        sumVal = ci.add(sumVal, tempVal);
        sumSqVal = ci.add(sumSqVal, ci.multiply(tempVal, tempVal));
        rowCountVal++;
      } while (hasMoreRows);

      if (sumVal != null && !request.getClientSupportsPartialResult()) {
        AggregateResponse.Builder pair = AggregateResponse.newBuilder();
        ByteString first_sumVal = ci.getProtoForPromotedType(sumVal).toByteString();
        ByteString first_sumSqVal = ci.getProtoForPromotedType(sumSqVal).toByteString();
        pair.addFirstPart(first_sumVal);
        pair.addFirstPart(first_sumSqVal);
        ByteBuffer bb = ByteBuffer.allocate(8).putLong(rowCountVal);
        bb.rewind();
        pair.setSecondPart(ByteString.copyFrom(bb));
        response = pair.build();
      } else if (request.getClientSupportsPartialResult()) {
        AggregateResponse.Builder pair =
          responseBuilder(request, hasMoreRows, partialResultContext);
        if (sumVal != null) {
          ByteString first_sumVal = ci.getProtoForPromotedType(sumVal).toByteString();
          ByteString first_sumSqVal = ci.getProtoForPromotedType(sumSqVal).toByteString();
          pair.addFirstPart(first_sumVal);
          pair.addFirstPart(first_sumSqVal);
          ByteBuffer bb = ByteBuffer.allocate(8).putLong(rowCountVal);
          bb.rewind();
          pair.setSecondPart(ByteString.copyFrom(bb));
        }
        response = pair.build();
      }
    } catch (IOException e) {
      CoprocessorRpcUtils.setControllerException(controller, e);
    } finally {
      if (scanner != null) {
        IOUtils.closeQuietly(scanner);
      }
      closeQuota(partialResultContext);
    }
    done.run(response);
  }
Gives a Pair with first object a List containing Sum and sum of squares, and the second object
as row count. It is computed for a given combination of column qualifier and column family in
the given row range as defined in the Scan object. In its current implementation, it takes one
column family and one column qualifier (if provided). The idea is get the value of variance
first: the average of the squares less the square of the average a standard deviation is square
root of variance.
hbase-endpoint/src/main/java/org/apache/hadoop/hbase/coprocessor/AggregateImplementation.java