public void testMiddleMaxMissingLast() throws Exception {
    Directory dir = newDirectory();
    RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
    Document doc = new Document();
    doc.add(newStringField("id", "3", Field.Store.YES));
    writer.addDocument(doc);
    doc = new Document();
    doc.add(new SortedSetDocValuesField("value", new BytesRef("a")));
    doc.add(new SortedSetDocValuesField("value", new BytesRef("b")));
    doc.add(new SortedSetDocValuesField("value", new BytesRef("c")));
    doc.add(new SortedSetDocValuesField("value", new BytesRef("d")));
    doc.add(newStringField("id", "1", Field.Store.YES));
    writer.addDocument(doc);
    doc = new Document();
    doc.add(new SortedSetDocValuesField("value", new BytesRef("b")));
    doc.add(newStringField("id", "2", Field.Store.YES));
    writer.addDocument(doc);
    IndexReader ir = writer.getReader();
    writer.close();

    // slow wrapper does not support random access ordinals (there is no need for that!)
    IndexSearcher searcher = newSearcher(ir, false);
    SortField sortField =
        new SortedSetSortField("value", false, SortedSetSortField.Selector.MIDDLE_MAX);
    sortField.setMissingValue(SortField.STRING_LAST);
    Sort sort = new Sort(sortField);

    TopDocs td = searcher.search(new MatchAllDocsQuery(), 10, sort);
    assertEquals(3, td.totalHits);
    // 'b' comes before 'c'
    assertEquals("2", searcher.doc(td.scoreDocs[0].doc).get("id"));
    assertEquals("1", searcher.doc(td.scoreDocs[1].doc).get("id"));
    // null comes last
    assertEquals("3", searcher.doc(td.scoreDocs[2].doc).get("id"));
    assertNoFieldCaches();

    ir.close();
    dir.close();
  }
  private SortField randomIndexSortField() {
    boolean reversed = random().nextBoolean();
    SortField sortField;
    switch (random().nextInt(10)) {
      case 0:
        sortField =
            new SortField(TestUtil.randomSimpleString(random()), SortField.Type.INT, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextInt());
        }
        break;
      case 1:
        sortField =
            new SortedNumericSortField(
                TestUtil.randomSimpleString(random()), SortField.Type.INT, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextInt());
        }
        break;

      case 2:
        sortField =
            new SortField(TestUtil.randomSimpleString(random()), SortField.Type.LONG, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextLong());
        }
        break;
      case 3:
        sortField =
            new SortedNumericSortField(
                TestUtil.randomSimpleString(random()), SortField.Type.LONG, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextLong());
        }
        break;
      case 4:
        sortField =
            new SortField(TestUtil.randomSimpleString(random()), SortField.Type.FLOAT, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextFloat());
        }
        break;
      case 5:
        sortField =
            new SortedNumericSortField(
                TestUtil.randomSimpleString(random()), SortField.Type.FLOAT, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextFloat());
        }
        break;
      case 6:
        sortField =
            new SortField(TestUtil.randomSimpleString(random()), SortField.Type.DOUBLE, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextDouble());
        }
        break;
      case 7:
        sortField =
            new SortedNumericSortField(
                TestUtil.randomSimpleString(random()), SortField.Type.DOUBLE, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(random().nextDouble());
        }
        break;
      case 8:
        sortField =
            new SortField(TestUtil.randomSimpleString(random()), SortField.Type.STRING, reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(SortField.STRING_LAST);
        }
        break;
      case 9:
        sortField = new SortedSetSortField(TestUtil.randomSimpleString(random()), reversed);
        if (random().nextBoolean()) {
          sortField.setMissingValue(SortField.STRING_LAST);
        }
        break;
      default:
        sortField = null;
        fail();
    }
    return sortField;
  }