You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ry...@apache.org on 2011/03/25 17:24:22 UTC

svn commit: r1085450 [1/2] - in /lucene/dev/trunk/solr: ./ src/common/org/apache/solr/common/ src/common/org/apache/solr/common/util/ src/java/org/apache/solr/handler/ src/java/org/apache/solr/handler/component/ src/java/org/apache/solr/response/ src/j...

Author: ryan
Date: Fri Mar 25 16:24:21 2011
New Revision: 1085450

URL: http://svn.apache.org/viewvc?rev=1085450&view=rev
Log:
SOLR-1566: Transforming documents in the ResponseWriters.  This will allow for more complex results in responses and open the door for function queries as results.

Added:
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/ResultContext.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/ReturnFields.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocIdAugmenter.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformer.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformers.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocValuesAugmenter.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ExplainAugmenter.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ScoreAugmenter.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformContext.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformerWithContext.java   (with props)
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ValueAugmenter.java   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/src/common/org/apache/solr/common/SolrDocument.java
    lucene/dev/trunk/solr/src/common/org/apache/solr/common/util/JavaBinCodec.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/handler/MoreLikeThisHandler.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/QueryComponent.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/BaseResponseWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/BinaryResponseWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/CSVResponseWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/JSONResponseWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/PHPSerializedResponseWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/SolrQueryResponse.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/TextResponseWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/response/XMLWriter.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/util/SolrPluginUtils.java
    lucene/dev/trunk/solr/src/test/org/apache/solr/BasicFunctionalityTest.java
    lucene/dev/trunk/solr/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
    lucene/dev/trunk/solr/src/test/org/apache/solr/response/TestCSVResponseWriter.java
    lucene/dev/trunk/solr/src/test/org/apache/solr/search/TestRangeQuery.java
    lucene/dev/trunk/solr/src/webapp/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Fri Mar 25 16:24:21 2011
@@ -108,6 +108,11 @@ New Features
   Adding a parameter NOW=<time_in_ms> to the request will override the
   current time.  (Peter Sturge, yonik)
 
+* SOLR-1566: Transforming documents in the ResponseWriters.  This will allow
+  for more complex results in responses and open the door for function queries
+  as results. (ryan)
+
+
 Optimizations
 ----------------------
 

Modified: lucene/dev/trunk/solr/src/common/org/apache/solr/common/SolrDocument.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/common/org/apache/solr/common/SolrDocument.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/common/org/apache/solr/common/SolrDocument.java (original)
+++ lucene/dev/trunk/solr/src/common/org/apache/solr/common/SolrDocument.java Fri Mar 25 16:24:21 2011
@@ -26,6 +26,8 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.solr.common.util.NamedList;
+
 
 /**
  * A concrete representation of a document within a Solr index.  Unlike a lucene
@@ -88,6 +90,9 @@ public class SolrDocument implements Map
     else if( value instanceof Collection ) {
       // nothing
     }
+    else if( value instanceof NamedList ) {
+      // nothing
+    }
     else if( value instanceof Iterable ) {
       ArrayList<Object> lst = new ArrayList<Object>();
       for( Object o : (Iterable)value ) {

Modified: lucene/dev/trunk/solr/src/common/org/apache/solr/common/util/JavaBinCodec.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/common/org/apache/solr/common/util/JavaBinCodec.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/common/org/apache/solr/common/util/JavaBinCodec.java (original)
+++ lucene/dev/trunk/solr/src/common/org/apache/solr/common/util/JavaBinCodec.java Fri Mar 25 16:24:21 2011
@@ -295,27 +295,13 @@ public class JavaBinCodec {
   }
 
   public void writeSolrDocument(SolrDocument doc) throws IOException {
-    writeSolrDocument(doc, null);
-  }
-
-  public void writeSolrDocument(SolrDocument doc, Set<String> fields) throws IOException {
-    int count = 0;
-    if (fields == null) {
-      count = doc.getFieldNames().size();
-    } else {
-      for (Map.Entry<String, Object> entry : doc) {
-        if (fields.contains(entry.getKey())) count++;
-      }
-    }
     writeTag(SOLRDOC);
-    writeTag(ORDERED_MAP, count);
+    writeTag(ORDERED_MAP, doc.size());
     for (Map.Entry<String, Object> entry : doc) {
-      if (fields == null || fields.contains(entry.getKey())) {
-        String name = entry.getKey();
-        writeExternString(name);
-        Object val = entry.getValue();
-        writeVal(val);
-      }
+      String name = entry.getKey();
+      writeExternString(name);
+      Object val = entry.getValue();
+      writeVal(val);
     }
   }
 

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/handler/MoreLikeThisHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/handler/MoreLikeThisHandler.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/handler/MoreLikeThisHandler.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/handler/MoreLikeThisHandler.java Fri Mar 25 16:24:21 2011
@@ -47,6 +47,7 @@ import org.apache.solr.common.util.Simpl
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.request.SimpleFacets;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.ReturnFields;
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.SchemaField;
@@ -77,10 +78,11 @@ public class MoreLikeThisHandler extends
     SolrParams params = req.getParams();
 
     // Set field flags
-    String fl = params.get(CommonParams.FL);
+    ReturnFields returnFields = ReturnFields.getReturnFields( req );
+    rsp.setReturnFields( returnFields );
     int flags = 0;
-    if (fl != null) {
-      flags |= SolrPluginUtils.setReturnFields(fl, rsp);
+    if (returnFields.getWantsScore()) {
+      flags |= SolrIndexSearcher.GET_SCORES;
     }
 
     String defType = params.get(QueryParsing.DEFTYPE, QParserPlugin.DEFAULT_QTYPE);

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/QueryComponent.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/QueryComponent.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/QueryComponent.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/QueryComponent.java Fri Mar 25 16:24:21 2011
@@ -39,6 +39,8 @@ import org.apache.solr.common.util.Named
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.ResultContext;
+import org.apache.solr.response.ReturnFields;
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.schema.FieldType;
 import org.apache.solr.schema.SchemaField;
@@ -72,13 +74,14 @@ public class QueryComponent extends Sear
     }
     SolrQueryResponse rsp = rb.rsp;
 
-    // Set field flags
-    String fl = params.get(CommonParams.FL);
-    int fieldFlags = 0;
-    if (fl != null) {
-      fieldFlags |= SolrPluginUtils.setReturnFields(fl, rsp);
+    // Set field flags    
+    ReturnFields returnFields = ReturnFields.getReturnFields( req );
+    rsp.setReturnFields( returnFields );
+    int flags = 0;
+    if (returnFields.getWantsScore()) {
+      flags |= SolrIndexSearcher.GET_SCORES;
     }
-    rb.setFieldFlags( fieldFlags );
+    rb.setFieldFlags( flags );
 
     String defType = params.get(QueryParsing.DEFTYPE,QParserPlugin.DEFAULT_QTYPE);
 
@@ -294,7 +297,11 @@ public class QueryComponent extends Sear
         res.docSet = searcher.getDocSet(queries);
       }
       rb.setResults(res);
-      rsp.add("response",rb.getResults().docList);
+      
+      ResultContext ctx = new ResultContext();
+      ctx.docs = rb.getResults().docList;
+      ctx.query = null; // anything?
+      rsp.add("response", ctx);
       return;
     }
 
@@ -416,7 +423,10 @@ public class QueryComponent extends Sear
         // TODO: get "hits" a different way to log
 
         if (grouping.mainResult != null) {
-          rsp.add("response",grouping.mainResult);
+          ResultContext ctx = new ResultContext();
+          ctx.docs = grouping.mainResult;
+          ctx.query = null; // TODO? add the query?
+          rsp.add("response", ctx);
           rsp.getToLog().add("hits", grouping.mainResult.matches());
         }
 
@@ -431,7 +441,11 @@ public class QueryComponent extends Sear
     searcher.search(result,cmd);
     rb.setResult( result );
 
-    rsp.add("response",rb.getResults().docList);
+
+    ResultContext ctx = new ResultContext();
+    ctx.docs = rb.getResults().docList;
+    ctx.query = rb.getQuery();
+    rsp.add("response", ctx);
     rsp.getToLog().add("hits", rb.getResults().docList.matches());
 
     doFieldSortValues(rb, searcher);

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/BaseResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/BaseResponseWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/BaseResponseWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/BaseResponseWriter.java Fri Mar 25 16:24:21 2011
@@ -38,10 +38,14 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Set;
 import java.util.ArrayList;
 
 /**
+ * THIS HAS NO TESTS and is not used anywhere....  no idea how or if it should work...
+ * 
+ * I think we should drop it - along with {@link GenericBinaryResponseWriter} and {@link GenericBinaryResponseWriter}
+ * 
+ * unless I'm missing something (ryan, March 2011)
  * 
  * 
  * This class serves as a basis from which {@link QueryResponseWriter}s can be
@@ -60,7 +64,6 @@ public abstract class BaseResponseWriter
   private static final Logger LOG = LoggerFactory
       .getLogger(BaseResponseWriter.class);
 
-  private static final String SCORE_FIELD = "score";
 
   /**
    * 
@@ -110,9 +113,6 @@ public abstract class BaseResponseWriter
           responseWriter.startDocumentList(name,info);
           for (int j = 0; j < sz; j++) {
             SolrDocument sdoc = getDoc(iterator.nextDoc(), idxInfo);
-            if (idxInfo.includeScore && docList.hasScores()) {
-              sdoc.addField(SCORE_FIELD, iterator.score());
-            }
             responseWriter.writeDoc(sdoc);
           }
         } else {
@@ -120,9 +120,6 @@ public abstract class BaseResponseWriter
               .size());
           for (int j = 0; j < sz; j++) {
             SolrDocument sdoc = getDoc(iterator.nextDoc(), idxInfo);
-            if (idxInfo.includeScore && docList.hasScores()) {
-              sdoc.addField(SCORE_FIELD, iterator.score());
-            }
             list.add(sdoc);
           }
           responseWriter.writeAllDocs(info, list);
@@ -144,22 +141,13 @@ public abstract class BaseResponseWriter
   private static class IdxInfo {
     IndexSchema schema;
     SolrIndexSearcher searcher;
-    Set<String> returnFields;
-    boolean includeScore;
+    ReturnFields returnFields;
 
     private IdxInfo(IndexSchema schema, SolrIndexSearcher searcher,
-        Set<String> returnFields) {
+        ReturnFields returnFields) {
       this.schema = schema;
       this.searcher = searcher;
-      this.includeScore = returnFields != null
-              && returnFields.contains(SCORE_FIELD);
-      if (returnFields != null) {
-        if (returnFields.size() == 0 || (returnFields.size() == 1 && includeScore) || returnFields.contains("*")) {
-          returnFields = null;  // null means return all stored fields
-        }
-      }
       this.returnFields = returnFields;
-
     }
   }
 

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/BinaryResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/BinaryResponseWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/BinaryResponseWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/BinaryResponseWriter.java Fri Mar 25 16:24:21 2011
@@ -19,12 +19,14 @@ package org.apache.solr.response;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Fieldable;
 import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.JavaBinCodec;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.transform.DocTransformer;
+import org.apache.solr.response.transform.TransformContext;
 import org.apache.solr.schema.*;
-import org.apache.solr.search.DocIterator;
 import org.apache.solr.search.DocList;
 import org.apache.solr.search.SolrIndexSearcher;
 import org.slf4j.Logger;
@@ -62,79 +64,101 @@ public class BinaryResponseWriter implem
     protected final SolrQueryRequest solrQueryRequest;
     protected IndexSchema schema;
     protected SolrIndexSearcher searcher;
-    protected final Set<String> returnFields;
-    protected final boolean includeScore;
+    protected final ReturnFields returnFields;
 
     // transmit field values using FieldType.toObject()
     // rather than the String from FieldType.toExternal()
     boolean useFieldObjects = true;
 
-    public Resolver(SolrQueryRequest req, Set<String> returnFields) {
+    public Resolver(SolrQueryRequest req, ReturnFields returnFields) {
       solrQueryRequest = req;
-      this.includeScore = returnFields != null && returnFields.contains("score");
-
-      if (returnFields != null) {
-        if (returnFields.size() == 0 || (returnFields.size() == 1 && includeScore) || returnFields.contains("*")) {
-          returnFields = null;  // null means return all stored fields
-        }
-      }
       this.returnFields = returnFields;
     }
 
     public Object resolve(Object o, JavaBinCodec codec) throws IOException {
+      if (o instanceof ResultContext) {
+        writeResults((ResultContext) o, codec);
+        return null; // null means we completely handled it
+      }
       if (o instanceof DocList) {
-        writeDocList((DocList) o, codec);
+        ResultContext ctx = new ResultContext();
+        ctx.docs = (DocList) o;
+        writeResults(ctx, codec);
         return null; // null means we completely handled it
       }
+
       if (o instanceof SolrDocument) {
-        SolrDocument solrDocument = (SolrDocument) o;
-        codec.writeSolrDocument(solrDocument, returnFields);
-        return null;
-      }
-      if (o instanceof Document) {
-        return getDoc((Document) o);
+        // Remove any fields that were not requested
+        // This typically happens when distributed search adds extra fields to an internal request
+        SolrDocument doc = (SolrDocument)o;
+        for( String fname : doc.getFieldNames() ) {
+          if( !returnFields.contains( fname ) ) {
+            doc.removeFields( fname );
+          }
+        }
+        return doc;
       }
-
       return o;
     }
 
-    public void writeDocList(DocList ids, JavaBinCodec codec) throws IOException {
-      codec.writeTag(JavaBinCodec.SOLRDOCLST);
-      List l = new ArrayList(3);
-      l.add((long) ids.matches());
-      l.add((long) ids.offset());
-      Float maxScore = null;
-      if (includeScore && ids.hasScores()) {
-        maxScore = ids.maxScore();
-      }
-      l.add(maxScore);
-      codec.writeArray(l);
-
+    protected void writeResultsBody( ResultContext res, JavaBinCodec codec ) throws IOException 
+    {
+      DocList ids = res.docs;
+      TransformContext context = new TransformContext();
+      context.query = res.query;
+      context.wantsScores = returnFields.getWantsScore() && ids.hasScores();
+      
       int sz = ids.size();
       codec.writeTag(JavaBinCodec.ARR, sz);
       if(searcher == null) searcher = solrQueryRequest.getSearcher();
       if(schema == null) schema = solrQueryRequest.getSchema(); 
-      DocIterator iterator = ids.iterator();
+      
+      context.searcher = searcher;
+      DocTransformer transformer = returnFields.getTransformer();
+      if( transformer != null ) {
+        transformer.setContext( context );
+      }
+      
+      Set<String> fnames = returnFields.getFieldNames();
+      context.iterator = ids.iterator();
       for (int i = 0; i < sz; i++) {
-        int id = iterator.nextDoc();
-        Document doc = searcher.doc(id, returnFields);
-
+        int id = context.iterator.nextDoc();
+        Document doc = searcher.doc(id, fnames);
         SolrDocument sdoc = getDoc(doc);
-
-        if (includeScore && ids.hasScores()) {
-          sdoc.addField("score", iterator.score());
+        if( transformer != null ) {
+          transformer.transform(sdoc, id );
         }
-
         codec.writeSolrDocument(sdoc);
       }
+      if( transformer != null ) {
+        transformer.setContext( null );
+      }
+    }
+    
+    public void writeResults(ResultContext ctx, JavaBinCodec codec) throws IOException {
+      codec.writeTag(JavaBinCodec.SOLRDOCLST);
+      boolean wantsScores = returnFields.getWantsScore() && ctx.docs.hasScores();
+      List l = new ArrayList(3);
+      l.add((long) ctx.docs.matches());
+      l.add((long) ctx.docs.offset());
+      
+      Float maxScore = null;
+      if (wantsScores) {
+        maxScore = ctx.docs.maxScore();
+      }
+      l.add(maxScore);
+      codec.writeArray(l);
+      
+      // this is a seprate function so that streaming responses can use just that part
+      writeResultsBody( ctx, codec );
     }
-
 
     public SolrDocument getDoc(Document doc) {
       SolrDocument solrDoc = new SolrDocument();
       for (Fieldable f : doc.getFields()) {
         String fieldName = f.name();
-        if (returnFields != null && !returnFields.contains(fieldName)) continue;
+        if( !returnFields.contains(fieldName) ) 
+          continue;
         SchemaField sf = schema.getFieldOrNull(fieldName);
         FieldType ft = null;
         if(sf != null) ft =sf.getType();

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/CSVResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/CSVResponseWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/CSVResponseWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/CSVResponseWriter.java Fri Mar 25 16:24:21 2011
@@ -159,7 +159,6 @@ class CSVWriter extends TextResponseWrit
   ResettableFastWriter mvWriter = new ResettableFastWriter();  // writer used for multi-valued fields
 
   String NullValue;
-  boolean returnScore = false;
 
 
   public CSVWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) {
@@ -236,12 +235,9 @@ class CSVWriter extends TextResponseWrit
       // encapsulator will already be disabled if it wasn't specified
     }
 
-    returnScore = returnFields != null && returnFields.contains("score");
-    boolean needListOfFields = returnFields==null || returnFields.size()==0 || (returnFields.size()==1 && returnScore) || returnFields.contains("*");
-    Collection<String> fields = returnFields;
-
+    Collection<String> fields = returnFields.getFieldNames();
     Object responseObj = rsp.getValues().get("response");
-    if (needListOfFields) {
+    if (fields==null) {
       if (responseObj instanceof SolrDocumentList) {
         // get the list of fields from the SolrDocumentList
         fields = new LinkedHashSet<String>();
@@ -252,7 +248,7 @@ class CSVWriter extends TextResponseWrit
         // get the list of fields from the index
         fields = req.getSearcher().getFieldNames();
       }
-      if (returnScore) {
+      if (returnFields.getWantsScore()) {
         fields.add("score");
       } else {
         fields.remove("score");
@@ -327,11 +323,15 @@ class CSVWriter extends TextResponseWrit
       printer.println();
     }
 
-
-    if (responseObj instanceof DocList) {
-      writeDocList(null, (DocList)responseObj, null, null);
+    if (responseObj instanceof ResultContext ) {
+      writeDocuments(null, (ResultContext)responseObj, returnFields );
+    }
+    else if (responseObj instanceof DocList) {
+      ResultContext ctx = new ResultContext();
+      ctx.docs =  (DocList)responseObj;
+      writeDocuments(null, ctx, returnFields );
     } else if (responseObj instanceof SolrDocumentList) {
-      writeSolrDocumentList(null, (SolrDocumentList)responseObj, null, null);
+      writeSolrDocumentList(null, (SolrDocumentList)responseObj, returnFields );
     }
 
   }
@@ -346,56 +346,21 @@ class CSVWriter extends TextResponseWrit
   public void writeNamedList(String name, NamedList val) throws IOException {
   }
 
-  @Override
-  public void writeDoc(String name, Document doc, Set<String> returnFields, float score, boolean includeScore) throws IOException {
-    pass++;
-
-    for (Fieldable field: doc.getFields()) {
-      CSVField csvField = csvFields.get(field.name());
-      if (csvField == null) continue;
-      if (csvField.tmp != pass) {
-        csvField.tmp = pass;
-        csvField.values.clear();
-      }
-      csvField.values.add(field);
-    }
-
-    for (CSVField csvField : csvFields.values()) {
-      if (csvField.name.equals("score")) {
-        writeFloat("score", score);
-        continue;
-      }
-      if (csvField.tmp != pass) {
-        writeNull(csvField.name);
-        continue;
-      }
-
-      if (csvField.sf.multiValued() || csvField.values.size() > 1) {
-        mvWriter.reset();
-        csvField.mvPrinter.reset();
-        // switch the printer to use the multi-valued one
-        CSVPrinter tmp = printer;
-        printer = csvField.mvPrinter;
-        for (Fieldable fval : csvField.values) {
-          csvField.sf.getType().write(this, csvField.name, fval);
-        }
-        printer = tmp;  // restore the original printer
-
-        mvWriter.freeze();
-        printer.print(mvWriter.getFrozenBuf(), 0, mvWriter.getFrozenSize(), true);
-      } else {
-        assert csvField.values.size() == 1;
-        csvField.sf.getType().write(this,csvField.name,csvField.values.get(0));
-      }
-    }
+  public void writeStartDocumentList(String name, 
+      long start, int size, long numFound, Float maxScore) throws IOException
+  {
+    // nothing
+  }
 
-    printer.println();
+  public void writeEndDocumentList() throws IOException
+  {
+    // nothing
   }
 
   //NOTE: a document cannot currently contain another document
   List tmpList;
   @Override
-  public void writeSolrDocument(String name, SolrDocument doc, Set<String> returnFields, Map pseudoFields) throws IOException {
+  public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx ) throws IOException {
     if (tmpList == null) {
       tmpList = new ArrayList(1);
       tmpList.add(null);
@@ -446,26 +411,6 @@ class CSVWriter extends TextResponseWrit
   }
 
   @Override
-  public void writeDocList(String name, DocList ids, Set<String> fields, Map otherFields) throws IOException {
-    int sz=ids.size();
-    SolrIndexSearcher searcher = req.getSearcher();
-    DocIterator iterator = ids.iterator();
-    for (int i=0; i<sz; i++) {
-      int id = iterator.nextDoc();
-      Document doc = searcher.doc(id, fields);
-      writeDoc(null, doc, fields, (returnScore ? iterator.score() : 0.0f), returnScore);
-    }
-  }
-
-  Map scoreMap = new HashMap(1);
-  @Override
-  public void writeSolrDocumentList(String name, SolrDocumentList docs, Set<String> fields, Map otherFields) throws IOException {
-    for (SolrDocument doc : docs) {
-      writeSolrDocument(name, doc, fields, otherFields);
-    }
-  }
-
-  @Override
   public void writeStr(String name, String val, boolean needsEscaping) throws IOException {
     printer.print(val, needsEscaping);
   }

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/JSONResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/JSONResponseWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/JSONResponseWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/JSONResponseWriter.java Fri Mar 25 16:24:21 2011
@@ -17,24 +17,23 @@
 
 package org.apache.solr.response;
 
-import org.apache.lucene.document.Document;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.lucene.document.Fieldable;
 import org.apache.lucene.util.StringHelper;
 import org.apache.solr.common.SolrDocument;
-import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.schema.SchemaField;
-import org.apache.solr.schema.TextField;
-import org.apache.solr.search.DocIterator;
-import org.apache.solr.search.DocList;
-import org.apache.solr.search.SolrIndexSearcher;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.*;
 
 /**
  * @version $Id$
@@ -73,7 +72,6 @@ class JSONWriter extends TextResponseWri
   private static final String JSON_NL_ARROFMAP="arrmap";
   private static final String JSON_WRAPPER_FUNCTION="json.wrf";
 
-
   public JSONWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) {
     super(writer, req, rsp);
     namedListStyle = StringHelper.intern(req.getParams().get(JSON_NL_STYLE, JSON_NL_FLAT));
@@ -312,94 +310,21 @@ class JSONWriter extends TextResponseWri
     }
   }
 
-  public void writeDoc(String name, Collection<Fieldable> fields, Set<String> returnFields, Map pseudoFields) throws IOException {
-    writeMapOpener(-1); // no trivial way to determine map size
-    incLevel();
-
-    HashMap<String, MultiValueField> multi = new HashMap<String, MultiValueField>();
-
-    boolean first=true;
-
-    for (Fieldable ff : fields) {
-      String fname = ff.name();
-      if (returnFields!=null && !returnFields.contains(fname)) {
-        continue;
-      }
-
-      // if the field is multivalued, it may have other values further on... so
-      // build up a list for each multi-valued field.
-      SchemaField sf = schema.getField(fname);
-      if (sf.multiValued()) {
-        MultiValueField mf = multi.get(fname);
-        if (mf==null) {
-          mf = new MultiValueField(sf, ff);
-          multi.put(fname, mf);
-        } else {
-          mf.fields.add(ff);
-        }
-      } else {
-        // not multi-valued, so write it immediately.
-        if (first) {
-          first=false;
-        } else {
-          writeMapSeparator();
-        }
-        indent();
-        writeKey(fname,true);
-        sf.write(this, fname, ff);
-      }
-    }
-
-    for(MultiValueField mvf : multi.values()) {
-      if (first) {
-        first=false;
-      } else {
-        writeMapSeparator();
-      }
-
-      indent();
-      writeKey(mvf.sfield.getName(), true);
-
-      boolean indentArrElems=false;
-      if (doIndent) {
-        // heuristic... TextField is probably the only field type likely to be long enough
-        // to warrant indenting individual values.
-        indentArrElems = (mvf.sfield.getType() instanceof TextField);
-      }
-
-      writeArrayOpener(-1); // no trivial way to determine array size
-      boolean firstArrElem=true;
-      incLevel();
-
-      for (Fieldable ff : mvf.fields) {
-        if (firstArrElem) {
-          firstArrElem=false;
-        } else {
-          writeArraySeparator();
-        }
-        if (indentArrElems) indent();
-        mvf.sfield.write(this, null, ff);
-      }
-      writeArrayCloser();
-      decLevel();
-    }
-
-    if (pseudoFields !=null && pseudoFields.size()>0) {
-      writeMap(null,pseudoFields,true,first);
-    }
-
-    decLevel();
-    writeMapCloser();
-  }
-
   @Override
-  public void writeSolrDocument(String name, SolrDocument doc, Set<String> returnFields, Map pseudoFields) throws IOException {
-    writeMapOpener(-1); // no trivial way to determine map size
-    // TODO: could easily figure out size for SolrDocument if needed...
+  public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException {
+    if( idx > 0 ) {
+      writeArraySeparator();
+    }
+    
+    writeMapOpener(doc.size()); 
     incLevel();
 
     boolean first=true;
     for (String fname : doc.getFieldNames()) {
+      if (!returnFields.contains(fname)) {
+        continue;
+      }
+      
       if (first) {
         first=false;
       }
@@ -424,144 +349,43 @@ class JSONWriter extends TextResponseWri
           writeVal(fname, val);
         }
       }
-
-      if (pseudoFields !=null && pseudoFields.size()>0) {
-        writeMap(null,pseudoFields,true,first);
-      }
     }
-
+    
     decLevel();
     writeMapCloser();
   }
 
-
-  // reusable map to store the "score" pseudo-field.
-  // if a Doc can ever contain another doc, this optimization would have to go.
-  private final HashMap scoreMap = new HashMap(1);
-
-  @Override
-  public void writeDoc(String name, Document doc, Set<String> returnFields, float score, boolean includeScore) throws IOException {
-    Map other = null;
-    if (includeScore) {
-      other = scoreMap;
-      scoreMap.put("score",score);
-    }
-    writeDoc(name, doc.getFields(), returnFields, other);
-  }
-
   @Override
-  public void writeDocList(String name, DocList ids, Set<String> fields, Map otherFields) throws IOException {
-    boolean includeScore=false;
-    if (fields!=null) {
-      includeScore = fields.contains("score");
-      if (fields.size()==0 || (fields.size()==1 && includeScore) || fields.contains("*")) {
-        fields=null;  // null means return all stored fields
-      }
-    }
-
-    int sz=ids.size();
-
-    writeMapOpener(includeScore ? 4 : 3);
+  public void writeStartDocumentList(String name, 
+      long start, int size, long numFound, Float maxScore) throws IOException
+  {
+    writeMapOpener((maxScore==null) ? 3 : 4);
     incLevel();
     writeKey("numFound",false);
-    writeInt(null,ids.matches());
+    writeLong(null,numFound);
     writeMapSeparator();
     writeKey("start",false);
-    writeInt(null,ids.offset());
+    writeLong(null,start);
 
-    if (includeScore) {
+    if (maxScore!=null) {
       writeMapSeparator();
       writeKey("maxScore",false);
-      writeFloat(null,ids.maxScore());
+      writeFloat(null,maxScore);
     }
     writeMapSeparator();
     // indent();
     writeKey("docs",false);
-    writeArrayOpener(sz);
+    writeArrayOpener(size);
 
     incLevel();
-    boolean first=true;
-
-    SolrIndexSearcher searcher = req.getSearcher();
-    // be defensive... write out the doc even if we don't have the scores like we should
-    includeScore = includeScore && ids.hasScores();
-    DocIterator iterator = ids.iterator();
-    for (int i=0; i<sz; i++) {
-      int id = iterator.nextDoc();
-      Document doc = searcher.doc(id, fields);
-
-      if (first) {
-        first=false;
-      } else {
-        writeArraySeparator();
-      }
-      indent();
-      writeDoc(null, doc, fields, (includeScore ? iterator.score() : 0.0f), includeScore);
-    }
-    decLevel();
-    writeArrayCloser();
-
-    if (otherFields !=null) {
-      writeMap(null, otherFields, true, false);
-    }
-
-    decLevel();
-    indent();
-    writeMapCloser();
   }
 
-
   @Override
-  public void writeSolrDocumentList(String name, SolrDocumentList docs, Set<String> fields, Map otherFields) throws IOException {
-    boolean includeScore=false;
-    if (fields!=null) {
-      includeScore = fields.contains("score");
-      if (fields.size()==0 || (fields.size()==1 && includeScore) || fields.contains("*")) {
-        fields=null;  // null means return all stored fields
-      }
-    }
-
-    int sz=docs.size();
-
-    writeMapOpener(includeScore ? 4 : 3);
-    incLevel();
-    writeKey("numFound",false);
-    writeLong(null,docs.getNumFound());
-    writeMapSeparator();
-    writeKey("start",false);
-    writeLong(null,docs.getStart());
-
-    if (includeScore && docs.getMaxScore() != null) {
-      writeMapSeparator();
-      writeKey("maxScore",false);
-      writeFloat(null,docs.getMaxScore());
-    }
-    writeMapSeparator();
-    // indent();
-    writeKey("docs",false);
-    writeArrayOpener(sz);
-
-    incLevel();
-    boolean first=true;
-
-    SolrIndexSearcher searcher = req.getSearcher();
-    for (SolrDocument doc : docs) {
-
-      if (first) {
-        first=false;
-      } else {
-        writeArraySeparator();
-      }
-      indent();      
-      writeSolrDocument(null, doc, fields, otherFields);
-    }
+  public void writeEndDocumentList() throws IOException
+  {
     decLevel();
     writeArrayCloser();
 
-    if (otherFields !=null) {
-      writeMap(null, otherFields, true, false);
-    }
-
     decLevel();
     indent();
     writeMapCloser();

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/PHPSerializedResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/PHPSerializedResponseWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/PHPSerializedResponseWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/PHPSerializedResponseWriter.java Fri Mar 25 16:24:21 2011
@@ -17,23 +17,22 @@
 
 package org.apache.solr.response;
 
-import java.io.Writer;
 import java.io.IOException;
-import java.util.*;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
 
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Fieldable;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.UnicodeUtil;
+import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.schema.SchemaField;
-import org.apache.solr.search.DocIterator;
-import org.apache.solr.search.DocList;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.apache.solr.common.SolrDocument;
-import org.apache.solr.common.SolrDocumentList;
+
+
 /**
  * A description of the PHP serialization format can be found here:
  * http://www.hurring.com/scott/code/perl/serialize/
@@ -80,126 +79,53 @@ class PHPSerializedWriter extends JSONWr
     writeNamedListAsMapMangled(name,val);
   }
   
-  @Override
-  public void writeDoc(String name, Collection<Fieldable> fields, Set<String> returnFields, Map pseudoFields) throws IOException {
-    ArrayList<Fieldable> single = new ArrayList<Fieldable>();
-    LinkedHashMap<String, MultiValueField> multi 
-      = new LinkedHashMap<String, MultiValueField>();
-
-    for (Fieldable ff : fields) {
-      String fname = ff.name();
-      if (returnFields!=null && !returnFields.contains(fname)) {
-        continue;
-      }
-      // if the field is multivalued, it may have other values further on... so
-      // build up a list for each multi-valued field.
-      SchemaField sf = schema.getField(fname);
-      if (sf.multiValued()) {
-        MultiValueField mf = multi.get(fname);
-        if (mf==null) {
-          mf = new MultiValueField(sf, ff);
-          multi.put(fname, mf);
-        } else {
-          mf.fields.add(ff);
-        }
-      } else {
-        single.add(ff);
-      }
-    }
-
-    // obtain number of fields in doc
-    writeArrayOpener(single.size() + multi.size() + ((pseudoFields!=null) ? pseudoFields.size() : 0));
-
-    // output single value fields
-    for(Fieldable ff : single) {
-      SchemaField sf = schema.getField(ff.name());
-      writeKey(ff.name(),true);
-      sf.write(this, ff.name(), ff);
-    }
-    
-    // output multi value fields
-    for(MultiValueField mvf : multi.values()) {
-      writeKey(mvf.sfield.getName(), true);
-      writeArrayOpener(mvf.fields.size());
-      int i = 0;
-      for (Fieldable ff : mvf.fields) {
-        writeKey(i++, false);
-        mvf.sfield.write(this, null, ff);
-      }
-      writeArrayCloser();
-    }
-
-    // output pseudo fields
-    if (pseudoFields !=null && pseudoFields.size()>0) {
-      writeMap(null,pseudoFields,true,false);
-    }
-    writeArrayCloser();
-  }
   
-  @Override
-  public void writeDocList(String name, DocList ids, Set<String> fields, Map otherFields) throws IOException {
-    boolean includeScore=false;
-    
-    if (fields!=null) {
-      includeScore = fields.contains("score");
-      if (fields.size()==0 || (fields.size()==1 && includeScore) || fields.contains("*")) {
-        fields=null;  // null means return all stored fields
-      }
-    }
-
-    int sz=ids.size();
 
-    writeMapOpener(includeScore ? 4 : 3);
+  public void writeStartDocumentList(String name, 
+      long start, int size, long numFound, Float maxScore) throws IOException
+  {
+    writeMapOpener((maxScore==null) ? 3 : 4);
     writeKey("numFound",false);
-    writeInt(null,ids.matches());
+    writeLong(null,numFound);
     writeKey("start",false);
-    writeInt(null,ids.offset());
+    writeLong(null,start);
 
-    if (includeScore) {
+    if (maxScore!=null) {
       writeKey("maxScore",false);
-      writeFloat(null,ids.maxScore());
+      writeFloat(null,maxScore);
     }
     writeKey("docs",false);
-    writeArrayOpener(sz);
-
-    SolrIndexSearcher searcher = req.getSearcher();
-    DocIterator iterator = ids.iterator();
-    for (int i=0; i<sz; i++) {
-      int id = iterator.nextDoc();
-      Document doc = searcher.doc(id, fields);
-      writeKey(i, false);
-      writeDoc(null, doc, fields, (includeScore ? iterator.score() : 0.0f), includeScore);
-    }
-    writeMapCloser();
-
-    if (otherFields !=null) {
-      writeMap(null, otherFields, true, false);
-    }
+    writeArrayOpener(size);
+  }
 
+  public void writeEndDocumentList() throws IOException
+  {
+    writeArrayCloser(); // doc list
     writeMapCloser();
   }
   
   @Override
-  public void writeSolrDocument(String name, SolrDocument doc, Set<String> returnFields, Map pseudoFields) throws IOException {
+  public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException 
+  {
+    writeKey(idx, false);
+    
     LinkedHashMap <String,Object> single = new LinkedHashMap<String, Object>();
     LinkedHashMap <String,Object> multi = new LinkedHashMap<String, Object>();
-    int pseudoSize = pseudoFields != null ? pseudoFields.size() : 0;
 
     for (String fname : doc.getFieldNames()) {
-      if(returnFields != null && !returnFields.contains(fname)){
+      if(!returnFields.contains(fname)){
         continue;
       }
 
       Object val = doc.getFieldValue(fname);
-      SchemaField sf = schema.getFieldOrNull(fname);
-      if (sf != null && sf.multiValued()) {
+      if (val instanceof Collection) {
         multi.put(fname, val);
       }else{
         single.put(fname, val);
       }
     }
 
-    writeMapOpener(single.size() + multi.size() + pseudoSize);
+    writeMapOpener(single.size() + multi.size());
     for(String fname: single.keySet()){
       Object val = single.get(fname);
       writeKey(fname, true);
@@ -220,51 +146,7 @@ class PHPSerializedWriter extends JSONWr
         writeVal(fname, val);
       }
     }
-
-    if (pseudoSize > 0) {
-      writeMap(null,pseudoFields,true, false);
-    }
-    writeMapCloser();
-  }
-
-
-  @Override
-  public void writeSolrDocumentList(String name, SolrDocumentList docs, Set<String> fields, Map otherFields) throws IOException {
-    boolean includeScore=false;
-    if (fields!=null) {
-      includeScore = fields.contains("score");
-      if (fields.size()==0 || (fields.size()==1 && includeScore) || fields.contains("*")) {
-        fields=null;  // null means return all stored fields
-      }
-    }
-
-    int sz = docs.size();
-
-    writeMapOpener(includeScore ? 4 : 3);
-
-    writeKey("numFound",false);
-    writeLong(null,docs.getNumFound());
-
-    writeKey("start",false);
-    writeLong(null,docs.getStart());
-
-    if (includeScore && docs.getMaxScore() != null) {
-      writeKey("maxScore",false);
-      writeFloat(null,docs.getMaxScore());
-    }
-
-    writeKey("docs",false);
-
-    writeArrayOpener(sz);
-    for (int i=0; i<sz; i++) {
-      writeKey(i, false);
-      writeSolrDocument(null, docs.get(i), fields, otherFields);
-    }
-    writeArrayCloser();
-
-    if (otherFields !=null) {
-      writeMap(null, otherFields, true, false);
-    }
+    
     writeMapCloser();
   }
 

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/ResultContext.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/ResultContext.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/ResultContext.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/ResultContext.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.response;
+
+import org.apache.lucene.search.Query;
+import org.apache.solr.search.DocList;
+
+/**
+ * A class to hold the QueryResult and the Query
+ * 
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ */
+public class ResultContext {
+  public Query query;
+  public DocList docs;
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/ReturnFields.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/ReturnFields.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/ReturnFields.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/ReturnFields.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,168 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.transform.DocIdAugmenter;
+import org.apache.solr.response.transform.DocTransformer;
+import org.apache.solr.response.transform.DocTransformers;
+import org.apache.solr.response.transform.ExplainAugmenter;
+import org.apache.solr.response.transform.ScoreAugmenter;
+import org.apache.solr.response.transform.ValueAugmenter;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.util.SolrPluginUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A class representing the return fields
+ * 
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public class ReturnFields
+{
+  static final Logger log = LoggerFactory.getLogger( ReturnFields.class );
+  
+  public static final String SCORE = "score";
+  public static final String DOCID = "_docid_";
+  public static final String SHARD = "_shard_";
+  public static final String EXPLAIN = "_explain_";
+
+  private Set<String> fields; // includes 'augment' names or null
+  private DocTransformer transformer;
+  private boolean wantsScore = false;
+
+
+  public static ReturnFields getReturnFields(SolrQueryRequest req)
+  {
+    return getReturnFields( req.getParams().get(CommonParams.FL), req );
+  }
+
+  public static ReturnFields getReturnFields(String fl, SolrQueryRequest req)
+  {
+    ReturnFields rf = new ReturnFields();
+    rf.wantsScore = false;
+    rf.fields = new LinkedHashSet<String>(); // order is important for CSVResponseWriter
+    boolean allFields = false;
+
+    DocTransformers augmenters = new DocTransformers();
+    if (fl != null) {
+      // TODO - this could become more efficient if widely used.
+      String[] flst = SolrPluginUtils.split(fl);
+      if (flst.length > 0 && !(flst.length==1 && flst[0].length()==0)) {
+        IndexSchema schema = req.getSchema();
+        for (String name : flst) {
+          if( "*".equals( name ) ) {
+            allFields = true;
+          }
+          else if( SCORE.equals( name ) ) {
+            rf.fields.add( name );
+            rf.wantsScore = true;
+            augmenters.addTransformer( new ScoreAugmenter( SCORE ) );
+          }
+          else {
+            rf.fields.add( name );
+
+            // Check if it is a real score
+            SchemaField sf = schema.getFieldOrNull( name );
+            if( sf == null ) {
+              // not a field name, but possibly return value
+              if( DOCID.equals( name ) ) {
+                augmenters.addTransformer( new DocIdAugmenter( DOCID ) );
+              }
+              else if( SHARD.equals( name ) ) {
+                String id = "getshardid???";
+                augmenters.addTransformer( new ValueAugmenter( SHARD, id ) );
+              }
+              else if( EXPLAIN.equals( name ) ) {
+                augmenters.addTransformer( new ExplainAugmenter( EXPLAIN ) );
+              }
+              else if( name.startsWith( "{!func}") ) {
+                // help?  not sure how to parse a ValueSorce
+                // -- not to mention, we probably want to reuse existing ones!
+                augmenters.addTransformer( new ValueAugmenter( name, "TODO:"+name ) );
+//                try {
+//                  String func = name.substring( "{!func}".length() );
+//                  SolrParams local = null;
+//                  FunctionQParser p = new FunctionQParser( func, local, req.getParams(), req );
+//                  Query q = p.parse();
+//                  ValueSource vs = p.parseValueSource();
+//                  AtomicReaderContext ctx = new AtomicReaderContext( req.getSearcher().getIndexReader() );
+//                  Map mmm = null; // ?????
+//                  DocValues values = p.parseValueSource().getValues( mmm, ctx );
+//                  augmenters.addAugmenter( new DocValuesAugmenter( name, values ) );
+//                }
+//                catch( Exception ex ) {
+//                  throw new SolrException( org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST,
+//                      "Unable to parse augmented field: "+name, ex );
+//                }
+              }
+              else { 
+                // maybe throw an exception?
+//                throw new SolrException( org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST,
+//                    "Unknown Return Field: "+name );
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    // Legacy behavior? "score" == "*,score"
+    if( rf.fields.size() == 1 && rf.wantsScore ) {
+      allFields = true;
+    }
+    
+    if( allFields || rf.fields.isEmpty() ) {
+      rf.fields = null;
+    }
+    
+    if( augmenters.size() == 1 ) {
+      rf.transformer = augmenters.getTransformer(0);
+    }
+    else if( augmenters.size() > 1 ) {
+      rf.transformer = augmenters;
+    }
+    return rf;
+  }
+
+  public Set<String> getFieldNames()
+  {
+    return fields;
+  }
+
+  public boolean getWantsScore()
+  {
+    return wantsScore;
+  }
+
+  public boolean contains( String name )
+  {
+    return fields==null || fields.contains( name );
+  }
+
+  public DocTransformer getTransformer()
+  {
+    return transformer;
+  }
+}

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/SolrQueryResponse.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/SolrQueryResponse.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/SolrQueryResponse.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/SolrQueryResponse.java Fri Mar 25 16:24:21 2011
@@ -67,13 +67,14 @@ public class SolrQueryResponse {
    * @see <a href="#returnable_data">Note on Returnable Data</a>
    */
   protected NamedList<Object> values = new SimpleOrderedMap<Object>();
-
-  /**
+  
+  
+/**
    * Container for storing information that should be logged by Solr before returning.
    */
   protected NamedList<Object> toLog = new SimpleOrderedMap<Object>();
 
-  protected Set<String> defaultReturnFields;
+  protected ReturnFields returnFields;
 
   // error if this is set...
   protected Exception err;
@@ -111,18 +112,19 @@ public class SolrQueryResponse {
    * Sets the document field names of fields to return by default when
    * returning DocLists
    */
-  public void setReturnFields(Set<String> fields) {
-    defaultReturnFields=fields;
+  public void setReturnFields(ReturnFields fields) {
+    returnFields=fields;
   }
-  // TODO: should this be represented as a String[] such
-  // that order can be maintained if needed?
 
   /**
    * Gets the document field names of fields to return by default when
    * returning DocLists
    */
-  public Set<String> getReturnFields() {
-    return defaultReturnFields;
+  public ReturnFields getReturnFields() {
+    if( returnFields == null ) {
+      returnFields = new ReturnFields(); // by default return everything
+    }
+    return returnFields;
   }
 
 

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/TextResponseWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/TextResponseWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/TextResponseWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/TextResponseWriter.java Fri Mar 25 16:24:21 2011
@@ -17,17 +17,22 @@
 
 package org.apache.solr.response;
 
+import java.io.IOException;
+import java.io.Writer;
+import java.util.*;
+
 import org.apache.lucene.document.Document;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.FastWriter;
+import org.apache.lucene.document.Fieldable;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.util.FastWriter;
+import org.apache.solr.common.util.NamedList;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.transform.DocTransformer;
+import org.apache.solr.response.transform.TransformContext;
 import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
 import org.apache.solr.search.DocList;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.*;
 
 /** Base class for text-oriented response writers.
  *
@@ -49,7 +54,7 @@ public abstract class TextResponseWriter
   protected final SolrQueryResponse rsp;
 
   // the default set of fields to return for each document
-  protected Set<String> returnFields;
+  protected ReturnFields returnFields;
 
   protected int level;
   protected boolean doIndent;
@@ -114,6 +119,15 @@ public abstract class TextResponseWriter
     } else if (val instanceof String) {
       writeStr(name, val.toString(), true);
       // micro-optimization... using toString() avoids a cast first
+    } else if (val instanceof Fieldable) {
+      Fieldable f = (Fieldable)val;
+      SchemaField sf = schema.getFieldOrNull( f.name() );
+      if( sf != null ) {
+        sf.getType().write(this, name, f);
+      }
+      else {
+        writeStr(name, f.stringValue(), true);
+      }
     } else if (val instanceof Integer) {
       writeInt(name, val.toString());
     } else if (val instanceof Boolean) {
@@ -129,19 +143,25 @@ public abstract class TextResponseWriter
     } else if (val instanceof Double) {
       writeDouble(name, ((Double)val).doubleValue());
     } else if (val instanceof Document) {
-      writeDoc(name, (Document)val, returnFields, 0.0f, false);
+      SolrDocument doc = toSolrDocument( (Document)val );
+      writeSolrDocument(name, doc, returnFields, 0 );
     } else if (val instanceof SolrDocument) {
-      writeSolrDocument(name, (SolrDocument)val, returnFields, null);
-    } else if (val instanceof DocList) {
+      writeSolrDocument(name, (SolrDocument)val, returnFields, 0);
+    } else if (val instanceof ResultContext) {
       // requires access to IndexReader
-      writeDocList(name, (DocList)val, returnFields,null);
+      writeDocuments(name, (ResultContext)val, returnFields);
+    } else if (val instanceof DocList) {
+      // Should not happen normally
+      ResultContext ctx = new ResultContext();
+      ctx.docs = (DocList)val;
+      writeDocuments(name, ctx, returnFields);
     // }
     // else if (val instanceof DocSet) {
     // how do we know what fields to read?
     // todo: have a DocList/DocSet wrapper that
     // restricts the fields to write...?
     } else if (val instanceof SolrDocumentList) {
-      writeSolrDocumentList(name, (SolrDocumentList)val, returnFields, null);
+      writeSolrDocumentList(name, (SolrDocumentList)val, returnFields);
     } else if (val instanceof Map) {
       writeMap(name, (Map)val, false, true);
     } else if (val instanceof NamedList) {
@@ -162,20 +182,82 @@ public abstract class TextResponseWriter
   // types of formats, including those where the name may come after the value (like
   // some XML formats).
 
-  public abstract void writeDoc(String name, Document doc, Set<String> returnFields, float score, boolean includeScore) throws IOException;
+  public abstract void writeStartDocumentList(String name, long start, int size, long numFound, Float maxScore) throws IOException;  
 
-  /**
-   * @since solr 1.3
-   */
-  public abstract void writeSolrDocument(String name, SolrDocument doc, Set<String> returnFields, Map pseudoFields) throws IOException;  
-
-  public abstract void writeDocList(String name, DocList ids, Set<String> fields, Map otherFields) throws IOException;
-
-  /**
-   * @since solr 1.3
-   */
-  public abstract void writeSolrDocumentList(String name, SolrDocumentList docs, Set<String> fields, Map otherFields) throws IOException;  
+  public abstract void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx) throws IOException;  
+  
+  public abstract void writeEndDocumentList() throws IOException;
+  
+  // Assume each SolrDocument is already transformed
+  public final void writeSolrDocumentList(String name, SolrDocumentList docs, ReturnFields returnFields) throws IOException
+  {
+    writeStartDocumentList(name, docs.getStart(), docs.size(), docs.getNumFound(), docs.getMaxScore() );
+    for( int i=0; i<docs.size(); i++ ) {
+      writeSolrDocument( null, docs.get(i), returnFields, i );
+    }
+    writeEndDocumentList();
+  }
 
+  public final SolrDocument toSolrDocument( Document doc )
+  {
+    SolrDocument out = new SolrDocument();
+    for( Fieldable f : doc.getFields() ) {
+      if( "gack_i".equals( f.name() ) ) {
+        System.out.println( f );
+      }
+      
+      // Make sure multivalued fields are represented as lists
+      Object existing = out.get(f.name());
+      if (existing == null) {
+        SchemaField sf = schema.getFieldOrNull(f.name());
+        if (sf != null && sf.multiValued()) {
+          List<Object> vals = new ArrayList<Object>();
+          vals.add( f );
+          out.setField( f.name(), vals );
+        } 
+        else{
+          out.setField( f.name(), f );
+        }
+      }
+      else {
+        out.addField( f.name(), f );
+      }
+    }
+    return out;
+  }
+  
+  public final void writeDocuments(String name, ResultContext res, ReturnFields fields ) throws IOException {
+    DocList ids = res.docs;
+    TransformContext context = new TransformContext();
+    context.query = res.query;
+    context.wantsScores = fields.getWantsScore() && ids.hasScores();
+    writeStartDocumentList(name, ids.offset(), ids.size(), ids.matches(), 
+        context.wantsScores ? new Float(ids.maxScore()) : null );
+    
+    DocTransformer transformer = fields.getTransformer();
+    context.searcher = req.getSearcher();
+    context.iterator = ids.iterator();
+    if( transformer != null ) {
+      transformer.setContext( context );
+    }
+    int sz = ids.size();
+    Set<String> fnames = fields.getFieldNames();
+    for (int i=0; i<sz; i++) {
+      int id = context.iterator.nextDoc();
+      Document doc = context.searcher.doc(id, fnames);
+      SolrDocument sdoc = toSolrDocument( doc );
+      if( transformer != null ) {
+        transformer.transform( sdoc, id );
+      }
+      writeSolrDocument( null, sdoc, returnFields, i );
+    }
+    if( transformer != null ) {
+      transformer.setContext( null );
+    }
+    writeEndDocumentList();
+  }
+  
+  
   public abstract void writeStr(String name, String val, boolean needsEscaping) throws IOException;
 
   public abstract void writeMap(String name, Map val, boolean excludeOuter, boolean isFirstVal) throws IOException;

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/response/XMLWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/XMLWriter.java?rev=1085450&r1=1085449&r2=1085450&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/XMLWriter.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/XMLWriter.java Fri Mar 25 16:24:21 2011
@@ -17,26 +17,22 @@
 
 package org.apache.solr.response;
 
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.solr.common.SolrDocument;
-import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.XML;
 import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.apache.solr.search.DocList;
-import org.apache.solr.search.DocIterator;
-import org.apache.solr.search.DocSet;
 import org.apache.solr.schema.SchemaField;
-import org.apache.solr.schema.TextField;
-
-import java.io.Writer;
-import java.io.IOException;
-import java.util.*;
-
-import org.apache.lucene.document.Fieldable;
-import org.apache.lucene.document.Document;
 
 
 public final class XMLWriter extends TextResponseWriter {
@@ -166,257 +162,59 @@ public final class XMLWriter extends Tex
     }
   }
 
-  private static final Comparator fieldnameComparator = new Comparator() {
-    public int compare(Object o, Object o1) {
-      Fieldable f1 = (Fieldable)o; Fieldable f2 = (Fieldable)o1;
-      int cmp = f1.name().compareTo(f2.name());
-      return cmp;
-      // note - the sort is stable, so this should not have affected the ordering
-      // of fields with the same name w.r.t eachother.
-    }
-  };
 
   @Override
-  public final void writeDoc(String name, Document doc, Set<String> returnFields, float score, boolean includeScore) throws IOException {
-    startTag("doc", name, false);
-    incLevel();
-
-    if (includeScore) {
-      writeFloat("score", score);
-    }
-
-
-    // Lucene Documents have multivalued types as multiple fields
-    // with the same name.
-    // The XML needs to represent these as
-    // an array.  The fastest way to detect multiple fields
-    // with the same name is to sort them first.
-
-
-    // using global tlst here, so we shouldn't call any other
-    // function that uses it until we are done.
-    tlst.clear();
-    for (Object obj : doc.getFields()) {
-      Fieldable ff = (Fieldable)obj;
-      // skip this field if it is not a field to be returned.
-      if (returnFields!=null && !returnFields.contains(ff.name())) {
-        continue;
-      }
-      tlst.add(ff);
-    }
-    Collections.sort(tlst, fieldnameComparator);
-
-    int sz = tlst.size();
-    int fidx1 = 0, fidx2 = 0;
-    while (fidx1 < sz) {
-      Fieldable f1 = (Fieldable)tlst.get(fidx1);
-      String fname = f1.name();
-
-      // find the end of fields with this name
-      fidx2 = fidx1+1;
-      while (fidx2 < sz && fname.equals(((Fieldable)tlst.get(fidx2)).name()) ) {
-        fidx2++;
-      }
-
-      /***
-      // more efficient to use getFieldType instead of
-      // getField since that way dynamic fields won't have
-      // to create a SchemaField on the fly.
-      FieldType ft = schema.getFieldType(fname);
-      ***/
-
-      SchemaField sf = schema.getFieldOrNull(fname);
-      if( sf == null ) {
-        sf = new SchemaField( fname, new TextField() );
-      }
-      if (fidx1+1 == fidx2) {
-        // single field value
-        if (sf.multiValued()) {
-          startTag("arr",fname,false);
-          doIndent=false;
-          sf.write(this, null, f1);
-          writer.write("</arr>");
-          doIndent=defaultIndent;
-        } else {
-          sf.write(this, f1.name(), f1);
-        }
-      } else {
-        // multiple fields with same name detected
+  public void writeStartDocumentList(String name, 
+      long start, int size, long numFound, Float maxScore) throws IOException
+  {
+    if (doIndent) indent();
 
-        startTag("arr",fname,false);
-        incLevel();
-        doIndent=false;
-        int cnt=0;
-        for (int i=fidx1; i<fidx2; i++) {
-          if (defaultIndent && ++cnt==4) { // only indent every 4th item
-            indent();
-            cnt=0;
-          }
-          sf.write(this, null, (Fieldable)tlst.get(i));
-        }
-        decLevel();
-        // if (doIndent) indent();
-        writer.write("</arr>");
-        // doIndent=true;
-        doIndent=defaultIndent;
-      }
-      fidx1 = fidx2;
+    writer.write("<result");
+    writeAttr("name",name);
+    writeAttr("numFound",Long.toString(numFound));
+    writeAttr("start",Long.toString(start));
+    if(maxScore!=null) {
+      writeAttr("maxScore",Float.toString(maxScore));
     }
-
-    decLevel();
-    if (doIndent) indent();
-    writer.write("</doc>");
+    writer.write(">");
+    
+    incLevel();
   }
 
+
+  /**
+   * The SolrDocument should already have multivalued fields implemented as
+   * Collections -- this will not rewrite to <arr>
+   */ 
   @Override
-  public void writeSolrDocument(String name, SolrDocument doc, Set<String> returnFields, Map pseudoFields) throws IOException {
+  public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx ) throws IOException {
     startTag("doc", name, false);
     incLevel();
 
     for (String fname : doc.getFieldNames()) {
-      if (returnFields!=null && !returnFields.contains(fname)) {
+      if (!returnFields.contains(fname)) {
         continue;
       }
+      
       Object val = doc.getFieldValue(fname);
-
-      if (val instanceof Collection) {
-        writeVal(fname, val);
-      } else {
-        // single valued... figure out if we should put <arr> tags around it anyway
-        SchemaField sf = schema.getFieldOrNull(fname);
-        if (sf!=null && sf.multiValued()) {
-          startTag("arr",fname,false);
-          doIndent=false;
-          writeVal(fname, val);
-          writer.write("</arr>");
-          doIndent=defaultIndent;
-        } else {
-          writeVal(fname, val);
-        }
-      }
-    }
-
-    if (pseudoFields != null) {
-      for (Object fname : pseudoFields.keySet()) {
-        writeVal(fname.toString(), pseudoFields.get(fname));
+      if( "_explain_".equals( fname ) ) {
+        System.out.println( val );
       }
+      writeVal(fname, val);
     }
-
+    
     decLevel();
-    if (doIndent) indent();
     writer.write("</doc>");
   }
-
-
-  private static interface DocumentListInfo {
-    Float getMaxScore();
-    int getCount();
-    long getNumFound();
-    long getStart();
-    void writeDocs( boolean includeScore, Set<String> fields ) throws IOException;
-  }
-
-  private final void writeDocuments(
-      String name,
-      DocumentListInfo docs,
-      Set<String> fields) throws IOException
+  
+  @Override
+  public void writeEndDocumentList() throws IOException
   {
-    boolean includeScore=false;
-    if (fields!=null) {
-      includeScore = fields.contains("score");
-      if (fields.size()==0 || (fields.size()==1 && includeScore) || fields.contains("*")) {
-        fields=null;  // null means return all stored fields
-      }
-    }
-
-    int sz=docs.getCount();
-    if (doIndent) indent();
-
-    writer.write("<result");
-    writeAttr("name",name);
-    writeAttr("numFound",Long.toString(docs.getNumFound()));
-    writeAttr("start",Long.toString(docs.getStart()));
-    if (includeScore && docs.getMaxScore()!=null) {
-      writeAttr("maxScore",Float.toString(docs.getMaxScore()));
-    }
-    if (sz==0) {
-      writer.write("/>");
-      return;
-    } else {
-      writer.write('>');
-    }
-
-    incLevel();
-    docs.writeDocs(includeScore, fields);
     decLevel();
-
     if (doIndent) indent();
     writer.write("</result>");
   }
 
-  @Override
-  public final void writeSolrDocumentList(String name, final SolrDocumentList docs, Set<String> fields, Map otherFields) throws IOException
-  {
-    this.writeDocuments( name, new DocumentListInfo()
-    {
-      public int getCount() {
-        return docs.size();
-      }
-
-      public Float getMaxScore() {
-        return docs.getMaxScore();
-      }
-
-      public long getNumFound() {
-        return docs.getNumFound();
-      }
-
-      public long getStart() {
-        return docs.getStart();
-      }
-
-      public void writeDocs(boolean includeScore, Set<String> fields) throws IOException {
-        for( SolrDocument doc : docs ) {
-          writeSolrDocument(null, doc, fields, null);
-        }
-      }
-    }, fields );
-  }
-
-  @Override
-  public void writeDocList(String name, final DocList ids, Set<String> fields, Map otherFields) throws IOException
-  {
-    this.writeDocuments( name, new DocumentListInfo()
-    {
-      public int getCount() {
-        return ids.size();
-      }
-
-      public Float getMaxScore() {
-        return ids.maxScore();
-      }
-
-      public long getNumFound() {
-        return ids.matches();
-      }
-
-      public long getStart() {
-        return ids.offset();
-      }
-
-      public void writeDocs(boolean includeScore, Set<String> fields) throws IOException {
-        SolrIndexSearcher searcher = req.getSearcher();
-        DocIterator iterator = ids.iterator();
-        int sz = ids.size();
-        includeScore = includeScore && ids.hasScores();
-        for (int i=0; i<sz; i++) {
-          int id = iterator.nextDoc();
-          Document doc = searcher.doc(id, fields);
-          writeDoc(null, doc, fields, (includeScore ? iterator.score() : 0.0f), includeScore);
-        }
-      }
-    }, fields );
-  }
 
 
   //

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocIdAugmenter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocIdAugmenter.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocIdAugmenter.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocIdAugmenter.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response.transform;
+
+import org.apache.solr.common.SolrDocument;
+
+/**
+ * Simple Transformer to add the lucene docid
+ *
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public class DocIdAugmenter extends DocTransformer
+{
+  final String name;
+
+  public DocIdAugmenter( String display )
+  {
+    this.name = display;
+  }
+
+  @Override
+  public void transform(SolrDocument doc, int docid) {
+    if( docid >= 0 ) {
+      doc.setField( name, docid );
+    }
+  }
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformer.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformer.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformer.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.response.transform;
+
+import java.io.IOException;
+
+import org.apache.solr.common.SolrDocument;
+
+/**
+ * New instance for each request
+ * 
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ */
+public abstract class DocTransformer
+{
+  public void setContext( TransformContext context ) {}
+  public abstract void transform(SolrDocument doc, int docid) throws IOException;
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformers.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformers.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformers.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocTransformers.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.response.transform;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.solr.common.SolrDocument;
+
+/**
+ * Transform a document before it gets sent out
+ * 
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ */
+public class DocTransformers extends DocTransformer
+{
+  final List<DocTransformer> children = new ArrayList<DocTransformer>();
+
+  public void addTransformer( DocTransformer a ) {
+    children.add( a );
+  }
+
+  public int size()
+  {
+    return children.size();
+  }
+
+  public DocTransformer getTransformer( int idx )
+  {
+    return children.get( idx );
+  }
+
+  @Override
+  public void setContext( TransformContext context ) {
+    for( DocTransformer a : children ) {
+      a.setContext( context );
+    }
+  }
+
+  @Override
+  public void transform(SolrDocument doc, int docid) throws IOException {
+    for( DocTransformer a : children ) {
+      a.transform( doc, docid );
+    }
+  }
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocValuesAugmenter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocValuesAugmenter.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocValuesAugmenter.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/DocValuesAugmenter.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response.transform;
+
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.search.function.DocValues;
+
+/**
+ * Add values from a ValueSource (function query etc)
+ *
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public class DocValuesAugmenter extends DocTransformer
+{
+  final String name;
+  final DocValues values;
+
+  public DocValuesAugmenter( String name, DocValues values )
+  {
+    this.name = name;
+    this.values = values;
+  }
+
+  @Override
+  public void transform(SolrDocument doc, int docid) {
+    // TODO, should know what the real type is -- not always string
+    Object v = values.strVal( docid );
+    doc.setField( name, v );
+  }
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ExplainAugmenter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ExplainAugmenter.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ExplainAugmenter.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ExplainAugmenter.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response.transform;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.Explanation;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.util.SolrPluginUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Add query explain info directly to Document
+ *
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public class ExplainAugmenter extends TransformerWithContext
+{
+  static final Logger log = LoggerFactory.getLogger( ExplainAugmenter.class );
+  final String name;
+
+  public ExplainAugmenter( String display )
+  {
+    this.name = display;
+  }
+
+  @Override
+  public void transform(SolrDocument doc, int docid) {
+    if( context != null && context.query != null ) {
+      try {
+        Explanation exp = context.searcher.explain(context.query, docid);
+        doc.setField( name, SolrPluginUtils.explanationToNamedList(exp) );
+      }
+      catch (IOException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ScoreAugmenter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ScoreAugmenter.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ScoreAugmenter.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/ScoreAugmenter.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response.transform;
+
+import org.apache.solr.common.SolrDocument;
+
+/**
+ * Simple Augmenter that adds the docId
+ *
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public class ScoreAugmenter extends TransformerWithContext
+{
+  final String name;
+
+  public ScoreAugmenter( String display )
+  {
+    this.name = display;
+  }
+
+  @Override
+  public void transform(SolrDocument doc, int docid) {
+    if( context != null && context.wantsScores ) {
+      if( context.iterator != null ) {
+        doc.setField( name, context.iterator.score() );
+      }
+    }
+  }
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformContext.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformContext.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformContext.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformContext.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response.transform;
+
+import org.apache.lucene.search.Query;
+import org.apache.solr.search.DocIterator;
+import org.apache.solr.search.SolrIndexSearcher;
+
+/**
+ * Environment variables for the transformed documents
+ * 
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public class TransformContext
+{
+  public Query query;
+  public boolean wantsScores = false;
+  public DocIterator iterator;
+  public SolrIndexSearcher searcher;
+}

Added: lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformerWithContext.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformerWithContext.java?rev=1085450&view=auto
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformerWithContext.java (added)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/response/transform/TransformerWithContext.java Fri Mar 25 16:24:21 2011
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.response.transform;
+
+
+/**
+ * @version $Id: JSONResponseWriter.java 1065304 2011-01-30 15:10:15Z rmuir $
+ * @since solr 4.0
+ */
+public abstract class TransformerWithContext extends DocTransformer
+{
+  protected TransformContext context = null;
+
+  @Override
+  public void setContext( TransformContext context ) {
+    this.context = context;
+  }
+}