You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2012/06/14 01:01:29 UTC

svn commit: r1350051 - in /lucene/dev/branches/branch_4x: ./ dev-tools/ lucene/ lucene/analysis/ lucene/analysis/common/ lucene/analysis/common/src/java/org/apache/lucene/analysis/standard/std31/ lucene/analysis/common/src/java/org/apache/lucene/analys...

Author: hossman
Date: Wed Jun 13 23:01:27 2012
New Revision: 1350051

URL: http://svn.apache.org/viewvc?rev=1350051&view=rev
Log:
SOLR-2599: CloneFieldUpdateProcessorFactory (merge r1350050 from trunk)

Added:
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/CloneFieldUpdateProcessorFactory.java
      - copied unchanged from r1350050, lucene/dev/trunk/solr/core/src/java/org/apache/solr/update/processor/CloneFieldUpdateProcessorFactory.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/IgnoreFieldUpdateProcessorFactory.java
      - copied unchanged from r1350050, lucene/dev/trunk/solr/core/src/java/org/apache/solr/update/processor/IgnoreFieldUpdateProcessorFactory.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/TruncateFieldUpdateProcessorFactory.java
      - copied unchanged from r1350050, lucene/dev/trunk/solr/core/src/java/org/apache/solr/update/processor/TruncateFieldUpdateProcessorFactory.java
Modified:
    lucene/dev/branches/branch_4x/   (props changed)
    lucene/dev/branches/branch_4x/dev-tools/   (props changed)
    lucene/dev/branches/branch_4x/lucene/   (props changed)
    lucene/dev/branches/branch_4x/lucene/BUILD.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/CHANGES.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/JRE_VERSION_MIGRATION.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/LICENSE.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/MIGRATE.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/NOTICE.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/README.txt   (props changed)
    lucene/dev/branches/branch_4x/lucene/analysis/   (props changed)
    lucene/dev/branches/branch_4x/lucene/analysis/common/   (props changed)
    lucene/dev/branches/branch_4x/lucene/analysis/common/src/java/org/apache/lucene/analysis/standard/std31/package.html   (props changed)
    lucene/dev/branches/branch_4x/lucene/analysis/common/src/java/org/apache/lucene/analysis/standard/std34/package.html   (props changed)
    lucene/dev/branches/branch_4x/lucene/backwards/   (props changed)
    lucene/dev/branches/branch_4x/lucene/benchmark/   (props changed)
    lucene/dev/branches/branch_4x/lucene/build.xml   (props changed)
    lucene/dev/branches/branch_4x/lucene/common-build.xml   (props changed)
    lucene/dev/branches/branch_4x/lucene/core/   (props changed)
    lucene/dev/branches/branch_4x/lucene/demo/   (props changed)
    lucene/dev/branches/branch_4x/lucene/facet/   (props changed)
    lucene/dev/branches/branch_4x/lucene/grouping/   (props changed)
    lucene/dev/branches/branch_4x/lucene/highlighter/   (props changed)
    lucene/dev/branches/branch_4x/lucene/ivy-settings.xml   (props changed)
    lucene/dev/branches/branch_4x/lucene/join/   (props changed)
    lucene/dev/branches/branch_4x/lucene/memory/   (props changed)
    lucene/dev/branches/branch_4x/lucene/misc/   (props changed)
    lucene/dev/branches/branch_4x/lucene/module-build.xml   (props changed)
    lucene/dev/branches/branch_4x/lucene/queries/   (props changed)
    lucene/dev/branches/branch_4x/lucene/queryparser/   (props changed)
    lucene/dev/branches/branch_4x/lucene/sandbox/   (props changed)
    lucene/dev/branches/branch_4x/lucene/site/   (props changed)
    lucene/dev/branches/branch_4x/lucene/spatial/   (props changed)
    lucene/dev/branches/branch_4x/lucene/suggest/   (props changed)
    lucene/dev/branches/branch_4x/lucene/test-framework/   (props changed)
    lucene/dev/branches/branch_4x/lucene/tools/   (props changed)
    lucene/dev/branches/branch_4x/solr/   (props changed)
    lucene/dev/branches/branch_4x/solr/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_4x/solr/LICENSE.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/NOTICE.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/README.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/build.xml   (props changed)
    lucene/dev/branches/branch_4x/solr/cloud-dev/   (props changed)
    lucene/dev/branches/branch_4x/solr/common-build.xml   (props changed)
    lucene/dev/branches/branch_4x/solr/contrib/   (props changed)
    lucene/dev/branches/branch_4x/solr/core/   (props changed)
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/FieldMutatingUpdateProcessorFactory.java
    lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/conf/solrconfig-update-processor-chains.xml
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/processor/FieldMutatingUpdateProcessorTest.java
    lucene/dev/branches/branch_4x/solr/dev-tools/   (props changed)
    lucene/dev/branches/branch_4x/solr/example/   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/httpclient-LICENSE-ASL.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/httpclient-NOTICE.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/httpcore-LICENSE-ASL.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/httpcore-NOTICE.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/httpmime-LICENSE-ASL.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/lib/httpmime-NOTICE.txt   (props changed)
    lucene/dev/branches/branch_4x/solr/scripts/   (props changed)
    lucene/dev/branches/branch_4x/solr/solrj/   (props changed)
    lucene/dev/branches/branch_4x/solr/test-framework/   (props changed)
    lucene/dev/branches/branch_4x/solr/testlogging.properties   (props changed)
    lucene/dev/branches/branch_4x/solr/webapp/   (props changed)

Modified: lucene/dev/branches/branch_4x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/CHANGES.txt?rev=1350051&r1=1350050&r2=1350051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_4x/solr/CHANGES.txt Wed Jun 13 23:01:27 2012
@@ -248,6 +248,8 @@ New Features
       LastFieldValueUpdateProcessorFactory
       MinFieldValueUpdateProcessorFactory
       MaxFieldValueUpdateProcessorFactory
+      TruncateFieldUpdateProcessorFactory
+      IgnoreFieldUpdateProcessorFactory 
   (hossman, janhoy)
 
 * SOLR-3120: Optional post filtering for spatial queries bbox and geofilt
@@ -353,6 +355,10 @@ New Features
   in cases where testing spellcheck collations for result counts should use different
   parameters from the main query (James Dyer)
 
+* SOLR-2599: CloneFieldUpdateProcessorFactory provides similar functionality 
+  to schema.xml's <copyField/> declaration but as an update processor that can 
+  be combined with other processors in any order. (Jan Høydahl & hossman)
+
 Optimizations
 ----------------------
 

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/FieldMutatingUpdateProcessorFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/FieldMutatingUpdateProcessorFactory.java?rev=1350051&r1=1350050&r2=1350051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/FieldMutatingUpdateProcessorFactory.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/update/processor/FieldMutatingUpdateProcessorFactory.java Wed Jun 13 23:01:27 2012
@@ -108,7 +108,7 @@ public abstract class FieldMutatingUpdat
   extends UpdateRequestProcessorFactory 
   implements SolrCoreAware {
   
-  private static class SelectorParams {
+  public static final class SelectorParams {
     public Set<String> fieldName = Collections.emptySet();
     public Set<String> typeName = Collections.emptySet();
     public Collection<String> typeClass = Collections.emptyList();
@@ -129,7 +129,7 @@ public abstract class FieldMutatingUpdat
   }
 
   @SuppressWarnings("unchecked")
-  private static final SelectorParams parseSelectorParams(NamedList args) {
+  public static SelectorParams parseSelectorParams(NamedList args) {
     SelectorParams params = new SelectorParams();
     
     params.fieldName = new HashSet<String>(oneOrMany(args, "fieldName"));
@@ -246,7 +246,7 @@ public abstract class FieldMutatingUpdat
    * to one or more strings (or arrays of strings)
    * @exception SolrException invalid arr/str structure.
    */
-  private static Collection<String> oneOrMany(final NamedList args, final String key) {
+  public static Collection<String> oneOrMany(final NamedList args, final String key) {
     List<String> result = new ArrayList<String>(args.size() / 2);
     final String err = "init arg '" + key + "' must be a string "
       + "(ie: 'str'), or an array (ie: 'arr') containing strings; found: ";

Modified: lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/conf/solrconfig-update-processor-chains.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/conf/solrconfig-update-processor-chains.xml?rev=1350051&r1=1350050&r2=1350051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/conf/solrconfig-update-processor-chains.xml (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test-files/solr/conf/solrconfig-update-processor-chains.xml Wed Jun 13 23:01:27 2012
@@ -224,6 +224,126 @@
     <processor class="solr.TrimFieldUpdateProcessorFactory"/>
   </updateRequestProcessorChain>
 
+  <updateRequestProcessorChain name="truncate">
+    <processor class="solr.TruncateFieldUpdateProcessorFactory">
+      <str name="fieldName">trunc</str>
+      <int name="maxLength">5</int>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="ignore-not-in-schema">
+    <processor class="solr.IgnoreFieldUpdateProcessorFactory" />
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="ignore-some">
+    <processor class="solr.IgnoreFieldUpdateProcessorFactory">
+      <str name="fieldRegex">.*_raw</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-single">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">source1_s</str>
+      <str name="dest">dest_s</str>
+    </processor>
+  </updateRequestProcessorChain>
+  <updateRequestProcessorChain name="clone-multi">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">source1_s</str>
+      <str name="source">source2_s</str>
+      <str name="dest">dest_s</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-array">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <arr name="source">
+        <str>source1_s</str>
+        <str>source2_s</str>
+      </arr>
+      <str name="dest">dest_s</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-selector">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <lst name="source">
+        <str name="fieldRegex">source\d_.*</str>
+        <lst name="exclude">
+          <str name="fieldRegex">source0_.*</str>
+        </lst>
+      </lst>
+      <str name="dest">dest_s</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-max-chars">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">field1</str>
+      <str name="dest">toField</str>
+    </processor>
+    <processor class="solr.TruncateFieldUpdateProcessorFactory">
+      <str name="fieldName">toField</str>
+      <int name="maxLength">3</int>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-move">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">field1</str>
+      <str name="dest">toField</str>
+    </processor>
+    <processor class="solr.IgnoreFieldUpdateProcessorFactory">
+      <str name="fieldName">field1</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-replace">
+    <processor class="solr.IgnoreFieldUpdateProcessorFactory">
+      <str name="fieldName">toField</str>
+    </processor>
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">field1</str>
+      <str name="dest">toField</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <updateRequestProcessorChain name="clone-append">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">field1</str>
+      <str name="source">field2</str>
+      <str name="dest">toField</str>
+    </processor>
+    <processor class="solr.ConcatFieldUpdateProcessorFactory">
+      <str name="delimiter">; </str>
+      <str name="fieldName">toField</str>
+    </processor>
+  </updateRequestProcessorChain>
+
+  <!-- example used in CloneFieldUpdateProcessorFactory javadocs -->
+  <updateRequestProcessorChain name="multiple-clones">
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <str name="source">category</str>
+      <str name="dest">category_s</str>
+    </processor>
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <arr name="source">
+        <str>authors</str>
+        <str>editors</str>
+      </arr>
+      <str name="dest">contributors</str>
+    </processor>
+    <processor class="solr.CloneFieldUpdateProcessorFactory">
+      <lst name="source">
+        <str name="fieldRegex">.*_price</str>
+        <lst name="exclude">
+          <str name="fieldName">list_price</str>
+        </lst>
+      </lst>
+      <str name="dest">all_prices</str>
+    </processor>
+  </updateRequestProcessorChain>
+
   <updateRequestProcessorChain name="regex-replace">
     <processor class="solr.RegexReplaceProcessorFactory">
       <str name="fieldName">content</str>

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/processor/FieldMutatingUpdateProcessorTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/processor/FieldMutatingUpdateProcessorTest.java?rev=1350051&r1=1350050&r2=1350051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/processor/FieldMutatingUpdateProcessorTest.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/processor/FieldMutatingUpdateProcessorTest.java Wed Jun 13 23:01:27 2012
@@ -34,6 +34,7 @@ import org.apache.solr.common.params.Mod
 import org.apache.solr.common.params.SolrParams;
 
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.schema.IndexSchema;
 
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.LocalSolrQueryRequest;
@@ -86,13 +87,8 @@ public class FieldMutatingUpdateProcesso
             ,"//long[@name='first_foo_l'][.='"+count+"']"
             ,"//long[@name='min_foo_l'][.='-34']"
             );
-
-
-
   }
 
-
-
   public void testTrimAll() throws Exception {
     SolrInputDocument d = null;
 
@@ -559,6 +555,213 @@ public class FieldMutatingUpdateProcesso
    
   }
 
+  public void testTruncate() throws Exception {
+    SolrInputDocument d = null;
+
+    d = processAdd("truncate", 
+                   doc(f("id", "1111"),
+                       f("trunc", "123456789", "", 42, "abcd")));
+
+    assertNotNull(d);
+
+    assertEquals(Arrays.asList("12345", "", 42, "abcd"),
+                 d.getFieldValues("trunc"));
+  }
+
+  public void testIgnore() throws Exception {
+
+    IndexSchema schema = h.getCore().getSchema();
+    assertNull("test expects 'foo_giberish' to not be a valid field, looks like schema was changed out from under us",
+               schema.getFieldTypeNoEx("foo_giberish"));
+    assertNotNull("test expects 't_raw' to be a valid field, looks like schema was changed out from under us",
+                  schema.getFieldTypeNoEx("t_raw"));
+    assertNotNull("test expects 'foo_s' to be a valid field, looks like schema was changed out from under us",
+                  schema.getFieldTypeNoEx("foo_s"));
+ 
+    SolrInputDocument d = null;
+    
+    d = processAdd("ignore-not-in-schema",       
+                   doc(f("id", "1111"),
+                       f("foo_giberish", "123456789", "", 42, "abcd"),
+                       f("t_raw", "123456789", "", 42, "abcd"),
+                       f("foo_s", "hoss")));
+    
+    assertNotNull(d);
+    assertFalse(d.containsKey("foo_giberish"));
+    assertEquals(Arrays.asList("123456789", "", 42, "abcd"), 
+                 d.getFieldValues("t_raw"));
+    assertEquals("hoss", d.getFieldValue("foo_s"));
+
+    d = processAdd("ignore-some",
+                   doc(f("id", "1111"),
+                       f("foo_giberish", "123456789", "", 42, "abcd"),
+                       f("t_raw", "123456789", "", 42, "abcd"),
+                       f("foo_s", "hoss")));
+
+    assertNotNull(d);
+    assertEquals(Arrays.asList("123456789", "", 42, "abcd"), 
+                 d.getFieldValues("foo_giberish"));
+    assertFalse(d.containsKey("t_raw"));
+    assertEquals("hoss", d.getFieldValue("foo_s"));
+    
+
+  }
+
+  public void testCloneField() throws Exception {
+
+    SolrInputDocument d = null;
+
+    // regardless of chain, all of these should be equivilent
+    for (String chain : Arrays.asList("clone-single", "clone-multi", 
+                                      "clone-array","clone-selector" )) {
+
+      // simple clone
+      d = processAdd(chain,       
+                     doc(f("id", "1111"),
+                         f("source0_s", "NOT COPIED"),
+                         f("source1_s", "123456789", "", 42, "abcd")));
+      assertNotNull(chain, d);
+      assertEquals(chain,
+                   Arrays.asList("123456789", "", 42, "abcd"), 
+                   d.getFieldValues("source1_s"));
+      assertEquals(chain,
+                   Arrays.asList("123456789", "", 42, "abcd"), 
+                   d.getFieldValues("dest_s"));
+
+      // append to existing values, preserve boost
+      d = processAdd(chain,       
+                     doc(f("id", "1111"),
+                         field("dest_s", 2.3f, "orig1", "orig2"),
+                         f("source0_s", "NOT COPIED"),
+                         f("source1_s", "123456789", "", 42, "abcd")));
+      assertNotNull(chain, d);
+      assertEquals(chain,
+                   Arrays.asList("123456789", "", 42, "abcd"), 
+                   d.getFieldValues("source1_s"));
+      assertEquals(chain,
+                   Arrays.asList("orig1", "orig2", "123456789", "", 42, "abcd"),
+                   d.getFieldValues("dest_s"));
+      assertEquals(chain + ": dest boost changed", 
+                   2.3f, d.getField("dest_s").getBoost(), 0.0f);
+    }
+
+    // should be equivilent for any chain matching source1_s and source2_s
+    for (String chain : Arrays.asList("clone-multi",
+                                      "clone-array","clone-selector" )) {
+
+      // simple clone
+      d = processAdd(chain,       
+                     doc(f("id", "1111"),
+                         f("source0_s", "NOT COPIED"),
+                         f("source1_s", "123456789", "", 42, "abcd"),
+                         f("source2_s", "xxx", 999)));
+      assertNotNull(chain, d);
+      assertEquals(chain,
+                   Arrays.asList("123456789", "", 42, "abcd"), 
+                   d.getFieldValues("source1_s"));
+      assertEquals(chain,
+                   Arrays.asList("xxx", 999),
+                   d.getFieldValues("source2_s"));
+      assertEquals(chain,
+                   Arrays.asList("123456789", "", 42, "abcd", "xxx", 999), 
+                   d.getFieldValues("dest_s"));
+
+      // append to existing values, preserve boost
+      d = processAdd(chain,       
+                     doc(f("id", "1111"),
+                         field("dest_s", 2.3f, "orig1", "orig2"),
+                         f("source0_s", "NOT COPIED"),
+                         f("source1_s", "123456789", "", 42, "abcd"),
+                         f("source2_s", "xxx", 999)));
+      assertNotNull(chain, d);
+      assertEquals(chain,
+                   Arrays.asList("123456789", "", 42, "abcd"), 
+                   d.getFieldValues("source1_s"));
+      assertEquals(chain,
+                   Arrays.asList("xxx", 999),
+                   d.getFieldValues("source2_s"));
+      assertEquals(chain,
+                   Arrays.asList("orig1", "orig2", 
+                                 "123456789", "", 42, "abcd",
+                                 "xxx", 999),
+                   d.getFieldValues("dest_s"));
+      assertEquals(chain + ": dest boost changed", 
+                   2.3f, d.getField("dest_s").getBoost(), 0.0f);
+    }
+  }
+
+  public void testCloneFieldExample() throws Exception {
+
+    SolrInputDocument d = null;
+
+    // test example from the javadocs
+    d = processAdd("multiple-clones",       
+                   doc(f("id", "1111"),
+                       f("category", "misc"),
+                       f("authors", "Isaac Asimov", "John Brunner"),
+                       f("editors", "John W. Campbell"),
+                       f("store1_price", 87),
+                       f("store2_price", 78),
+                       f("list_price", 1000)));
+    assertNotNull(d);
+    assertEquals("misc",d.getFieldValue("category"));
+    assertEquals("misc",d.getFieldValue("category_s"));
+    assertEquals(Arrays.asList("Isaac Asimov", "John Brunner"),
+                 d.getFieldValues("authors"));
+    assertEquals(Arrays.asList("John W. Campbell"),
+                 d.getFieldValues("editors"));
+    assertEquals(Arrays.asList("Isaac Asimov", "John Brunner", 
+                               "John W. Campbell"),
+                 d.getFieldValues("contributors"));
+    assertEquals(87,d.getFieldValue("store1_price"));
+    assertEquals(78,d.getFieldValue("store2_price"));
+    assertEquals(1000,d.getFieldValue("list_price"));
+    assertEquals(Arrays.asList(87, 78),
+                 d.getFieldValues("all_prices"));
+
+  } 
+
+  public void testCloneCombinations() throws Exception {
+
+    SolrInputDocument d = null;
+
+    // maxChars
+    d = processAdd("clone-max-chars",
+                   doc(f("id", "1111"),
+                       f("field1", "text")));
+    assertNotNull(d);
+    assertEquals("text",d.getFieldValue("field1"));
+    assertEquals("tex",d.getFieldValue("toField"));
+
+    // move
+    d = processAdd("clone-move",
+                   doc(f("id", "1111"),
+                       f("field1", "text")));
+    assertNotNull(d);
+    assertEquals("text",d.getFieldValue("toField"));
+    assertFalse(d.containsKey("field1"));
+
+    // replace
+    d = processAdd("clone-replace",
+                   doc(f("id", "1111"),
+                       f("toField", "IGNORED"),
+                       f("field1", "text")));
+    assertNotNull(d);
+    assertEquals("text", d.getFieldValue("field1"));
+    assertEquals("text", d.getFieldValue("toField"));
+
+    // append
+    d = processAdd("clone-append",
+                   doc(f("id", "1111"),
+                       f("toField", "aaa"),
+                       f("field1", "bbb"),
+                       f("field2", "ccc")));
+    assertNotNull(d);
+    assertEquals("bbb", d.getFieldValue("field1"));
+    assertEquals("ccc", d.getFieldValue("field2"));
+    assertEquals("aaa; bbb; ccc", d.getFieldValue("toField"));
+  } 
+
   public void testConcatDefaults() throws Exception {
     SolrInputDocument d = null;
     d = processAdd("concat-defaults",