Re: svn commit: r1683134 - in /lucene/dev/branches/branch_5x/solr: ./ core/src/java/org/apache/solr/response/ core/src/java/org/apache/solr/response/transform/ core/src/java/org/apache/solr/search/ core/src/test-files/solr/collection1/conf/ core/src/test/o...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: svn commit: r1683134 - in /lucene/dev/branches/branch_5x/solr: ./ core/src/java/org/apache/solr/response/ core/src/java/org/apache/solr/response/transform/ core/src/java/org/apache/solr/search/ core/src/test-files/solr/collection1/conf/ core/src/test/o...

Erik Hatcher-6
Ryan - check “ant precommit” - 

/Users/erikhatcher/dev/clean-branch_5x/extra-targets.xml:204: The following files are missing svn:eol-style (or binary svn:mime-type):
* ./solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml
* ./solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java

Erik Hatcher, Senior Solutions Architect




On Jun 2, 2015, at 12:42 PM, [hidden email] wrote:

Author: ryan
Date: Tue Jun  2 16:42:47 2015
New Revision: 1683134

URL: http://svn.apache.org/r1683134
Log:
SOLR-7622: let DocTransformers request extra fields

Added:
   lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml
   lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java
Modified:
   lucene/dev/branches/branch_5x/solr/CHANGES.txt
   lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java
   lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java
   lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java

Modified: lucene/dev/branches/branch_5x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/CHANGES.txt?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/solr/CHANGES.txt Tue Jun  2 16:42:47 2015
@@ -29,6 +29,10 @@ New Features
* SOLR-7389: Expose znodeVersion property for each of the collections returned for the clusterstatus
  operation in the collections API (Marius Grama via shalin)

+* SOLR-7622: A DocTransformer can now request fields from the SolrIndexSearcher that are not
+  necessarily returned in the file SolrDocument by returning a list of fields from
+  DocTransformer#getExtraRequestFields  (ryan)
+
Bug Fixes
----------------------


Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java Tue Jun  2 16:42:47 2015
@@ -54,4 +54,15 @@ public class ResponseWriterUtil {
    }
    return out;
  }
+
+  public static String getAsString(String field, SolrDocument doc) {
+    Object v = doc.getFirstValue(field);
+    if(v != null) {
+      if(v instanceof IndexableField) {
+        return ((IndexableField)v).stringValue();
+      }
+      return v.toString();
+    }
+    return null;
+  }
}

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java Tue Jun  2 16:42:47 2015
@@ -20,7 +20,9 @@ package org.apache.solr.response.transfo
import java.io.IOException;

import org.apache.solr.common.SolrDocument;
-import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.QueryResponseWriter;
+import org.apache.solr.response.ResponseWriterUtil;
+import org.apache.solr.search.SolrIndexSearcher;

/**
 * A DocTransformer can add, remove or alter a Document before it is written out to the Response.  For instance, there are implementations
@@ -57,6 +59,19 @@ public abstract class DocTransformer
   */
  public abstract void transform(SolrDocument doc, int docid) throws IOException;

+  /**
+   * When a transformer needs access to fields that are not automaticaly derived from the
+   * input fields names, this option lets us explicitly say the field names that we hope
+   * will be in the SolrDocument.  These fields will be requestd from the
+   * {@link SolrIndexSearcher} but may or may not be returned in the final
+   * {@link QueryResponseWriter}
+   *
+   * @return a list of extra lucene fields
+   */
+  public String[] getExtraRequestFields() {
+    return null;
+  }
+  
  @Override
  public String toString() {
    return getName();

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java Tue Jun  2 16:42:47 2015
@@ -264,6 +264,14 @@ public class SolrReturnFields extends Re
            MapSolrParams augmenterParams = new MapSolrParams( augmenterArgs );
            DocTransformer t = factory.create(disp, augmenterParams, req);
            if(t!=null) {
+              if(!_wantsAllFields) {
+                String[] extra = t.getExtraRequestFields();
+                if(extra!=null) {
+                  for(String f : extra) {
+                    fields.add(f); // also request this field from IndexSearcher
+                  }
+                }
+              }
              augmenters.addTransformer( t );
            }
          }

Added: lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml?rev=1683134&view=auto
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml (added)
+++ lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml Tue Jun  2 16:42:47 2015
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+ This is a stripped down config file used for a simple example...
+ It is *not* a good example to work from.
+-->
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
+  <indexConfig>
+    <useCompoundFile>${useCompoundFile:false}</useCompoundFile>
+  </indexConfig>
+  <dataDir>${solr.data.dir:}</dataDir>
+  <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.StandardDirectoryFactory}"/>
+
+  <updateHandler class="solr.DirectUpdateHandler2">
+    <updateLog>
+      <str name="dir">${solr.data.dir:}</str>
+    </updateLog>
+  </updateHandler>
+
+  <transformer name="custom" class="org.apache.solr.response.TestCustomDocTransformer$CustomTransformerFactory" />
+
+  <requestHandler name="/select" class="solr.StandardRequestHandler"/>
+
+  <requestDispatcher handleSelect="true" >
+    <requestParsers enableRemoteStreaming="false" multipartUploadLimitInKB="2048" />
+  </requestDispatcher>
+
+  <requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
+
+  <!-- config for the admin interface -->
+  <admin>
+    <defaultQuery>solr</defaultQuery>
+  </admin>
+
+</config>
+

Added: lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java?rev=1683134&view=auto
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java (added)
+++ lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java Tue Jun  2 16:42:47 2015
@@ -0,0 +1,118 @@
+package org.apache.solr.response;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.transform.DocTransformer;
+import org.apache.solr.response.transform.TransformerFactory;
+import org.bouncycastle.util.Strings;
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestCustomDocTransformer extends SolrTestCaseJ4 {
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-doctransformers.xml","schema.xml");
+  }
+
+  @After
+  public void cleanup() throws Exception {
+    assertU(delQ("*:*"));
+    assertU(commit());
+  }
+
+  @Test
+  public void testCustomTransformer() throws Exception {
+    // Build a simple index
+    int max = 10;
+    for(int i=0; i<max; i++) {
+      SolrInputDocument sdoc = new SolrInputDocument();
+      sdoc.addField("id", i);
+      sdoc.addField("subject", "xx");
+      sdoc.addField("title", "title_"+i);
+      updateJ(jsonAdd(sdoc), null);
+    }
+    assertU(commit());
+    assertQ(req("q", "*:*"), "//*[@numFound='" + max + "']");
+    
+    assertQ( req(
+        "q", "*:*",
+        "fl", "id,out:[custom extra=subject,title]"),
+        // Check that the concatinated fields make it in the results
+        "//*[@numFound='" + max + "']",
+        "//str[.='xx#title_0#']",
+        "//str[.='xx#title_1#']",
+        "//str[.='xx#title_2#']",
+        "//str[.='xx#title_3#']");
+  }
+  
+  public static class CustomTransformerFactory extends TransformerFactory {
+    @Override
+    public DocTransformer create(String field, SolrParams params, SolrQueryRequest req) {
+      String[] extra = null;
+      String ext = params.get("extra");
+      if(ext!=null) {
+        extra = Strings.split(ext, ',');
+      }
+      return new CustomTransformer(field, extra);
+    }
+  }
+  
+  public static class CustomTransformer extends DocTransformer {
+    final String name;
+    final String[] extra;
+    final StringBuilder str = new StringBuilder();
+    
+    public CustomTransformer(String name, String[] extra) {
+      this.name = name;
+      this.extra = extra;
+    }
+    
+    @Override
+    public String getName() {
+      return "custom";
+    }
+
+    @Override
+    public String[] getExtraRequestFields() {
+      return extra;
+    }
+
+    /**
+     * This transformer simply concatinates the values of multipe fields
+     */
+    @Override
+    public void transform(SolrDocument doc, int docid) throws IOException {
+      str.setLength(0);
+      for(String s : extra) {
+        String v = ResponseWriterUtil.getAsString(s, doc);
+        str.append(v).append('#');
+      }
+      System.out.println( "HELLO: "+str );
+      doc.setField(name, str.toString());
+    }
+  }
+}



Reply | Threaded
Open this post in threaded view
|

Re: svn commit: r1683134 - in /lucene/dev/branches/branch_5x/solr: ./ core/src/java/org/apache/solr/response/ core/src/java/org/apache/solr/response/transform/ core/src/java/org/apache/solr/search/ core/src/test-files/solr/collection1/conf/ core/src/test/o...

Ryan McKinley
thanks -- i'm on it

On Tue, Jun 2, 2015 at 11:52 AM, Erik Hatcher <[hidden email]> wrote:
Ryan - check “ant precommit” - 

/Users/erikhatcher/dev/clean-branch_5x/extra-targets.xml:204: The following files are missing svn:eol-style (or binary svn:mime-type):
* ./solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml
* ./solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java

Erik Hatcher, Senior Solutions Architect




On Jun 2, 2015, at 12:42 PM, [hidden email] wrote:

Author: ryan
Date: Tue Jun  2 16:42:47 2015
New Revision: 1683134

URL: http://svn.apache.org/r1683134
Log:
SOLR-7622: let DocTransformers request extra fields

Added:
   lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml
   lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java
Modified:
   lucene/dev/branches/branch_5x/solr/CHANGES.txt
   lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java
   lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java
   lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java

Modified: lucene/dev/branches/branch_5x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/CHANGES.txt?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/solr/CHANGES.txt Tue Jun  2 16:42:47 2015
@@ -29,6 +29,10 @@ New Features
* SOLR-7389: Expose znodeVersion property for each of the collections returned for the clusterstatus
  operation in the collections API (Marius Grama via shalin)

+* SOLR-7622: A DocTransformer can now request fields from the SolrIndexSearcher that are not
+  necessarily returned in the file SolrDocument by returning a list of fields from
+  DocTransformer#getExtraRequestFields  (ryan)
+
Bug Fixes
----------------------


Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/ResponseWriterUtil.java Tue Jun  2 16:42:47 2015
@@ -54,4 +54,15 @@ public class ResponseWriterUtil {
    }
    return out;
  }
+
+  public static String getAsString(String field, SolrDocument doc) {
+    Object v = doc.getFirstValue(field);
+    if(v != null) {
+      if(v instanceof IndexableField) {
+        return ((IndexableField)v).stringValue();
+      }
+      return v.toString();
+    }
+    return null;
+  }
}

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/response/transform/DocTransformer.java Tue Jun  2 16:42:47 2015
@@ -20,7 +20,9 @@ package org.apache.solr.response.transfo
import java.io.IOException;

import org.apache.solr.common.SolrDocument;
-import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.QueryResponseWriter;
+import org.apache.solr.response.ResponseWriterUtil;
+import org.apache.solr.search.SolrIndexSearcher;

/**
 * A DocTransformer can add, remove or alter a Document before it is written out to the Response.  For instance, there are implementations
@@ -57,6 +59,19 @@ public abstract class DocTransformer
   */
  public abstract void transform(SolrDocument doc, int docid) throws IOException;

+  /**
+   * When a transformer needs access to fields that are not automaticaly derived from the
+   * input fields names, this option lets us explicitly say the field names that we hope
+   * will be in the SolrDocument.  These fields will be requestd from the
+   * {@link SolrIndexSearcher} but may or may not be returned in the final
+   * {@link QueryResponseWriter}
+   *
+   * @return a list of extra lucene fields
+   */
+  public String[] getExtraRequestFields() {
+    return null;
+  }
+  
  @Override
  public String toString() {
    return getName();

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java?rev=1683134&r1=1683133&r2=1683134&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java Tue Jun  2 16:42:47 2015
@@ -264,6 +264,14 @@ public class SolrReturnFields extends Re
            MapSolrParams augmenterParams = new MapSolrParams( augmenterArgs );
            DocTransformer t = factory.create(disp, augmenterParams, req);
            if(t!=null) {
+              if(!_wantsAllFields) {
+                String[] extra = t.getExtraRequestFields();
+                if(extra!=null) {
+                  for(String f : extra) {
+                    fields.add(f); // also request this field from IndexSearcher
+                  }
+                }
+              }
              augmenters.addTransformer( t );
            }
          }

Added: lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml?rev=1683134&view=auto
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml (added)
+++ lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/solrconfig-doctransformers.xml Tue Jun  2 16:42:47 2015
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+ This is a stripped down config file used for a simple example...
+ It is *not* a good example to work from.
+-->
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
+  <indexConfig>
+    <useCompoundFile>${useCompoundFile:false}</useCompoundFile>
+  </indexConfig>
+  <dataDir>${solr.data.dir:}</dataDir>
+  <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.StandardDirectoryFactory}"/>
+
+  <updateHandler class="solr.DirectUpdateHandler2">
+    <updateLog>
+      <str name="dir">${solr.data.dir:}</str>
+    </updateLog>
+  </updateHandler>
+
+  <transformer name="custom" class="org.apache.solr.response.TestCustomDocTransformer$CustomTransformerFactory" />
+
+  <requestHandler name="/select" class="solr.StandardRequestHandler"/>
+
+  <requestDispatcher handleSelect="true" >
+    <requestParsers enableRemoteStreaming="false" multipartUploadLimitInKB="2048" />
+  </requestDispatcher>
+
+  <requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
+
+  <!-- config for the admin interface -->
+  <admin>
+    <defaultQuery>solr</defaultQuery>
+  </admin>
+
+</config>
+

Added: lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java?rev=1683134&view=auto
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java (added)
+++ lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/response/TestCustomDocTransformer.java Tue Jun  2 16:42:47 2015
@@ -0,0 +1,118 @@
+package org.apache.solr.response;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.transform.DocTransformer;
+import org.apache.solr.response.transform.TransformerFactory;
+import org.bouncycastle.util.Strings;
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestCustomDocTransformer extends SolrTestCaseJ4 {
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-doctransformers.xml","schema.xml");
+  }
+
+  @After
+  public void cleanup() throws Exception {
+    assertU(delQ("*:*"));
+    assertU(commit());
+  }
+
+  @Test
+  public void testCustomTransformer() throws Exception {
+    // Build a simple index
+    int max = 10;
+    for(int i=0; i<max; i++) {
+      SolrInputDocument sdoc = new SolrInputDocument();
+      sdoc.addField("id", i);
+      sdoc.addField("subject", "xx");
+      sdoc.addField("title", "title_"+i);
+      updateJ(jsonAdd(sdoc), null);
+    }
+    assertU(commit());
+    assertQ(req("q", "*:*"), "//*[@numFound='" + max + "']");
+    
+    assertQ( req(
+        "q", "*:*",
+        "fl", "id,out:[custom extra=subject,title]"),
+        // Check that the concatinated fields make it in the results
+        "//*[@numFound='" + max + "']",
+        "//str[.='xx#title_0#']",
+        "//str[.='xx#title_1#']",
+        "//str[.='xx#title_2#']",
+        "//str[.='xx#title_3#']");
+  }
+  
+  public static class CustomTransformerFactory extends TransformerFactory {
+    @Override
+    public DocTransformer create(String field, SolrParams params, SolrQueryRequest req) {
+      String[] extra = null;
+      String ext = params.get("extra");
+      if(ext!=null) {
+        extra = Strings.split(ext, ',');
+      }
+      return new CustomTransformer(field, extra);
+    }
+  }
+  
+  public static class CustomTransformer extends DocTransformer {
+    final String name;
+    final String[] extra;
+    final StringBuilder str = new StringBuilder();
+    
+    public CustomTransformer(String name, String[] extra) {
+      this.name = name;
+      this.extra = extra;
+    }
+    
+    @Override
+    public String getName() {
+      return "custom";
+    }
+
+    @Override
+    public String[] getExtraRequestFields() {
+      return extra;
+    }
+
+    /**
+     * This transformer simply concatinates the values of multipe fields
+     */
+    @Override
+    public void transform(SolrDocument doc, int docid) throws IOException {
+      str.setLength(0);
+      for(String s : extra) {
+        String v = ResponseWriterUtil.getAsString(s, doc);
+        str.append(v).append('#');
+      }
+      System.out.println( "HELLO: "+str );
+      doc.setField(name, str.toString());
+    }
+  }
+}