code: def split_input(cls, job_config):
      
      shard_count = job_config.shard_count
      params = job_config.input_reader_params
      query_spec = cls._get_query_spec(params)
  
      namespaces = None
      if query_spec.ns is not None:
        k_ranges = cls._to_key_ranges_by_shard(
            query_spec.app, [query_spec.ns], shard_count, query_spec)
      else:
        ns_keys = namespace_range.get_namespace_keys(
            query_spec.app, cls.MAX_NAMESPACES_FOR_KEY_SHARD+1)
        # No namespace means the app may have some data but those data are not
        # visible yet. Just return.
        if not ns_keys:
          return
        # If the number of ns is small, we shard each ns by key and assign each
        # shard a piece of a ns.
        elif len(ns_keys) <= cls.MAX_NAMESPACES_FOR_KEY_SHARD:
          namespaces = [ns_key.name() or "" for ns_key in ns_keys]
          k_ranges = cls._to_key_ranges_by_shard(
              query_spec.app, namespaces, shard_count, query_spec)
        # When number of ns is large, we can only split lexicographically by ns.
        else:
          ns_ranges = namespace_range.NamespaceRange.split(n=shard_count,
                                                           contiguous=False,
                                                           can_query=lambda: True,
                                                           _app=query_spec.app)
          k_ranges = [key_ranges.KeyRangesFactory.create_from_ns_range(ns_range)
                      for ns_range in ns_ranges]
  
      iters = [db_iters.RangeIteratorFactory.create_key_ranges_iterator(
          r, query_spec, cls._KEY_RANGE_ITER_CLS) for r in k_ranges]
  
      return [cls(i) for i in iters]
docs: Inherit doc.