/*
   * (non-Javadoc)
   *
   * @see
   * com.basho.riak.client.raw.RawClient#fetchIndex(com.basho.riak.client.
   * raw.query.IndexQuery)
   */
  public List<String> fetchIndex(IndexQuery indexQuery) throws IOException {
    final MapReduce mr = new IndexMapReduce(this, indexQuery);

    mr.addReducePhase(NamedErlangFunction.REDUCE_IDENTITY, Args.REDUCE_PHASE_ONLY_1);
    // only return the key, to match the http rest api
    mr.addReducePhase(
        new JSSourceFunction("function(v) { return v.map(function(e) { return e[1]; }); }"),
        Args.REDUCE_PHASE_ONLY_1);

    try {
      MapReduceResult result = mr.execute();
      return new ArrayList<String>(result.getResult(String.class));
    } catch (RiakException e) {
      throw new IOException(e);
    }
  }
  /**
   * Takes the results of running linkWalkFirstPhase and creates an m/r job from them
   *
   * @param firstPhaseResult the results of running linkWalkfirstPhase.
   * @return the results from the intermediate bkeys of phase one.
   * @throws IOException
   */
  private MapReduceResult linkWalkSecondPhase(final MapReduceResult firstPhaseResult)
      throws IOException {
    try {
      @SuppressWarnings("rawtypes")
      Collection<LinkedList> bkeys = firstPhaseResult.getResult(LinkedList.class);

      BucketKeyMapReduce mr = new BucketKeyMapReduce(this);
      int stepCnt = 0;

      for (LinkedList<List<String>> step : bkeys) {
        // TODO find a way to *enforce* order here (custom
        // deserializer?)
        stepCnt++;
        for (List<String> input : step) {
          // use the step count as key data so we can aggregate the
          // results into the correct steps when they come back
          mr.addInput(input.get(0), input.get(1), Integer.toString(stepCnt));
        }
      }

      mr.addReducePhase(new NamedErlangFunction("riak_kv_mapreduce", "reduce_set_union"), false);
      mr.addMapPhase(
          new JSSourceFunction("function(v, keyData) { return [{\"step\": keyData, \"v\": v}]; }"),
          true);

      return mr.execute();
    } catch (ConversionException e) {
      throw new IOException(e.getMessage());
    } catch (RiakException e) {
      throw (IOException) e.getCause();
    }
  }