Example usage for org.apache.lucene.search Sort getSort

List of usage examples for org.apache.lucene.search Sort getSort

Introduction

In this page you can find the example usage for org.apache.lucene.search Sort getSort.

Prototype

public SortField[] getSort() 

Source Link

Document

Representation of the sort criteria.

Usage

From source file:org.apache.jackrabbit.core.query.lucene.ChildAxisQuery.java

License:Apache License

/**
 * {@inheritDoc}/*  w w  w . java2s  . c om*/
 */
public QueryHits execute(JackrabbitIndexSearcher searcher, SessionImpl session, Sort sort) throws IOException {
    if (sort.getSort().length == 0 && matchesAnyChildNode()) {
        Query context = getContextQuery();
        return new ChildNodesQueryHits(searcher.evaluate(context), session);
    } else {
        return null;
    }
}

From source file:org.apache.jackrabbit.core.query.lucene.DescendantSelfAxisQuery.java

License:Apache License

/**
 * {@inheritDoc}/*from w w  w . java  2  s. co  m*/
 */
public QueryHits execute(final JackrabbitIndexSearcher searcher, final SessionImpl session, final Sort sort)
        throws IOException {
    if (sort.getSort().length == 0 && subQueryMatchesAll()) {
        // maps path String to ScoreNode
        Map<String, ScoreNode> startingPoints = new TreeMap<String, ScoreNode>();
        QueryHits result = searcher.evaluate(getContextQuery());
        try {
            // minLevels 0 and 1 are handled with a series of
            // NodeTraversingQueryHits directly on result. For minLevels >= 2
            // intermediate ChildNodesQueryHits are required.
            for (int i = 2; i <= getMinLevels(); i++) {
                result = new ChildNodesQueryHits(result, session);
            }

            ScoreNode sn;
            while ((sn = result.nextScoreNode()) != null) {
                NodeId id = sn.getNodeId();
                try {
                    Node node = session.getNodeById(id);
                    startingPoints.put(node.getPath(), sn);
                } catch (ItemNotFoundException e) {
                    // JCR-3001 access denied to score node, will just skip it
                    log.warn("Access denied to node id {}.", id);
                } catch (RepositoryException e) {
                    throw Util.createIOException(e);
                }
            }
        } finally {
            result.close();
        }

        // prune overlapping starting points
        String previousPath = null;
        for (Iterator<String> it = startingPoints.keySet().iterator(); it.hasNext();) {
            String path = it.next();
            // if the previous path is a prefix of this path then the
            // current path is obsolete
            if (previousPath != null && path.startsWith(previousPath)) {
                it.remove();
            } else {
                previousPath = path;
            }
        }

        final Iterator<ScoreNode> scoreNodes = startingPoints.values().iterator();
        return new AbstractQueryHits() {

            private NodeTraversingQueryHits currentTraversal;

            {
                fetchNextTraversal();
            }

            public void close() throws IOException {
                if (currentTraversal != null) {
                    currentTraversal.close();
                }
            }

            public ScoreNode nextScoreNode() throws IOException {
                while (currentTraversal != null) {
                    ScoreNode sn = currentTraversal.nextScoreNode();
                    if (sn != null) {
                        return sn;
                    } else {
                        fetchNextTraversal();
                    }
                }
                // if we get here there are no more score nodes
                return null;
            }

            private void fetchNextTraversal() throws IOException {
                if (currentTraversal != null) {
                    currentTraversal.close();
                }
                currentTraversal = null;
                // We only need one node, but because of the acls, we'll
                // iterate until we find a good one
                while (scoreNodes.hasNext()) {
                    ScoreNode sn = scoreNodes.next();
                    NodeId id = sn.getNodeId();
                    try {
                        Node node = session.getNodeById(id);
                        currentTraversal = new NodeTraversingQueryHits(node, getMinLevels() == 0);
                        break;
                    } catch (ItemNotFoundException e) {
                        // JCR-3001 node access denied, will just skip it
                        log.warn("Access denied to node id {}.", id);
                    } catch (RepositoryException e) {
                        throw Util.createIOException(e);
                    }
                }
            }
        };
    } else {
        return null;
    }
}

From source file:org.apache.jackrabbit.core.query.lucene.JackrabbitIndexSearcher.java

License:Apache License

/**
 * Evaluates the query and returns the hits that match the query.
 *
 * @param query           the query to execute.
 * @param sort            the sort criteria.
 * @param resultFetchHint a hint on how many results should be fetched.
 * @return the query hits.//from   w  w w  .  ja  v a  2  s.  co m
 * @throws IOException if an error occurs while executing the query.
 */
public QueryHits evaluate(Query query, Sort sort, long resultFetchHint) throws IOException {
    query = query.rewrite(reader);
    QueryHits hits = null;
    if (query instanceof JackrabbitQuery) {
        hits = ((JackrabbitQuery) query).execute(this, session, sort);
    }
    if (hits == null) {
        if (sort.getSort().length == 0) {
            hits = new LuceneQueryHits(reader, this, query);
        } else {
            hits = new SortedLuceneQueryHits(this, query, sort, resultFetchHint);
        }
    }
    return hits;
}

From source file:org.apache.jackrabbit.core.query.lucene.MatchAllDocsQuery.java

License:Apache License

/**
 * {@inheritDoc}/*from w  w  w .j a  v a  2  s  .com*/
 */
public QueryHits execute(JackrabbitIndexSearcher searcher, SessionImpl session, Sort sort) throws IOException {
    if (sort.getSort().length == 0) {
        try {
            return new NodeTraversingQueryHits(session.getRootNode(), true);
        } catch (RepositoryException e) {
            throw Util.createIOException(e);
        }
    } else {
        return null;
    }
}

From source file:org.apache.jackrabbit.core.query.lucene.QueryHitsQuery.java

License:Apache License

/**
 * {@inheritDoc}/*  w w  w  . jav a2 s  . c  o  m*/
 */
public QueryHits execute(JackrabbitIndexSearcher searcher, SessionImpl session, Sort sort) throws IOException {
    if (sort.getSort().length == 0) {
        return hits;
    } else {
        return null;
    }
}

From source file:org.apache.solr.handler.component.HelloHandlerComponent.java

License:Apache License

protected void doFieldSortValues(ResponseBuilder rb, SolrIndexSearcher searcher) throws IOException {
    SolrQueryRequest req = rb.req;//  w  w  w .  j a  v a  2 s.c om
    SolrQueryResponse rsp = rb.rsp;
    final CharsRef spare = new CharsRef();
    // The query cache doesn't currently store sort field values, and SolrIndexSearcher doesn't
    // currently have an option to return sort field values.  Because of this, we
    // take the documents given and re-derive the sort values.
    boolean fsv = req.getParams().getBool(ResponseBuilder.FIELD_SORT_VALUES, false);
    if (fsv) {
        Sort sort = searcher.weightSort(rb.getSortSpec().getSort());
        SortField[] sortFields = sort == null ? new SortField[] { SortField.FIELD_SCORE } : sort.getSort();
        NamedList<Object[]> sortVals = new NamedList<Object[]>(); // order is important for the sort fields
        Field field = new StringField("dummy", "", Field.Store.NO); // a dummy Field
        IndexReaderContext topReaderContext = searcher.getTopReaderContext();
        List<AtomicReaderContext> leaves = topReaderContext.leaves();
        AtomicReaderContext currentLeaf = null;
        if (leaves.size() == 1) {
            // if there is a single segment, use that subReader and avoid looking up each time
            currentLeaf = leaves.get(0);
            leaves = null;
        }

        DocList docList = rb.getResults().docList;

        // sort ids from lowest to highest so we can access them in order
        int nDocs = docList.size();
        long[] sortedIds = new long[nDocs];
        DocIterator it = rb.getResults().docList.iterator();
        for (int i = 0; i < nDocs; i++) {
            sortedIds[i] = (((long) it.nextDoc()) << 32) | i;
        }
        Arrays.sort(sortedIds);

        for (SortField sortField : sortFields) {
            SortField.Type type = sortField.getType();
            if (type == SortField.Type.SCORE || type == SortField.Type.DOC)
                continue;

            FieldComparator comparator = null;

            String fieldname = sortField.getField();
            FieldType ft = fieldname == null ? null : req.getSchema().getFieldTypeNoEx(fieldname);

            Object[] vals = new Object[nDocs];

            int lastIdx = -1;
            int idx = 0;

            for (long idAndPos : sortedIds) {
                int doc = (int) (idAndPos >>> 32);
                int position = (int) idAndPos;

                if (leaves != null) {
                    idx = ReaderUtil.subIndex(doc, leaves);
                    currentLeaf = leaves.get(idx);
                    if (idx != lastIdx) {
                        // we switched segments.  invalidate comparator.
                        comparator = null;
                    }
                }

                if (comparator == null) {
                    comparator = sortField.getComparator(1, 0);
                    comparator = comparator.setNextReader(currentLeaf);
                }

                doc -= currentLeaf.docBase; // adjust for what segment this is in
                comparator.copy(0, doc);
                Object val = comparator.value(0);

                // Sortable float, double, int, long types all just use a string
                // comparator. For these, we need to put the type into a readable
                // format.  One reason for this is that XML can't represent all
                // string values (or even all unicode code points).
                // indexedToReadable() should be a no-op and should
                // thus be harmless anyway (for all current ways anyway)
                if (val instanceof String) {
                    field.setStringValue((String) val);
                    val = ft.toObject(field);
                }

                // Must do the same conversion when sorting by a
                // String field in Lucene, which returns the terms
                // data as BytesRef:
                if (val instanceof BytesRef) {
                    UnicodeUtil.UTF8toUTF16((BytesRef) val, spare);
                    field.setStringValue(spare.toString());
                    val = ft.toObject(field);
                }

                vals[position] = val;
            }

            sortVals.add(fieldname, vals);
        }

        rsp.add("sort_values", sortVals);
    }
}

From source file:org.apache.solr.handler.component.HelloHandlerComponent.java

License:Apache License

private void mergeIds(ResponseBuilder rb, ShardRequest sreq) {
    SortSpec ss = rb.getSortSpec();//from   w  w  w  . j av a2 s . c om
    Sort sort = ss.getSort();

    SortField[] sortFields = null;
    if (sort != null)
        sortFields = sort.getSort();
    else {
        sortFields = new SortField[] { SortField.FIELD_SCORE };
    }

    SchemaField uniqueKeyField = rb.req.getSchema().getUniqueKeyField();

    // id to shard mapping, to eliminate any accidental dups
    HashMap<Object, String> uniqueDoc = new HashMap<Object, String>();

    // Merge the docs via a priority queue so we don't have to sort *all* of the
    // documents... we only need to order the top (rows+start)
    ShardFieldSortedHitQueue queue;
    queue = new ShardFieldSortedHitQueue(sortFields, ss.getOffset() + ss.getCount());

    NamedList<Object> shardInfo = null;
    if (rb.req.getParams().getBool(ShardParams.SHARDS_INFO, false)) {
        shardInfo = new SimpleOrderedMap<Object>();
        rb.rsp.getValues().add(ShardParams.SHARDS_INFO, shardInfo);
    }

    long numFound = 0;
    Float maxScore = null;
    boolean partialResults = false;
    for (ShardResponse srsp : sreq.responses) {
        SolrDocumentList docs = null;

        if (shardInfo != null) {
            SimpleOrderedMap<Object> nl = new SimpleOrderedMap<Object>();

            if (srsp.getException() != null) {
                Throwable t = srsp.getException();
                if (t instanceof SolrServerException) {
                    t = ((SolrServerException) t).getCause();
                }
                nl.add("error", t.toString());
                StringWriter trace = new StringWriter();
                t.printStackTrace(new PrintWriter(trace));
                nl.add("trace", trace.toString());
            } else {
                docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
                nl.add("numFound", docs.getNumFound());
                nl.add("maxScore", docs.getMaxScore());
            }
            if (srsp.getSolrResponse() != null) {
                nl.add("time", srsp.getSolrResponse().getElapsedTime());
            }

            shardInfo.add(srsp.getShard(), nl);
        }
        // now that we've added the shard info, let's only proceed if we have no error.
        if (srsp.getException() != null) {
            continue;
        }

        if (docs == null) { // could have been initialized in the shards info block above
            docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
        }

        NamedList<?> responseHeader = (NamedList<?>) srsp.getSolrResponse().getResponse().get("responseHeader");
        if (responseHeader != null && Boolean.TRUE.equals(responseHeader.get("partialResults"))) {
            partialResults = true;
        }

        // calculate global maxScore and numDocsFound
        if (docs.getMaxScore() != null) {
            maxScore = maxScore == null ? docs.getMaxScore() : Math.max(maxScore, docs.getMaxScore());
        }
        numFound += docs.getNumFound();

        NamedList sortFieldValues = (NamedList) (srsp.getSolrResponse().getResponse().get("sort_values"));

        // go through every doc in this response, construct a ShardDoc, and
        // put it in the priority queue so it can be ordered.
        for (int i = 0; i < docs.size(); i++) {
            SolrDocument doc = docs.get(i);
            Object id = doc.getFieldValue(uniqueKeyField.getName());

            String prevShard = uniqueDoc.put(id, srsp.getShard());
            if (prevShard != null) {
                // duplicate detected
                numFound--;

                // For now, just always use the first encountered since we can't currently
                // remove the previous one added to the priority queue.  If we switched
                // to the Java5 PriorityQueue, this would be easier.
                continue;
                // make which duplicate is used deterministic based on shard
                // if (prevShard.compareTo(srsp.shard) >= 0) {
                //  TODO: remove previous from priority queue
                //  continue;
                // }
            }

            ShardDoc shardDoc = new ShardDoc();
            shardDoc.id = id;
            shardDoc.shard = srsp.getShard();
            shardDoc.orderInShard = i;
            Object scoreObj = doc.getFieldValue("score");
            if (scoreObj != null) {
                if (scoreObj instanceof String) {
                    shardDoc.score = Float.parseFloat((String) scoreObj);
                } else {
                    shardDoc.score = (Float) scoreObj;
                }
            }

            shardDoc.sortFieldValues = sortFieldValues;

            queue.insertWithOverflow(shardDoc);
        } // end for-each-doc-in-response
    } // end for-each-response

    // The queue now has 0 -> queuesize docs, where queuesize <= start + rows
    // So we want to pop the last documents off the queue to get
    // the docs offset -> queuesize
    int resultSize = queue.size() - ss.getOffset();
    resultSize = Math.max(0, resultSize); // there may not be any docs in range

    Map<Object, ShardDoc> resultIds = new HashMap<Object, ShardDoc>();
    for (int i = resultSize - 1; i >= 0; i--) {
        ShardDoc shardDoc = queue.pop();
        shardDoc.positionInResponse = i;
        // Need the toString() for correlation with other lists that must
        // be strings (like keys in highlighting, explain, etc)
        resultIds.put(shardDoc.id.toString(), shardDoc);
    }

    // Add hits for distributed requests
    // https://issues.apache.org/jira/browse/SOLR-3518
    rb.rsp.addToLog("hits", numFound);

    SolrDocumentList responseDocs = new SolrDocumentList();
    if (maxScore != null)
        responseDocs.setMaxScore(maxScore);
    responseDocs.setNumFound(numFound);
    responseDocs.setStart(ss.getOffset());
    // size appropriately
    for (int i = 0; i < resultSize; i++)
        responseDocs.add(null);

    // save these results in a private area so we can access them
    // again when retrieving stored fields.
    // TODO: use ResponseBuilder (w/ comments) or the request context?
    rb.resultIds = resultIds;
    rb._responseDocs = responseDocs;
    if (partialResults) {
        rb.rsp.getResponseHeader().add("partialResults", Boolean.TRUE);
    }
}

From source file:org.apache.solr.handler.component.QueryComponent.java

License:Apache License

protected void doFieldSortValues(ResponseBuilder rb, SolrIndexSearcher searcher) throws IOException {
    SolrQueryRequest req = rb.req;/*from   ww  w. ja v  a 2 s.c o  m*/
    SolrQueryResponse rsp = rb.rsp;
    final CharsRef spare = new CharsRef();
    // The query cache doesn't currently store sort field values, and SolrIndexSearcher doesn't
    // currently have an option to return sort field values.  Because of this, we
    // take the documents given and re-derive the sort values.
    boolean fsv = req.getParams().getBool(ResponseBuilder.FIELD_SORT_VALUES, false);
    if (fsv) {
        Sort sort = searcher.weightSort(rb.getSortSpec().getSort());
        SortField[] sortFields = sort == null ? new SortField[] { SortField.FIELD_SCORE } : sort.getSort();
        NamedList<Object[]> sortVals = new NamedList<Object[]>(); // order is important for the sort fields
        Field field = new StringField("dummy", "", Field.Store.NO); // a dummy Field
        IndexReaderContext topReaderContext = searcher.getTopReaderContext();
        List<AtomicReaderContext> leaves = topReaderContext.leaves();
        AtomicReaderContext currentLeaf = null;
        if (leaves.size() == 1) {
            // if there is a single segment, use that subReader and avoid looking up each time
            currentLeaf = leaves.get(0);
            leaves = null;
        }

        DocList docList = rb.getResults().docList;

        // sort ids from lowest to highest so we can access them in order
        int nDocs = docList.size();
        long[] sortedIds = new long[nDocs];
        DocIterator it = rb.getResults().docList.iterator();
        for (int i = 0; i < nDocs; i++) {
            sortedIds[i] = (((long) it.nextDoc()) << 32) | i;
        }
        Arrays.sort(sortedIds);

        for (SortField sortField : sortFields) {
            SortField.Type type = sortField.getType();
            if (type == SortField.Type.SCORE || type == SortField.Type.DOC)
                continue;

            FieldComparator comparator = null;

            String fieldname = sortField.getField();
            FieldType ft = fieldname == null ? null : searcher.getSchema().getFieldTypeNoEx(fieldname);

            Object[] vals = new Object[nDocs];

            int lastIdx = -1;
            int idx = 0;

            for (long idAndPos : sortedIds) {
                int doc = (int) (idAndPos >>> 32);
                int position = (int) idAndPos;

                if (leaves != null) {
                    idx = ReaderUtil.subIndex(doc, leaves);
                    currentLeaf = leaves.get(idx);
                    if (idx != lastIdx) {
                        // we switched segments.  invalidate comparator.
                        comparator = null;
                    }
                }

                if (comparator == null) {
                    comparator = sortField.getComparator(1, 0);
                    comparator = comparator.setNextReader(currentLeaf);
                }

                doc -= currentLeaf.docBase; // adjust for what segment this is in
                comparator.copy(0, doc);
                Object val = comparator.value(0);

                // Sortable float, double, int, long types all just use a string
                // comparator. For these, we need to put the type into a readable
                // format.  One reason for this is that XML can't represent all
                // string values (or even all unicode code points).
                // indexedToReadable() should be a no-op and should
                // thus be harmless anyway (for all current ways anyway)
                if (val instanceof String) {
                    field.setStringValue((String) val);
                    val = ft.toObject(field);
                }

                // Must do the same conversion when sorting by a
                // String field in Lucene, which returns the terms
                // data as BytesRef:
                if (val instanceof BytesRef) {
                    UnicodeUtil.UTF8toUTF16((BytesRef) val, spare);
                    field.setStringValue(spare.toString());
                    val = ft.toObject(field);
                }

                vals[position] = val;
            }

            sortVals.add(fieldname, vals);
        }

        rsp.add("sort_values", sortVals);
    }
}

From source file:org.apache.solr.handler.ExportWriter.java

License:Apache License

protected void writeDocs(SolrQueryRequest req, IteratorWriter.ItemWriter writer, Sort sort) throws IOException {
    //Write the data.
    List<LeafReaderContext> leaves = req.getSearcher().getTopReaderContext().leaves();
    SortDoc sortDoc = getSortDoc(req.getSearcher(), sort.getSort());
    int count = 0;
    int queueSize = 30000;
    SortQueue queue = new SortQueue(queueSize, sortDoc);
    SortDoc[] outDocs = new SortDoc[queueSize];

    while (count < totalHits) {
        //long begin = System.nanoTime();
        queue.reset();//  ww  w.j  av a2s.c  o m
        SortDoc top = queue.top();
        for (int i = 0; i < leaves.size(); i++) {
            sortDoc.setNextReader(leaves.get(i));
            DocIdSetIterator it = new BitSetIterator(sets[i], 0); // cost is not useful here
            int docId = -1;
            while ((docId = it.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
                sortDoc.setValues(docId);
                if (top.lessThan(sortDoc)) {
                    top.setValues(sortDoc);
                    top = queue.updateTop();
                }
            }
        }

        int outDocsIndex = -1;

        for (int i = 0; i < queueSize; i++) {
            SortDoc s = queue.pop();
            if (s.docId > -1) {
                outDocs[++outDocsIndex] = s;
            }
        }

        //long end = System.nanoTime();

        count += (outDocsIndex + 1);

        try {
            for (int i = outDocsIndex; i >= 0; --i) {
                SortDoc s = outDocs[i];
                writer.add((MapWriter) ew -> {
                    writeDoc(s, leaves, ew);
                    s.reset();
                });
            }
        } catch (Throwable e) {
            Throwable ex = e;
            e.printStackTrace();
            while (ex != null) {
                String m = ex.getMessage();
                if (m != null && m.contains("Broken pipe")) {
                    throw new IgnoreException();
                }
                ex = ex.getCause();
            }

            if (e instanceof IOException) {
                throw ((IOException) e);
            } else {
                throw new IOException(e);
            }
        }
    }
}

From source file:org.apache.solr.response.SortingResponseWriter.java

License:Apache License

public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse res) throws IOException {
    Exception e1 = res.getException();
    if (e1 != null) {
        e1.printStackTrace(new PrintWriter(writer));
        return;//  www .j  a  v a2 s. c om
    }
    SolrRequestInfo info = SolrRequestInfo.getRequestInfo();
    SortSpec sortSpec = info.getResponseBuilder().getSortSpec();

    if (sortSpec == null) {
        throw new IOException(new SyntaxError("No sort criteria was provided."));
    }

    SolrIndexSearcher searcher = req.getSearcher();
    Sort sort = searcher.weightSort(sortSpec.getSort());

    if (sort == null) {
        throw new IOException(new SyntaxError("No sort criteria was provided."));
    }

    if (sort.needsScores()) {
        throw new IOException(new SyntaxError("Scoring is not currently supported with xsort."));
    }

    FixedBitSet[] sets = (FixedBitSet[]) req.getContext().get("export");
    Integer th = (Integer) req.getContext().get("totalHits");

    if (sets == null) {
        throw new IOException(new SyntaxError("xport RankQuery is required for xsort: rq={!xport}"));
    }

    int totalHits = th.intValue();
    SolrParams params = req.getParams();
    String fl = params.get("fl");

    if (fl == null) {
        throw new IOException(new SyntaxError("export field list (fl) must be specified."));
    }

    String[] fields = fl.split(",");

    for (int i = 0; i < fields.length; i++) {
        if (fl.trim().equals("score")) {
            throw new IOException(new SyntaxError("Scoring is not currently supported with xsort."));
        }
    }

    FieldWriter[] fieldWriters = getFieldWriters(fields, req.getSearcher());
    writer.write(
            "{\"responseHeader\": {\"status\": 0}, \"response\":{\"numFound\":" + totalHits + ", \"docs\":[");

    //Write the data.
    List<AtomicReaderContext> leaves = req.getSearcher().getTopReaderContext().leaves();
    SortDoc sortDoc = getSortDoc(req.getSearcher(), sort.getSort());
    int count = 0;
    int queueSize = 30000;
    SortQueue queue = new SortQueue(queueSize, sortDoc);
    SortDoc[] outDocs = new SortDoc[queueSize];

    boolean commaNeeded = false;
    while (count < totalHits) {
        //long begin = System.nanoTime();
        queue.reset();
        SortDoc top = queue.top();
        for (int i = 0; i < leaves.size(); i++) {
            sortDoc.setNextReader(leaves.get(i));
            DocIdSetIterator it = sets[i].iterator();
            int docId = -1;
            while ((docId = it.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
                sortDoc.setValues(docId);
                if (top.lessThan(sortDoc)) {
                    top.setValues(sortDoc);
                    top = queue.updateTop();
                }
            }
        }

        int outDocsIndex = -1;

        for (int i = 0; i < queueSize; i++) {
            SortDoc s = queue.pop();
            if (s.docId > -1) {
                outDocs[++outDocsIndex] = s;
            }
        }

        //long end = System.nanoTime();

        count += (outDocsIndex + 1);

        try {
            for (int i = outDocsIndex; i >= 0; --i) {
                SortDoc s = outDocs[i];
                if (commaNeeded) {
                    writer.write(',');
                }
                writer.write('{');
                writeDoc(s, leaves, fieldWriters, sets, writer);
                writer.write('}');
                commaNeeded = true;
                s.reset();
            }
        } catch (Throwable e) {
            Throwable ex = e;
            while (ex != null) {
                String m = ex.getMessage();
                if (m != null && m.contains("Broken pipe")) {
                    logger.info("Early client disconnect during export");
                    return;
                }
                ex = ex.getCause();
            }

            if (e instanceof IOException) {
                throw ((IOException) e);
            } else {
                throw new IOException(e);
            }
        }
    }

    //System.out.println("Sort Time 2:"+Long.toString(total/1000000));
    writer.write("]}}");
    writer.flush();
}