code: private List<Key> getScatterKeys(
        int numSplits, Query query, PartitionId partition, Datastore datastore)
        throws DatastoreException {
      Query.Builder scatterPointQuery = createScatterQuery(query, numSplits);
  
      List<Key> keySplits = new ArrayList<Key>();
  
      QueryResultBatch batch;
      do {
        RunQueryRequest scatterRequest =
            RunQueryRequest.newBuilder()
                .setPartitionId(partition)
                .setQuery(scatterPointQuery)
                .build();
        batch = datastore.runQuery(scatterRequest).getBatch();
        for (EntityResult result : batch.getEntityResultsList()) {
          keySplits.add(result.getEntity().getKey());
        }
        scatterPointQuery.setStartCursor(batch.getEndCursor());
        scatterPointQuery.getLimitBuilder().setValue(
            scatterPointQuery.getLimit().getValue() - batch.getEntityResultsCount());
      } while (batch.getMoreResults() == MoreResultsType.NOT_FINISHED);
      Collections.sort(keySplits, DatastoreHelper.getKeyComparator());
      return keySplits;
    }
docs: Gets a list of split keys given a desired number of splits.
  
  <p>This list will contain multiple split keys for each split. Only a single split key
  will be chosen as the split point, however providing multiple keys allows for more uniform
  sharding.
  
  @param numSplits the number of desired splits.
  @param query the user query.
  @param partition the partition to run the query in.
  @param datastore the datastore containing the data.
  @throws DatastoreException if there was an error when executing the datastore query.