docs: def split_input(cls, mapper_spec):
      """Inherit docs."""
      shard_count = mapper_spec.shard_count
      query_spec = cls._get_query_spec(mapper_spec)
  
      if not property_range.should_shard_by_property_range(query_spec.filters):
        return super(DatastoreInputReader, cls).split_input(mapper_spec)
  
      # Artificially increase the number of shards to get a more even split.
      # For example, if we are creating 7 shards for one week of data based on a
      # Day property and the data points tend to be clumped on certain days (say,
      # Monday and Wednesday), instead of assigning each shard a single day of
      # the week, we will split each day into "oversplit_factor" pieces, and
      # assign each shard "oversplit_factor" pieces with "1 / oversplit_factor"
      # the work, so that the data from Monday and Wednesday is more evenly
      # spread across all shards.
      oversplit_factor = query_spec.oversplit_factor
      oversplit_shard_count = oversplit_factor * shard_count
      p_range = property_range.PropertyRange(query_spec.filters,
                                             query_spec.model_class_path)
      p_ranges = p_range.split(oversplit_shard_count)
  
      # User specified a namespace.
      if query_spec.ns is not None:
        ns_range = namespace_range.NamespaceRange(
            namespace_start=query_spec.ns,
            namespace_end=query_spec.ns,
            _app=query_spec.app)
        ns_ranges = [copy.copy(ns_range) for _ in p_ranges]
      else:
        ns_keys = namespace_range.get_namespace_keys(
            query_spec.app, cls.MAX_NAMESPACES_FOR_KEY_SHARD+1)
        if not ns_keys:
          return
        # User doesn't specify ns but the number of ns is small.
        # We still split by property range.
        if len(ns_keys) <= cls.MAX_NAMESPACES_FOR_KEY_SHARD:
          ns_ranges = [namespace_range.NamespaceRange(_app=query_spec.app)
                       for _ in p_ranges]
        # Lots of namespaces. Split by ns.
        else:
          ns_ranges = namespace_range.NamespaceRange.split(n=oversplit_shard_count,
                                                           contiguous=False,
                                                           can_query=lambda: True,
                                                           _app=query_spec.app)
          p_ranges = [copy.copy(p_range) for _ in ns_ranges]
  
      assert len(p_ranges) == len(ns_ranges)
  
      iters = [
          db_iters.RangeIteratorFactory.create_property_range_iterator(
              p, ns, query_spec) for p, ns in zip(p_ranges, ns_ranges)]
  
      # Reduce the number of ranges back down to the shard count.
      # It's possible that we didn't split into enough shards even
      # after oversplitting, in which case we don't need to do anything.
      if len(iters) > shard_count:
        # We cycle through the iterators and chain them together, e.g.
        # if we look at the indices chained together, we get:
        # Shard #0 gets 0, num_shards, 2 * num_shards, ...
        # Shard #1 gets 1, num_shards + 1, 2 * num_shards + 1, ...
        # Shard #2 gets 2, num_shards + 2, 2 * num_shards + 2, ...
        # and so on. This should split fairly evenly.
        iters = [
          db_iters.RangeIteratorFactory.create_multi_property_range_iterator(
            [iters[i] for i in xrange(start_index, len(iters), shard_count)]
          ) for start_index in xrange(shard_count)
        ]
  
      return [cls(i) for i in iters]