docs: def _split_ns_by_scatter(cls,
                             shard_count,
                             namespace,
                             raw_entity_kind,
                             filters,
                             app):
      """Split a namespace by scatter index into key_range.KeyRange.
  
      TODO(user): Power this with key_range.KeyRange.compute_split_points.
  
      Args:
        shard_count: number of shards.
        namespace: namespace name to split. str.
        raw_entity_kind: low level datastore API entity kind.
        app: app id in str.
  
      Returns:
        A list of key_range.KeyRange objects. If there are not enough entities to
      splits into requested shards, the returned list will contain KeyRanges
      ordered lexicographically with any Nones appearing at the end.
      """
      if shard_count == 1:
        # With one shard we don't need to calculate any split points at all.
        return [key_range.KeyRange(namespace=namespace, _app=app)]
  
      ds_query = datastore.Query(kind=raw_entity_kind,
                                 namespace=namespace,
                                 _app=app,
                                 keys_only=True)
      ds_query.Order("__scatter__")
      oversampling_factor = 32
      random_keys = None
      if filters:
        ds_query_with_filters = copy.copy(ds_query)
        for (key, op, value) in filters:
          ds_query_with_filters.update({'%s %s' % (key, op): value})
          try:
            random_keys = ds_query_with_filters.Get(shard_count *
                                                    oversampling_factor)
          except db.NeedIndexError, why:
            logging.warning('Need to add an index for optimal mapreduce-input'
                            ' splitting:\n%s' % why)
            # We'll try again without the filter.  We hope the filter
            # will filter keys uniformly across the key-name space!
  
      if not random_keys:
        random_keys = ds_query.Get(shard_count * oversampling_factor)
  
      if not random_keys:
        # There are no entities with scatter property. We have no idea
        # how to split.
        return ([key_range.KeyRange(namespace=namespace, _app=app)] +
                [None] * (shard_count - 1))
  
      random_keys.sort()
  
      if len(random_keys) >= shard_count:
        # We've got a lot of scatter values. Sample them down.
        random_keys = cls._choose_split_points(random_keys, shard_count)
  
      k_ranges = []
  
      k_ranges.append(key_range.KeyRange(
          key_start=None,
          key_end=random_keys[0],
          direction=key_range.KeyRange.ASC,
          include_start=False,
          include_end=False,
          namespace=namespace,
          _app=app))
  
      for i in range(0, len(random_keys) - 1):
        k_ranges.append(key_range.KeyRange(
            key_start=random_keys[i],
            key_end=random_keys[i+1],
            direction=key_range.KeyRange.ASC,
            include_start=True,
            include_end=False,
            namespace=namespace,
            _app=app))
  
      k_ranges.append(key_range.KeyRange(
          key_start=random_keys[-1],
          key_end=None,
          direction=key_range.KeyRange.ASC,
          include_start=True,
          include_end=False,
          namespace=namespace,
          _app=app))
  
      if len(k_ranges) < shard_count:
        # We need to have as many shards as it was requested. Add some Nones.
        k_ranges += [None] * (shard_count - len(k_ranges))
      return k_ranges