def secondary_sort(start_index, end_index)
      @job.set_partitioner_class(Hadoop::Mapreduce::Lib::Partition::BinaryPartitioner)
      Hadoop::Mapreduce::Lib::Partition::BinaryPartitioner.set_offsets(@job.configuration, start_index, end_index)
      @job.set_grouping_comparator_class(Humboldt::JavaLib::BinaryComparator)
      Humboldt::JavaLib::BinaryComparator.set_offsets(@job.configuration, start_index, end_index)
    end
def secondary_sort(start_index, end_index)
      @job.set_partitioner_class(Hadoop::Mapreduce::Lib::Partition::BinaryPartitioner)
      Hadoop::Mapreduce::Lib::Partition::BinaryPartitioner.set_offsets(@job.configuration, start_index, end_index)
      @job.set_grouping_comparator_class(Humboldt::JavaLib::BinaryComparator)
      Humboldt::JavaLib::BinaryComparator.set_offsets(@job.configuration, start_index, end_index)
    end
Configures the job for secondary sort on the specified slice of the mapper
 output key.

 Hadoop comes with a partitioner that can partition the map output based
 on a slice of the map output key. Humboldt ships with a comparator that
 uses the same configuration. Together they can be used to implement
 secondary sort.

 Secondary sort is a mapreduce pattern where you emit a key, but partition
 and group only on a subset of that key. This has the result that each
 reduce invocation will see values grouped by the subset, but ordered by
 the whole key. It is used, among other things, to efficiently count
 distinct values.

 Say you want to count the number of distinct visitors to a site. Your
 input is pairs of site and visitor IDs. The naïve implementation is to
 emit the site as key and the visitor ID as value and then, in the reducer,
 collect all IDs in a set, and emit the site and the size of the set of IDs.
 This is very memory inefficient, and impractical. For any interesting
 amount of data you will not be able to keep all the visitor IDs in memory.

 What you do, instead, is to concatenate the site and visitor ID and emit
 that as key, and the visitor ID as value. It might seem wasteful to emit
 the visitor ID twice, but it's necessary since Hadoop will only give you
 the key for the first value in each group.

 You then instruct Hadoop to partition and group on just the site part of
 the key. Hadoop will still sort the values by their full key, so within
 each group the values will be sorted by visitor ID. In the reducer it's
 now trivial to loop over the values and just increment a counter each time
 the visitor ID changes.

 You configure which part of the key to partition and group by specifying
 the start and end _indexes_. The reason why they are indexes and not a
 start index and a length, like Ruby's `String#slice`, is that you also can
 use negative indexes to count from the end. Negative indexes are useful
 for example when you don't know how wide the part of the key that you want
 use is. In the example above if you use the domain to identify sites these
 can be of different length. If your visitor IDs are 20 characters you can
 use 0 and -21 as your indexes.

 @param [Fixnum] start_index The first index of the slice, negative numbers
   are counted from the end
 @param [Fixnum] end_index The last index of the slice, negative numbers
   are counted from the end
 @see http://hadoop.apache.org/docs/r2.7.1/api/org/apache/hadoop/mapreduce/lib/partition/BinaryPartitioner.html Hadoop's BinaryPartitioner