You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by is...@apache.org on 2017/03/19 15:57:36 UTC

[02/12] lucene-solr:jira/solr-6736: Merge master into jira/solr-6736 branch

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/search/TestMultiWordSynonyms.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestMultiWordSynonyms.java b/solr/core/src/test/org/apache/solr/search/TestMultiWordSynonyms.java
new file mode 100644
index 0000000..ecc80c3
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/search/TestMultiWordSynonyms.java
@@ -0,0 +1,100 @@
+/*
+ * 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.search;
+
+import java.util.Arrays;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestMultiWordSynonyms extends SolrTestCaseJ4 {
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig.xml", "schema-multiword-synonyms.xml");
+    index();
+  }
+
+  private static void index() throws Exception {
+    assertU(adoc("id","1", "text","USA Today"));
+    assertU(adoc("id","2", "text","A dynamic US economy"));
+    assertU(adoc("id","3", "text","The United States of America's 50 states"));
+    assertU(adoc("id","4", "text","Party in the U.S.A."));
+    assertU(adoc("id","5", "text","These United States"));
+
+    assertU(adoc("id","6", "text","America United of States"));
+    assertU(adoc("id","7", "text","States United"));
+
+    assertU(commit());
+  }
+
+  @Test
+  public void testNonPhrase() throws Exception {
+    // Don't split on whitespace (sow=false)
+    for (String q : Arrays.asList("US", "U.S.", "USA", "U.S.A.", "United States", "United States of America")) {
+      for (String defType : Arrays.asList("lucene", "edismax")) {
+        assertJQ(req("q", q,
+            "defType", defType,
+            "df", "text",
+            "sow", "false")
+            , "/response/numFound==7"
+        );
+      }
+    }
+
+    // Split on whitespace (sow=true)
+    for (String q : Arrays.asList("US", "U.S.", "USA", "U.S.A.")) {
+      for (String defType : Arrays.asList("lucene", "edismax")) {
+        assertJQ(req("q", q,
+            "defType", defType,
+            "df", "text",
+            "sow", "true")
+            , "/response/numFound==7"
+        );
+      }
+    }
+    for (String q : Arrays.asList("United States", "United States of America")) {
+      for (String defType : Arrays.asList("lucene", "edismax")) {
+        assertJQ(req("q", q,
+            "defType", defType,
+            "df", "text",
+            "sow", "true")
+            , "/response/numFound==4"
+        );
+      }
+    }
+  }
+  
+  @Test
+  public void testPhrase() throws Exception {
+    for (String q : Arrays.asList
+        ("\"US\"", "\"U.S.\"", "\"USA\"", "\"U.S.A.\"", "\"United States\"", "\"United States of America\"")) {
+      for (String defType : Arrays.asList("lucene", "edismax")) {
+        for (String sow : Arrays.asList("true", "false")) {
+          assertJQ(req("q", q,
+              "defType", defType,
+              "df", "text",
+              "sow", sow)
+              , "/response/numFound==5"
+          );
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java b/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
index 2fe3740..8cd96ae 100644
--- a/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
+++ b/solr/core/src/test/org/apache/solr/search/TestSolr4Spatial.java
@@ -19,7 +19,6 @@ package org.apache.solr.search;
 import java.text.ParseException;
 import java.util.Arrays;
 
-import com.carrotsearch.randomizedtesting.RandomizedTest;
 import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
 import org.locationtech.spatial4j.context.SpatialContext;
 import org.locationtech.spatial4j.distance.DistanceUtils;
@@ -43,16 +42,18 @@ import org.junit.Test;
  */
 public class TestSolr4Spatial extends SolrTestCaseJ4 {
 
-  private String fieldName;
+  private final String fieldName;
+  private final boolean canCalcDistance;
 
   public TestSolr4Spatial(String fieldName) {
     this.fieldName = fieldName;
+    this.canCalcDistance = !fieldName.equals("llp_idx");
   }
 
   @ParametersFactory
   public static Iterable<Object[]> parameters() {
     return Arrays.asList(new Object[][]{
-        {"srpt_geohash"}, {"srpt_quad"}, {"srpt_packedquad"}, {"stqpt_geohash"}, {"pointvector"}, {"bbox"}
+        {"llp"}, {"llp_idx"}, {"llp_dv"}, {"srpt_geohash"}, {"srpt_quad"}, {"srpt_packedquad"}, {"stqpt_geohash"}, {"pointvector"}, {"bbox"}
     });
   }
 
@@ -105,6 +106,10 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
     assertU(adoc("id", "11", fieldName, "89.9,-130"));
     assertU(adoc("id", "12", fieldName, "-89.9,50"));
     assertU(adoc("id", "13", fieldName, "-89.9,-130"));
+    if (random().nextBoolean()) {
+      assertU(commit());
+    }
+    assertU(adoc("id", "99"));//blank
     assertU(commit());
   }
 
@@ -192,7 +197,7 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
     //Test using the Lucene spatial syntax
     {
       //never actually need the score but lets test
-      String score = new String[]{null, "none","distance","recipDistance"}[random().nextInt(4)];
+      String score = randomScoreMode();
 
       double distDEG = DistanceUtils.dist2Degrees(distKM, DistanceUtils.EARTH_MEAN_RADIUS_KM);
       Point point = SpatialUtils.parsePoint(ptStr, SpatialContext.GEO);
@@ -225,6 +230,10 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
 
   }
 
+  private String randomScoreMode() {
+    return canCalcDistance ? new String[]{null, "none","distance","recipDistance"}[random().nextInt(4)] : "none";
+  }
+
   @Test
   public void testRangeSyntax() {
     setupDocs();
@@ -232,10 +241,10 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
     int docId = 1;
     int count = 1;
 
-    String score = random().nextBoolean() ? "none" : "distance";//never actually need the score but lets test
+    String score = randomScoreMode();//never actually need the score but lets test
     assertQ(req(
         "fl", "id", "q","*:*", "rows", "1000",    // testing quotes in range too
-        "fq", "{! score="+score+" df="+fieldName+"}[32,-80 TO \"33 , -79\"]"),//lower-left to upper-right
+        "fq", "{! "+(score==null?"":" score="+score)+" df="+fieldName+"}[32,-80 TO \"33 , -79\"]"),//lower-left to upper-right
 
         "//result/doc/*[@name='id'][.='" + docId + "']",
         "*[count(//doc)=" + count + "]");
@@ -243,13 +252,46 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
 
   @Test
   public void testSort() throws Exception {
+    assumeTrue("dist sorting not supported on field " + fieldName, canCalcDistance);
     assertU(adoc("id", "100", fieldName, "1,2"));
     assertU(adoc("id", "101", fieldName, "4,-1"));
-    assertU(adoc("id", "999", fieldName, "70,70"));//far away from these queries
+    if (random().nextBoolean()) {
+      assertU(commit()); // new segment
+    }
+    if (random().nextBoolean()) {
+      assertU(adoc("id", "999", fieldName, "70,70"));//far away from these queries; we filter it out
+    } else {
+      assertU(adoc("id", "999")); // no data
+    }
     assertU(commit());
 
-    //test absence of score=distance means it doesn't score
 
+    // geodist asc
+    assertJQ(req(
+        "q", radiusQuery(3, 4, 9, null, null),
+        "fl","id",
+        "sort","geodist() asc",
+        "sfield", fieldName, "pt", "3,4")
+        , 1e-3
+        , "/response/docs/[0]/id=='100'"
+        , "/response/docs/[1]/id=='101'"
+    );
+    // geodist desc  (simply reverse the assertions)
+    assertJQ(req(
+        "q", radiusQuery(3, 4, 9, null, null),
+        "fl","id",
+        "sort","geodist() desc", // DESC
+        "sfield", fieldName, "pt", "3,4")
+        , 1e-3
+        , "/response/docs/[0]/id=='101'" // FLIPPED
+        , "/response/docs/[1]/id=='100'" // FLIPPED
+    );
+
+    //
+    //  NOTE: the rest work via the score of the spatial query. Generally, you should use geodist() instead.
+    //
+
+    //test absence of score=distance means it doesn't score
     assertJQ(req(
         "q", radiusQuery(3, 4, 9, null, null),
         "fl","id,score")
@@ -345,7 +387,8 @@ public class TestSolr4Spatial extends SolrTestCaseJ4 {
 
   @Test
   public void testSortMultiVal() throws Exception {
-    RandomizedTest.assumeFalse("Multivalue not supported for this field",
+    assumeTrue("dist sorting not supported on field " + fieldName, canCalcDistance);
+    assumeFalse("Multivalue not supported for this field",
         fieldName.equals("pointvector") || fieldName.equals("bbox"));
 
     assertU(adoc("id", "100", fieldName, "1,2"));//1 point

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheMBean.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheMBean.java b/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheMBean.java
index 35bdec6..d11c919 100644
--- a/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheMBean.java
+++ b/solr/core/src/test/org/apache/solr/search/TestSolrFieldCacheMBean.java
@@ -68,7 +68,7 @@ public class TestSolrFieldCacheMBean extends SolrTestCaseJ4 {
   private void assertEntryListIncluded(boolean checkJmx) {
     SolrFieldCacheMBean mbean = new SolrFieldCacheMBean();
     NamedList stats = checkJmx ? mbean.getStatisticsForJmx() : mbean.getStatistics();
-    assert(new Integer(stats.get("entries_count").toString()) > 0);
+    assert(Integer.parseInt(stats.get("entries_count").toString()) > 0);
     assertNotNull(stats.get("total_size"));
     assertNotNull(stats.get("entry#0"));
   }
@@ -76,7 +76,7 @@ public class TestSolrFieldCacheMBean extends SolrTestCaseJ4 {
   private void assertEntryListNotIncluded(boolean checkJmx) {
     SolrFieldCacheMBean mbean = new SolrFieldCacheMBean();
     NamedList stats = checkJmx ? mbean.getStatisticsForJmx() : mbean.getStatistics();
-    assert(new Integer(stats.get("entries_count").toString()) > 0);
+    assert(Integer.parseInt(stats.get("entries_count").toString()) > 0);
     assertNull(stats.get("total_size"));
     assertNull(stats.get("entry#0"));
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/search/TestSolrQueryParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestSolrQueryParser.java b/solr/core/src/test/org/apache/solr/search/TestSolrQueryParser.java
index 8195c05..92bd6c0 100644
--- a/solr/core/src/test/org/apache/solr/search/TestSolrQueryParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestSolrQueryParser.java
@@ -16,7 +16,12 @@
  */
 package org.apache.solr.search;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Random;
 
 import org.apache.lucene.search.BooleanClause;
@@ -28,12 +33,15 @@ import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermInSetQuery;
 import org.apache.lucene.search.TermQuery;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.core.SolrInfoMBean;
 import org.apache.solr.parser.QueryParser;
 import org.apache.solr.query.FilterQuery;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.schema.TextField;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.noggit.ObjectBuilder;
 
 
 public class TestSolrQueryParser extends SolrTestCaseJ4 {
@@ -57,6 +65,8 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "12", "eee_s", "X"));
     assertU(adoc("id", "13", "eee_s", "'balance'", "rrr_s", "/leading_slash"));
 
+    assertU(adoc("id", "20", "syn", "wifi ATM"));
+
     assertU(commit());
   }
 
@@ -208,86 +218,105 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
     QParser qParser;
     Query q,qq;
 
-    // relevance query should not be a filter
-    qParser = QParser.getParser("foo_s:(a b c)", req);
-    q = qParser.getQuery();
-    assertEquals(3, ((BooleanQuery)q).clauses().size());
-
-    // small filter query should still use BooleanQuery
-    if (QueryParser.TERMS_QUERY_THRESHOLD > 3) {
+    Map<String, String> sowFalseParamsMap = new HashMap<>();
+    sowFalseParamsMap.put("sow", "false");
+    Map<String, String> sowTrueParamsMap = new HashMap<>();
+    sowTrueParamsMap.put("sow", "true");
+    List<MapSolrParams> paramMaps = Arrays.asList
+        (new MapSolrParams(Collections.emptyMap()), // no sow param (i.e. the default sow value) 
+         new MapSolrParams(sowFalseParamsMap),
+         new MapSolrParams(sowTrueParamsMap));
+
+    for (MapSolrParams params : paramMaps) {
+      // relevance query should not be a filter
       qParser = QParser.getParser("foo_s:(a b c)", req);
-      qParser.setIsFilter(true); // this may change in the future
+      qParser.setParams(params);
       q = qParser.getQuery();
       assertEquals(3, ((BooleanQuery) q).clauses().size());
-    }
 
-    // large relevancy query should use BooleanQuery
-    // TODO: we may decide that string fields shouldn't have relevance in the future... change to a text field w/o a stop filter if so
-    qParser = QParser.getParser("foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z)", req);
-    q = qParser.getQuery();
-    assertEquals(26, ((BooleanQuery)q).clauses().size());
+      // small filter query should still use BooleanQuery
+      if (QueryParser.TERMS_QUERY_THRESHOLD > 3) {
+        qParser = QParser.getParser("foo_s:(a b c)", req);
+        qParser.setParams(params);
+        qParser.setIsFilter(true); // this may change in the future
+        q = qParser.getQuery();
+        assertEquals(3, ((BooleanQuery) q).clauses().size());
+      }
 
-    // large filter query should use TermsQuery
-    qParser = QParser.getParser("foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z)", req);
-    qParser.setIsFilter(true); // this may change in the future
-    q = qParser.getQuery();
-    assertEquals(26, ((TermInSetQuery)q).getTermData().size());
+      // large relevancy query should use BooleanQuery
+      // TODO: we may decide that string fields shouldn't have relevance in the future... change to a text field w/o a stop filter if so
+      qParser = QParser.getParser("foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z)", req);
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertEquals(26, ((BooleanQuery)q).clauses().size());
 
-    // large numeric filter query should use TermsQuery (for trie fields)
-    qParser = QParser.getParser("foo_ti:(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 11)", req);
-    qParser.setIsFilter(true); // this may change in the future
-    q = qParser.getQuery();
-    assertEquals(20, ((TermInSetQuery)q).getTermData().size());
-    
-    // for point fields large filter query should use PointInSetQuery
-    qParser = QParser.getParser("foo_pi:(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 11)", req);
-    qParser.setIsFilter(true); // this may change in the future
-    q = qParser.getQuery();
-    assertTrue(q instanceof PointInSetQuery);
-    assertEquals(20, ((PointInSetQuery)q).getPackedPoints().size());
+      // large filter query should use TermsQuery
+      qParser = QParser.getParser("foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z)", req);
+      qParser.setIsFilter(true); // this may change in the future
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertEquals(26, ((TermInSetQuery)q).getTermData().size());
 
-    // a filter() clause inside a relevancy query should be able to use a TermsQuery
-    qParser = QParser.getParser("foo_s:aaa filter(foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z))", req);
-    q = qParser.getQuery();
-    assertEquals(2, ((BooleanQuery)q).clauses().size());
-    qq = ((BooleanQuery)q).clauses().get(0).getQuery();
-    if (qq instanceof TermQuery) {
-      qq = ((BooleanQuery)q).clauses().get(1).getQuery();
-    }
+      // large numeric filter query should use TermsQuery (for trie fields)
+      qParser = QParser.getParser("foo_ti:(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 11)", req);
+      qParser.setIsFilter(true); // this may change in the future
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertEquals(20, ((TermInSetQuery)q).getTermData().size());
 
-    if (qq instanceof FilterQuery) {
-      qq = ((FilterQuery)qq).getQuery();
-    }
+      // for point fields large filter query should use PointInSetQuery
+      qParser = QParser.getParser("foo_pi:(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 11)", req);
+      qParser.setIsFilter(true); // this may change in the future
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertTrue(q instanceof PointInSetQuery);
+      assertEquals(20, ((PointInSetQuery)q).getPackedPoints().size());
 
-    assertEquals(26, ((TermInSetQuery)qq).getTermData().size());
+      // a filter() clause inside a relevancy query should be able to use a TermsQuery
+      qParser = QParser.getParser("foo_s:aaa filter(foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z))", req);
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertEquals(2, ((BooleanQuery)q).clauses().size());
+      qq = ((BooleanQuery)q).clauses().get(0).getQuery();
+      if (qq instanceof TermQuery) {
+        qq = ((BooleanQuery)q).clauses().get(1).getQuery();
+      }
 
-    // test mixed boolean query, including quotes (which shouldn't matter)
-    qParser = QParser.getParser("foo_s:(a +aaa b -bbb c d e f bar_s:(qqq www) g h i j k l m n o p q r s t u v w x y z)", req);
-    qParser.setIsFilter(true); // this may change in the future
-    q = qParser.getQuery();
-    assertEquals(4, ((BooleanQuery)q).clauses().size());
-    qq = null;
-    for (BooleanClause clause : ((BooleanQuery)q).clauses()) {
-      qq = clause.getQuery();
-      if (qq instanceof TermInSetQuery) break;
-    }
-    assertEquals(26, ((TermInSetQuery)qq).getTermData().size());
+      if (qq instanceof FilterQuery) {
+        qq = ((FilterQuery)qq).getQuery();
+      }
 
-    // test terms queries of two different fields (LUCENE-7637 changed to require all terms be in the same field)
-    StringBuilder sb = new StringBuilder();
-    for (int i=0; i<17; i++) {
-      char letter = (char)('a'+i);
-      sb.append("foo_s:" + letter + " bar_s:" + letter + " ");
-    }
-    qParser = QParser.getParser(sb.toString(), req);
-    qParser.setIsFilter(true); // this may change in the future
-    q = qParser.getQuery();
-    assertEquals(2, ((BooleanQuery)q).clauses().size());
-    for (BooleanClause clause : ((BooleanQuery)q).clauses()) {
-      qq = clause.getQuery();
-      assertEquals(17, ((TermInSetQuery)qq).getTermData().size());
-    }
+      assertEquals(26, ((TermInSetQuery) qq).getTermData().size());
+
+      // test mixed boolean query, including quotes (which shouldn't matter)
+      qParser = QParser.getParser("foo_s:(a +aaa b -bbb c d e f bar_s:(qqq www) g h i j k l m n o p q r s t u v w x y z)", req);
+      qParser.setIsFilter(true); // this may change in the future
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertEquals(4, ((BooleanQuery)q).clauses().size());
+      qq = null;
+      for (BooleanClause clause : ((BooleanQuery)q).clauses()) {
+        qq = clause.getQuery();
+        if (qq instanceof TermInSetQuery) break;
+      }
+      assertEquals(26, ((TermInSetQuery)qq).getTermData().size());
 
+      // test terms queries of two different fields (LUCENE-7637 changed to require all terms be in the same field)
+      StringBuilder sb = new StringBuilder();
+      for (int i=0; i<17; i++) {
+        char letter = (char)('a'+i);
+        sb.append("foo_s:" + letter + " bar_s:" + letter + " ");
+      }
+      qParser = QParser.getParser(sb.toString(), req);
+      qParser.setIsFilter(true); // this may change in the future
+      qParser.setParams(params);
+      q = qParser.getQuery();
+      assertEquals(2, ((BooleanQuery)q).clauses().size());
+      for (BooleanClause clause : ((BooleanQuery)q).clauses()) {
+        qq = clause.getQuery();
+        assertEquals(17, ((TermInSetQuery)qq).getTermData().size());
+      }
+    }
     req.close();
   }
 
@@ -306,6 +335,10 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
     // This will still fail when used as the main query, but will pass in a filter query since TermsQuery can be used.
     assertJQ(req("q","*:*", "fq", q)
         ,"/response/numFound==6");
+    assertJQ(req("q","*:*", "fq", q, "sow", "false")
+        ,"/response/numFound==6");
+    assertJQ(req("q","*:*", "fq", q, "sow", "true")
+        ,"/response/numFound==6");
   }
 
   @Test
@@ -540,4 +573,400 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
     req.close();
   }
 
+  // LUCENE-7533
+  public void testSplitOnWhitespace_with_autoGeneratePhraseQueries() throws Exception {
+    assertTrue(((TextField)h.getCore().getLatestSchema().getField("text").getType()).getAutoGeneratePhraseQueries());
+    
+    try (SolrQueryRequest req = req()) {
+      final QParser qparser = QParser.getParser("{!lucene sow=false qf=text}blah blah", req);
+      expectThrows(QueryParserConfigurationException.class, qparser::getQuery);
+    }
+  }
+
+  @Test
+  public void testSplitOnWhitespace_Basic() throws Exception {
+    // The "syn" field has synonyms loaded from synonyms.txt
+
+    assertJQ(req("df", "syn", "q", "wifi", "sow", "true") // retrieve the single document containing literal "wifi"
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+
+    assertJQ(req("df", "syn", "q", "wi fi", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+
+    assertJQ(req("df", "syn", "q", "wi fi", "sow", "true")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi") // default sow=true
+        , "/response/numFound==0"
+    );
+
+    assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi fi")
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi fi")
+        , "/response/numFound==0"
+    );
+
+    assertJQ(req("df", "syn", "q", "{!lucene}wi fi") // default sow=true
+        , "/response/numFound==0"
+    );
+  }
+
+  public void testSplitOnWhitespace_Comments() throws Exception {
+    // The "syn" field has synonyms loaded from synonyms.txt
+
+    assertJQ(req("df", "syn", "q", "wifi", "sow", "true") // retrieve the single document containing literal "wifi"
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "wi /* foo */ fi", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "wi /* foo */ /* bar */ fi", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", " /* foo */ wi fi /* bar */", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", " /* foo */ wi /* bar */ fi /* baz */", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+
+    assertJQ(req("df", "syn", "q", "wi fi", "sow", "true")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi /* foo */ fi", "sow", "true")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi /* foo */ /* bar */ fi", "sow", "true")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "/* foo */ wi fi /* bar */", "sow", "true")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "/* foo */ wi /* bar */ fi /* baz */", "sow", "true")
+        , "/response/numFound==0"
+    );
+
+    assertJQ(req("df", "syn", "q", "wi fi") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi /* foo */ fi") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi /* foo */ /* bar */ fi") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "/* foo */ wi fi /* bar */") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "/* foo */ wi /* bar */ fi /* baz */") // default sow=true
+        , "/response/numFound==0"
+    );
+
+
+    assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi fi")
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi /* foo */ fi")
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi /* foo */ /* bar */ fi")
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=false}/* foo */ wi fi /* bar */")
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=false}/* foo */ wi /* bar */ fi /* baz */")
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+
+    assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi fi")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi /* foo */ fi")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi /* foo */ /* bar */ fi")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=true}/* foo */ wi fi /* bar */")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene sow=true}/* foo */ wi /* bar */ fi /* baz */")
+        , "/response/numFound==0"
+    );
+
+    assertJQ(req("df", "syn", "q", "{!lucene}wi fi") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene}wi /* foo */ fi") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene}wi /* foo */ /* bar */ fi") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene}/* foo */ wi fi /* bar */") // default sow=true
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "{!lucene}/* foo */ wi /* bar */ fi /* baz */") // default sow=true
+        , "/response/numFound==0"
+    );
+  }
+
+  public void testOperatorsAndMultiWordSynonyms() throws Exception {
+    // The "syn" field has synonyms loaded from synonyms.txt
+
+    assertJQ(req("df", "syn", "q", "wifi", "sow", "true") // retrieve the single document containing literal "wifi"
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi", "sow", "false") // trigger the "wi fi => wifi" synonym
+        , "/response/numFound==1"
+        , "/response/docs/[0]/id=='20'"
+    );
+
+    assertJQ(req("df", "syn", "q", "+wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "-wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "!wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi* fi", "sow", "false")    // matches because wi* matches wifi
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "w? fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi~1 fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi^2 fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi^=2 fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi +fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi -fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi !fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi*", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi?", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi~1", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi^2", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi^=2", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "syn:wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi syn:fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "NOT wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi NOT fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+
+    assertJQ(req("df", "syn", "q", "wi fi AND ATM", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "ATM AND wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi && ATM", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "ATM && wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi) AND ATM", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "ATM AND (wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi) && ATM", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "ATM && (wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+
+    assertJQ(req("df", "syn", "q", "wi fi OR NotThereAtAll", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "NotThereAtAll OR wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi || NotThereAtAll", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "NotThereAtAll || wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi) OR NotThereAtAll", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "NotThereAtAll OR (wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi) || NotThereAtAll", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "NotThereAtAll || (wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+
+    assertJQ(req("df", "syn", "q", "\"wi\" fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi \"fi\"", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "(wi) fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi (fi)", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "/wi/ fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi /fi/", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "+(wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+
+    Map all = (Map)ObjectBuilder.fromJSON(h.query(req("q", "*:*", "rows", "0", "wt", "json")));
+    int totalDocs = Integer.parseInt(((Map)all.get("response")).get("numFound").toString());
+    int allDocsExceptOne = totalDocs - 1;
+
+    assertJQ(req("df", "syn", "q", "-(wi fi)", "sow", "false")
+        , "/response/numFound==" + allDocsExceptOne  // one doc contains "wifi" in the syn field
+    );
+    assertJQ(req("df", "syn", "q", "!(wi fi)", "sow", "false")
+        , "/response/numFound==" + allDocsExceptOne  // one doc contains "wifi" in the syn field
+    );
+    assertJQ(req("df", "syn", "q", "NOT (wi fi)", "sow", "false")
+        , "/response/numFound==" + allDocsExceptOne  // one doc contains "wifi" in the syn field
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi)^2", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "(wi fi)^=2", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "syn:(wi fi)", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "+ATM wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "-ATM wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "-NotThereAtAll wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "!ATM wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "!NotThereAtAll wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "NOT ATM wi fi", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "NOT NotThereAtAll wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "AT* wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "AT? wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "\"ATM\" wi fi", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi +ATM", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi -ATM", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi -NotThereAtAll", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi !ATM", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi !NotThereAtAll", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi NOT ATM", "sow", "false")
+        , "/response/numFound==0"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi NOT NotThereAtAll", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi AT*", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi AT?", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "wi fi \"ATM\"", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "\"wi fi\"~2", "sow", "false")
+        , "/response/numFound==1"
+    );
+    assertJQ(req("df", "syn", "q", "syn:\"wi fi\"", "sow", "false")
+        , "/response/numFound==1"
+    );
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacetRefinement.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacetRefinement.java b/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacetRefinement.java
index a8f8ff2..f23ae8c 100644
--- a/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacetRefinement.java
+++ b/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacetRefinement.java
@@ -18,9 +18,12 @@
 package org.apache.solr.search.facet;
 
 import java.io.IOException;
+import java.util.List;
 
 import org.apache.solr.JSONTestUtil;
 import org.apache.solr.SolrTestCaseHS;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.request.SolrQueryRequest;
 import org.junit.AfterClass;
@@ -209,6 +212,97 @@ public class TestJsonFacetRefinement extends SolrTestCaseHS {
   }
 
 
+  @Test
+  public void testBasicRefinement() throws Exception {
+    initServers();
+    Client client = servers.getClient(random().nextInt());
+    client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
+
+    List<SolrClient> clients = client.getClientProvider().all();
+    assertTrue(clients.size() >= 3);
+
+    client.deleteByQuery("*:*", null);
+
+    ModifiableSolrParams p = params("cat_s", "cat_s", "num_d", "num_d");
+    String cat_s = p.get("cat_s");
+    String num_d = p.get("num_d");
+
+    clients.get(0).add( sdoc("id", "01", cat_s, "A", num_d, -1) ); // A wins count tie
+    clients.get(0).add( sdoc("id", "02", cat_s, "B", num_d, 3) );
+
+    clients.get(1).add( sdoc("id", "11", cat_s, "B", num_d, -5) ); // B highest count
+    clients.get(1).add( sdoc("id", "12", cat_s, "B", num_d, -11) );
+    clients.get(1).add( sdoc("id", "13", cat_s, "A", num_d, 7) );
+
+    clients.get(2).add( sdoc("id", "21", cat_s, "A", num_d, 17) ); // A highest count
+    clients.get(2).add( sdoc("id", "22", cat_s, "A", num_d, -19) );
+    clients.get(2).add( sdoc("id", "23", cat_s, "B", num_d, 11) );
+
+    client.commit();
+
+    // Shard responses should be A=1, B=2, A=2, merged should be "A=3, B=2"
+    // One shard will have _facet_={"refine":{"cat0":{"_l":["A"]}}} on the second phase
+
+    /****
+    // fake a refinement request... good for development/debugging
+    assertJQ(clients.get(1),
+        params(p, "q", "*:*",     "_facet_","{refine:{cat0:{_l:[A]}}}", "isShard","true", "distrib","false", "shards.purpose","2097216", "ids","11,12,13",
+            "json.facet", "{" +
+                "cat0:{type:terms, field:cat_s, sort:'count desc', limit:1, overrequest:0, refine:true}" +
+                "}"
+        )
+        , "facets=={foo:555}"
+    );
+    ****/
+
+    client.testJQ(params(p, "q", "*:*",
+        "json.facet", "{" +
+            "cat0:{type:terms, field:${cat_s}, sort:'count desc', limit:1, overrequest:0, refine:false}" +
+            "}"
+        )
+        , "facets=={ count:8" +
+            ", cat0:{ buckets:[ {val:A,count:3} ] }" +  // w/o overrequest and refinement, count is lower than it should be (we don't see the A from the middle shard)
+            "}"
+    );
+
+    client.testJQ(params(p, "q", "*:*",
+        "json.facet", "{" +
+            "cat0:{type:terms, field:${cat_s}, sort:'count desc', limit:1, overrequest:0, refine:true}" +
+            "}"
+        )
+        , "facets=={ count:8" +
+            ", cat0:{ buckets:[ {val:A,count:4} ] }" +  // w/o overrequest, we need refining to get the correct count.
+            "}"
+    );
+
+    // test that basic stats work for refinement
+    client.testJQ(params(p, "q", "*:*",
+        "json.facet", "{" +
+            "cat0:{type:terms, field:${cat_s}, sort:'count desc', limit:1, overrequest:0, refine:true, facet:{ stat1:'sum(${num_d})'}   }" +
+            "}"
+        )
+        , "facets=={ count:8" +
+            ", cat0:{ buckets:[ {val:A,count:4, stat1:4.0} ] }" +
+            "}"
+    );
+
+    // test sorting buckets by a different stat
+    client.testJQ(params(p, "q", "*:*",
+        "json.facet", "{" +
+            " cat0:{type:terms, field:${cat_s}, sort:'min1 asc', limit:1, overrequest:0, refine:false, facet:{ min1:'min(${num_d})'}   }" +
+            ",cat1:{type:terms, field:${cat_s}, sort:'min1 asc', limit:1, overrequest:0, refine:true,  facet:{ min1:'min(${num_d})'}   }" +
+            ",sum1:'sum(num_d)'" +  // make sure that root bucket stats aren't affected by refinement
+            "}"
+        )
+        , "facets=={ count:8" +
+            ", cat0:{ buckets:[ {val:A,count:3, min1:-19.0} ] }" +  // B wins in shard2, so we're missing the "A" count for that shar w/o refinement.
+            ", cat1:{ buckets:[ {val:A,count:4, min1:-19.0} ] }" +  // with refinement, we get the right count
+            ", sum1:2.0" +
+            "}"
+    );
+
+
+  }
 
 
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/search/mlt/CloudMLTQParserTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/mlt/CloudMLTQParserTest.java b/solr/core/src/test/org/apache/solr/search/mlt/CloudMLTQParserTest.java
index e3a8d7b..f502f24 100644
--- a/solr/core/src/test/org/apache/solr/search/mlt/CloudMLTQParserTest.java
+++ b/solr/core/src/test/org/apache/solr/search/mlt/CloudMLTQParserTest.java
@@ -102,7 +102,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     int[] actualIds = new int[10];
     int i = 0;
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] = Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] = Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
     }
     assertArrayEquals(expectedIds, actualIds);
 
@@ -117,7 +117,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     int[] actualIds = new int[solrDocuments.size()];
     int i = 0;
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] = Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] = Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
     }
     assertArrayEquals(expectedIds, actualIds);
 
@@ -127,7 +127,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     actualIds = new int[solrDocuments.size()];
     i = 0;
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] = Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] = Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
     }
     System.out.println("DEBUG ACTUAL IDS 1: " + Arrays.toString(actualIds));
     assertArrayEquals(expectedIds, actualIds);
@@ -138,7 +138,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     actualIds = new int[solrDocuments.size()];
     i = 0;
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] = Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] = Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
     }
     System.out.println("DEBUG ACTUAL IDS 2: " + Arrays.toString(actualIds));
     assertArrayEquals(expectedIds, actualIds);
@@ -154,7 +154,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     int[] actualIds = new int[solrDocuments.size()];
     int i = 0;
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] = Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] = Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
     }
     assertArrayEquals(expectedIds, actualIds);
 
@@ -184,7 +184,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     int[] actualIds = new int[solrDocuments.size()];
     int i = 0;
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] = Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] = Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
     }
 
     assertArrayEquals(expectedIds, actualIds);
@@ -236,7 +236,7 @@ public class CloudMLTQParserTest extends SolrCloudTestCase {
     int i = 0;
     StringBuilder sb = new StringBuilder();
     for (SolrDocument solrDocument : solrDocuments) {
-      actualIds[i++] =  Integer.valueOf(String.valueOf(solrDocument.getFieldValue("id")));
+      actualIds[i++] =  Integer.parseInt(String.valueOf(solrDocument.getFieldValue("id")));
       sb.append(actualIds[i-1]).append(", ");
     }
     assertArrayEquals(expectedIds, actualIds);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/update/DirectUpdateHandlerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/DirectUpdateHandlerTest.java b/solr/core/src/test/org/apache/solr/update/DirectUpdateHandlerTest.java
index 2816354..462241a 100644
--- a/solr/core/src/test/org/apache/solr/update/DirectUpdateHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/update/DirectUpdateHandlerTest.java
@@ -119,7 +119,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
     String delsQName = PREFIX + "deletesByQuery";
     String cumulativeDelsQName = PREFIX + "cumulativeDeletesByQuery";
     long commits = ((Meter) metrics.get(commitsName)).getCount();
-    long adds = ((Gauge<Long>) metrics.get(addsName)).getValue();
+    long adds = ((Gauge<Number>) metrics.get(addsName)).getValue().longValue();
     long cumulativeAdds = ((Meter) metrics.get(cumulativeAddsName)).getCount();
     long cumulativeDelsI = ((Meter) metrics.get(cumulativeDelsIName)).getCount();
     long cumulativeDelsQ = ((Meter) metrics.get(cumulativeDelsQName)).getCount();
@@ -137,7 +137,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
     assertQ(req("q","id:5"), "//*[@numFound='0']");
     assertQ(req("q","id:6"), "//*[@numFound='0']");
 
-    long newAdds = ((Gauge<Long>) metrics.get(addsName)).getValue();
+    long newAdds = ((Gauge<Number>) metrics.get(addsName)).getValue().longValue();
     long newCumulativeAdds = ((Meter) metrics.get(cumulativeAddsName)).getCount();
     assertEquals("new adds", 2, newAdds - adds);
     assertEquals("new cumulative adds", 2, newCumulativeAdds - cumulativeAdds);
@@ -147,7 +147,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
     long newCommits = ((Meter) metrics.get(commitsName)).getCount();
     assertEquals("new commits", 1, newCommits - commits);
 
-    newAdds = ((Gauge<Long>) metrics.get(addsName)).getValue();
+    newAdds = ((Gauge<Number>) metrics.get(addsName)).getValue().longValue();
     newCumulativeAdds = ((Meter) metrics.get(cumulativeAddsName)).getCount();
     // adds should be reset to 0 after commit
     assertEquals("new adds after commit", 0, newAdds);
@@ -161,7 +161,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
     // now delete one
     assertU(delI("5"));
 
-    long newDelsI = ((Gauge<Long>) metrics.get(delsIName)).getValue();
+    long newDelsI = ((Gauge<Number>) metrics.get(delsIName)).getValue().longValue();
     long newCumulativeDelsI = ((Meter) metrics.get(cumulativeDelsIName)).getCount();
     assertEquals("new delsI", 1, newDelsI);
     assertEquals("new cumulative delsI", 1, newCumulativeDelsI - cumulativeDelsI);
@@ -171,7 +171,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
 
     assertU(commit());
     // delsI should be reset to 0 after commit
-    newDelsI = ((Gauge<Long>) metrics.get(delsIName)).getValue();
+    newDelsI = ((Gauge<Number>) metrics.get(delsIName)).getValue().longValue();
     newCumulativeDelsI = ((Meter) metrics.get(cumulativeDelsIName)).getCount();
     assertEquals("new delsI after commit", 0, newDelsI);
     assertEquals("new cumulative delsI after commit", 1, newCumulativeDelsI - cumulativeDelsI);
@@ -183,7 +183,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
     // now delete all
     assertU(delQ("*:*"));
 
-    long newDelsQ = ((Gauge<Long>) metrics.get(delsQName)).getValue();
+    long newDelsQ = ((Gauge<Number>) metrics.get(delsQName)).getValue().longValue();
     long newCumulativeDelsQ = ((Meter) metrics.get(cumulativeDelsQName)).getCount();
     assertEquals("new delsQ", 1, newDelsQ);
     assertEquals("new cumulative delsQ", 1, newCumulativeDelsQ - cumulativeDelsQ);
@@ -193,7 +193,7 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
 
     assertU(commit());
 
-    newDelsQ = ((Gauge<Long>) metrics.get(delsQName)).getValue();
+    newDelsQ = ((Gauge<Number>) metrics.get(delsQName)).getValue().longValue();
     newCumulativeDelsQ = ((Meter) metrics.get(cumulativeDelsQName)).getCount();
     assertEquals("new delsQ after commit", 0, newDelsQ);
     assertEquals("new cumulative delsQ after commit", 1, newCumulativeDelsQ - cumulativeDelsQ);
@@ -204,11 +204,11 @@ public class DirectUpdateHandlerTest extends SolrTestCaseJ4 {
     // verify final metrics
     newCommits = ((Meter) metrics.get(commitsName)).getCount();
     assertEquals("new commits", 3, newCommits - commits);
-    newAdds = ((Gauge<Long>) metrics.get(addsName)).getValue();
+    newAdds = ((Gauge<Number>) metrics.get(addsName)).getValue().longValue();
     assertEquals("new adds", 0, newAdds);
     newCumulativeAdds = ((Meter) metrics.get(cumulativeAddsName)).getCount();
     assertEquals("new cumulative adds", 2, newCumulativeAdds - cumulativeAdds);
-    newDelsI = ((Gauge<Long>) metrics.get(delsIName)).getValue();
+    newDelsI = ((Gauge<Number>) metrics.get(delsIName)).getValue().longValue();
     assertEquals("new delsI", 0, newDelsI);
     newCumulativeDelsI = ((Meter) metrics.get(cumulativeDelsIName)).getCount();
     assertEquals("new cumulative delsI", 1, newCumulativeDelsI - cumulativeDelsI);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/update/DocumentBuilderTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/DocumentBuilderTest.java b/solr/core/src/test/org/apache/solr/update/DocumentBuilderTest.java
index 2a78d6b..5d98d8b 100644
--- a/solr/core/src/test/org/apache/solr/update/DocumentBuilderTest.java
+++ b/solr/core/src/test/org/apache/solr/update/DocumentBuilderTest.java
@@ -16,7 +16,14 @@
  */
 package org.apache.solr.update;
 
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import com.carrotsearch.randomizedtesting.generators.RandomStrings;
 import org.apache.lucene.document.Document;
+import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.util.TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrDocument;
@@ -25,6 +32,8 @@ import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.SolrInputField;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.schema.FieldType;
+import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -33,12 +42,23 @@ import org.junit.Test;
  *
  */
 public class DocumentBuilderTest extends SolrTestCaseJ4 {
+  static final int save_min_len = DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST;
 
   @BeforeClass
   public static void beforeClass() throws Exception {
     initCore("solrconfig.xml", "schema.xml");
   }
 
+  @AfterClass
+  public static void afterClass() {
+    DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST = save_min_len;
+  }
+
+  @After
+  public void afterTest() {
+    DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST = save_min_len;
+  }
+
   @Test
   public void testBuildDocument() throws Exception 
   {
@@ -111,8 +131,8 @@ public class DocumentBuilderTest extends SolrTestCaseJ4 {
     doc.addField( "home", "2.2,3.3" );
     Document out = DocumentBuilder.toDocument( doc, core.getLatestSchema() );
     assertNotNull( out.get( "home" ) );//contains the stored value and term vector, if there is one
-    assertNotNull( out.getField( "home_0" + FieldType.POLY_FIELD_SEPARATOR + "double" ) );
-    assertNotNull( out.getField( "home_1" + FieldType.POLY_FIELD_SEPARATOR + "double" ) );
+    assertNotNull( out.getField( "home_0" + FieldType.POLY_FIELD_SEPARATOR + System.getProperty("solr.tests.doubleClass", "pdouble") ) );
+    assertNotNull( out.getField( "home_1" + FieldType.POLY_FIELD_SEPARATOR + System.getProperty("solr.tests.doubleClass", "pdouble") ) );
   }
   
   /**
@@ -222,7 +242,54 @@ public class DocumentBuilderTest extends SolrTestCaseJ4 {
     sif2.setName("foo");
     assertFalse(assertSolrInputFieldEquals(sif1, sif2));
 
+  }
 
+  public void testMoveLargestLast() {
+    SolrInputDocument inDoc = new SolrInputDocument();
+    String TEXT_FLD = "text"; // not stored.  It won't be moved.  This value is the longest, however.
+    inDoc.addField(TEXT_FLD,
+        "NOT STORED|" + RandomStrings.randomAsciiOfLength(random(), 4 * DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST));
+
+    String CAT_FLD = "cat"; // stored, multiValued
+    inDoc.addField(CAT_FLD,
+        "STORED V1|");
+    //  pretty long value
+    inDoc.addField(CAT_FLD,
+        "STORED V2|" + RandomStrings.randomAsciiOfLength(random(), 2 * DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST));
+    inDoc.addField(CAT_FLD,
+        "STORED V3|" + RandomStrings.randomAsciiOfLength(random(), DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST));
+
+    String SUBJECT_FLD = "subject"; // stored.  This value is long, but not long enough.
+    inDoc.addField(SUBJECT_FLD,
+        "2ndplace|" + RandomStrings.randomAsciiOfLength(random(), DocumentBuilder.MIN_LENGTH_TO_MOVE_LAST));
+
+    Document outDoc = DocumentBuilder.toDocument(inDoc, h.getCore().getLatestSchema());
+
+    // filter outDoc by stored fields; convert to list.
+    List<IndexableField> storedFields = StreamSupport.stream(outDoc.spliterator(), false)
+        .filter(f -> f.fieldType().stored()).collect(Collectors.toList());
+    // clip to last 3.  We expect these to be for CAT_FLD
+    storedFields = storedFields.subList(storedFields.size() - 3, storedFields.size());
+
+    Iterator<IndexableField> fieldIterator = storedFields.iterator();
+    IndexableField field;
+
+    // Test that we retained the particular value ordering, even though though the 2nd of three was longest
+
+    assertTrue(fieldIterator.hasNext());
+    field = fieldIterator.next();
+    assertEquals(CAT_FLD, field.name());
+    assertTrue(field.stringValue().startsWith("STORED V1|"));
+
+    assertTrue(fieldIterator.hasNext());
+    field = fieldIterator.next();
+    assertEquals(CAT_FLD, field.name());
+    assertTrue(field.stringValue().startsWith("STORED V2|"));
+
+    assertTrue(fieldIterator.hasNext());
+    field = fieldIterator.next();
+    assertEquals(CAT_FLD, field.name());
+    assertTrue(field.stringValue().startsWith("STORED V3|"));
   }
 
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java b/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java
index c9935bb..9985937 100644
--- a/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java
+++ b/solr/core/src/test/org/apache/solr/update/SolrIndexMetricsTest.java
@@ -67,7 +67,7 @@ public class SolrIndexMetricsTest extends SolrTestCaseJ4 {
 
     Map<String, Metric> metrics = registry.getMetrics();
 
-    assertEquals(10, metrics.entrySet().stream().filter(e -> e.getKey().startsWith("INDEX")).count());
+    assertEquals(12, metrics.entrySet().stream().filter(e -> e.getKey().startsWith("INDEX")).count());
 
     // check basic index meters
     Timer timer = (Timer)metrics.get("INDEX.merge.minor");
@@ -92,7 +92,8 @@ public class SolrIndexMetricsTest extends SolrTestCaseJ4 {
     assertNotNull(registry);
 
     Map<String, Metric> metrics = registry.getMetrics();
-    assertEquals(0, metrics.entrySet().stream().filter(e -> e.getKey().startsWith("INDEX")).count());
+    // INDEX.size, INDEX.sizeInBytes
+    assertEquals(2, metrics.entrySet().stream().filter(e -> e.getKey().startsWith("INDEX")).count());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
index 4c90bc6..4538e90 100644
--- a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
+++ b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesDistrib.java
@@ -71,6 +71,7 @@ import org.slf4j.LoggerFactory;
 @Slow
 public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+  private final boolean onlyLeaderIndexes = random().nextBoolean();
 
   @BeforeClass
   public static void beforeSuperClass() throws Exception {
@@ -108,7 +109,12 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
       iw.decref();
     }
   }
-  
+
+  @Override
+  protected int getRealtimeReplicas() {
+    return onlyLeaderIndexes? 1 : -1;
+  }
+
   @After
   public void after() {
     System.clearProperty("solr.tests.intClassName");
@@ -151,15 +157,18 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
         "docValues",Boolean.TRUE));
 
     // Do the tests now:
-    reorderedDBQIndividualReplicaTest();
-    testDBQUsingUpdatedFieldFromDroppedUpdate();
-    outOfOrderDBQsTest();
     docValuesUpdateTest();
     ensureRtgWorksWithPartialUpdatesTest();
-    delayedReorderingFetchesMissingUpdateFromLeaderTest();
     outOfOrderUpdatesIndividualReplicaTest();
-    outOfOrderDeleteUpdatesIndividualReplicaTest();
-    reorderedDBQsWithInPlaceUpdatesShouldNotThrowReplicaInLIRTest();
+    delayedReorderingFetchesMissingUpdateFromLeaderTest();
+    updatingDVsInAVeryOldSegment();
+
+    // TODO Should we combine all/some of these into a single test, so as to cut down on execution time?
+    reorderedDBQIndividualReplicaTest();
+    reorderedDeletesTest();
+    reorderedDBQsSimpleTest();
+    reorderedDBQsResurrectionTest();
+    reorderedDBQsUsingUpdatedValueFromADroppedUpdate();
   }
   
   private void mapReplicasToClients() throws KeeperException, InterruptedException {
@@ -195,7 +204,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
   final int NUM_RETRIES = 100, WAIT_TIME = 10;
 
   // The following should work: full update to doc 0, in-place update for doc 0, delete doc 0
-  private void outOfOrderDBQsTest() throws Exception {
+  private void reorderedDBQsSimpleTest() throws Exception {
     
     clearIndex();
     commit();
@@ -243,7 +252,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     }
     
     threadpool.shutdown();
-    assertTrue("Thread pool didn't terminate within 10 secs", threadpool.awaitTermination(10, TimeUnit.SECONDS));
+    assertTrue("Thread pool didn't terminate within 15 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
     
     // assert all requests were successful
     for (Future<UpdateResponse> resp: updateResponses) {
@@ -256,12 +265,16 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
       assertNull("This doc was supposed to have been deleted, but was: " + doc, doc);
     }
 
-    log.info("outOfOrderDeleteUpdatesIndividualReplicaTest: This test passed fine...");
+    log.info("reorderedDBQsSimpleTest: This test passed fine...");
     clearIndex();
     commit();
   }
 
   private void reorderedDBQIndividualReplicaTest() throws Exception {
+    if (onlyLeaderIndexes) {
+      log.info("RTG with DBQs are not working in append replicas");
+      return;
+    }
     clearIndex();
     commit();
 
@@ -294,7 +307,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     }
 
     threadpool.shutdown();
-    assertTrue("Thread pool didn't terminate within 10 secs", threadpool.awaitTermination(10, TimeUnit.SECONDS));
+    assertTrue("Thread pool didn't terminate within 15 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
 
     // assert all requests were successful
     for (Future<UpdateResponse> resp: updateResponses) {
@@ -329,7 +342,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     SolrDocumentList results = LEADER.query(params).getResults();
     assertEquals(numDocs, results.size());
     for (SolrDocument doc : results) {
-      luceneDocids.add((int) doc.get("[docid]"));
+      luceneDocids.add((Integer) doc.get("[docid]"));
       valuesList.add((Float) doc.get("inplace_updatable_float"));
     }
     log.info("Initial results: "+results);
@@ -391,6 +404,36 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
   }
 
   /**
+   * Ingest many documents, keep committing. Then update a document from a very old segment.
+   */
+  private void updatingDVsInAVeryOldSegment() throws Exception {
+    clearIndex();
+    commit();
+
+    String id = String.valueOf(Integer.MAX_VALUE);
+    index("id", id, "inplace_updatable_float", "1", "title_s", "newtitle");
+
+    // create 10 more segments
+    for (int i=0; i<10; i++) {
+      buildRandomIndex(101.0F, Collections.emptyList());
+    }
+
+    index("id", id, "inplace_updatable_float", map("inc", "1"));
+
+    for (SolrClient client: new SolrClient[] {LEADER, NONLEADERS.get(0), NONLEADERS.get(1)}) {
+      assertEquals("newtitle", client.getById(id).get("title_s"));
+      assertEquals(2.0f, client.getById(id).get("inplace_updatable_float"));
+    }
+    commit();
+    for (SolrClient client: new SolrClient[] {LEADER, NONLEADERS.get(0), NONLEADERS.get(1)}) {
+      assertEquals("newtitle", client.getById(id).get("title_s"));
+      assertEquals(2.0f, client.getById(id).get("inplace_updatable_float"));
+    }
+
+    log.info("updatingDVsInAVeryOldSegment: This test passed fine...");
+  }
+
+  /**
    * Retries the specified 'req' against each SolrClient in "clients" untill the expected number of 
    * results are returned, at which point the results are verified using assertDocIdsAndValuesInResults
    *
@@ -562,7 +605,6 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
   }
 
   private void outOfOrderUpdatesIndividualReplicaTest() throws Exception {
-    
     clearIndex();
     commit();
 
@@ -610,7 +652,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     }
     
     threadpool.shutdown();
-    assertTrue("Thread pool didn't terminate within 10 secs", threadpool.awaitTermination(10, TimeUnit.SECONDS));
+    assertTrue("Thread pool didn't terminate within 15 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
 
     // assert all requests were successful
     for (Future<UpdateResponse> resp: updateResponses) {
@@ -633,7 +675,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
   }
   
   // The following should work: full update to doc 0, in-place update for doc 0, delete doc 0
-  private void outOfOrderDeleteUpdatesIndividualReplicaTest() throws Exception {
+  private void reorderedDeletesTest() throws Exception {
     
     clearIndex();
     commit();
@@ -680,7 +722,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     }
     
     threadpool.shutdown();
-    assertTrue("Thread pool didn't terminate within 10 secs", threadpool.awaitTermination(10, TimeUnit.SECONDS));
+    assertTrue("Thread pool didn't terminate within 15 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
 
     // assert all requests were successful
     for (Future<UpdateResponse> resp: updateResponses) {
@@ -693,7 +735,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
       assertNull("This doc was supposed to have been deleted, but was: " + doc, doc);
     }
 
-    log.info("outOfOrderDeleteUpdatesIndividualReplicaTest: This test passed fine...");
+    log.info("reorderedDeletesTest: This test passed fine...");
     clearIndex();
     commit();
   }
@@ -707,7 +749,11 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
         DBQ(q=val:10, v=4)
         DV(id=x, val=5, ver=3)
    */
-  private void reorderedDBQsWithInPlaceUpdatesShouldNotThrowReplicaInLIRTest() throws Exception {
+  private void reorderedDBQsResurrectionTest() throws Exception {
+    if (onlyLeaderIndexes) {
+      log.info("RTG with DBQs are not working in append replicas");
+      return;
+    }
     clearIndex();
     commit();
 
@@ -754,7 +800,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     }
     
     threadpool.shutdown();
-    assertTrue("Thread pool didn't terminate within 10 secs", threadpool.awaitTermination(10, TimeUnit.SECONDS));
+    assertTrue("Thread pool didn't terminate within 15 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
 
     int successful = 0;
     for (Future<UpdateResponse> resp: updateResponses) {
@@ -794,7 +840,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
       assertEquals("Client: "+((HttpSolrClient)client).getBaseURL(), 5, doc.getFieldValue(field));
     }
 
-    log.info("reorderedDBQsWithInPlaceUpdatesShouldNotThrowReplicaInLIRTest: This test passed fine...");
+    log.info("reorderedDBQsResurrectionTest: This test passed fine...");
     clearIndex();
     commit();
   }
@@ -829,7 +875,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     }
 
     threadpool.shutdown();
-    assertTrue("Thread pool didn't terminate within 10 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
+    assertTrue("Thread pool didn't terminate within 15 secs", threadpool.awaitTermination(15, TimeUnit.SECONDS));
 
     commit();
 
@@ -983,7 +1029,7 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
     String baseUrl = getBaseUrl(""+id);
 
     UpdateRequest ur = new UpdateRequest();
-    if (random().nextBoolean()) {
+    if (random().nextBoolean() || onlyLeaderIndexes) {
       ur.deleteById(""+id);
     } else {
       ur.deleteByQuery("id:"+id);
@@ -1104,7 +1150,11 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
    * inp(id=1,inpfield=14,prevVersion=2,version=3) // will wait till timeout, and then fetch a "not found" from leader
    * dbq("inp:14",version=4)
    */
-  private void testDBQUsingUpdatedFieldFromDroppedUpdate() throws Exception {
+  private void reorderedDBQsUsingUpdatedValueFromADroppedUpdate() throws Exception {
+    if (onlyLeaderIndexes) {
+      log.info("RTG with DBQs are not working in append replicas");
+      return;
+    }
     clearIndex();
     commit();
     
@@ -1161,7 +1211,21 @@ public class TestInPlaceUpdatesDistrib extends AbstractFullDistribZkTestBase {
       assertNull(client.getById("1", params("distrib", "false")));
     }
 
-    log.info("testDBQUsingUpdatedFieldFromDroppedUpdate: This test passed fine...");
+    log.info("reorderedDBQsUsingUpdatedValueFromADroppedUpdate: This test passed fine...");
+  }
+
+  @Override
+  public void clearIndex() {
+    super.clearIndex();
+    try {
+      for (SolrClient client: new SolrClient[] {LEADER, NONLEADERS.get(0), NONLEADERS.get(1)}) {
+        if (client != null) {
+          client.request(simulatedDeleteRequest("*:*", -Long.MAX_VALUE));
+          client.commit();
+        }
+      }
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
   }
-  
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesStandalone.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesStandalone.java b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesStandalone.java
index 9a5031f..877467e 100644
--- a/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesStandalone.java
+++ b/solr/core/src/test/org/apache/solr/update/TestInPlaceUpdatesStandalone.java
@@ -32,6 +32,8 @@ import java.util.Random;
 import java.util.Set;
 
 import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.NoMergePolicy;
 import org.apache.lucene.util.TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
@@ -41,6 +43,7 @@ import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.SolrInputField;
+import org.apache.solr.index.NoMergePolicyFactory;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.update.processor.DistributedUpdateProcessor;
 import org.apache.solr.schema.IndexSchema;
@@ -49,6 +52,7 @@ import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.update.processor.AtomicUpdateDocumentMerger;
 import org.apache.solr.util.RefCounted;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -67,6 +71,14 @@ public class TestInPlaceUpdatesStandalone extends SolrTestCaseJ4 {
     System.setProperty("solr.tests.floatClassName", random().nextBoolean()? "TrieFloatField": "FloatPointField");
     System.setProperty("solr.tests.doubleClassName", random().nextBoolean()? "TrieDoubleField": "DoublePointField");
 
+    // we need consistent segments that aren't re-ordered on merge because we're
+    // asserting inplace updates happen by checking the internal [docid]
+    systemSetPropertySolrTestsMergePolicyFactory(NoMergePolicyFactory.class.getName());
+
+    // HACK: Don't use a RandomMergePolicy, but only use the mergePolicyFactory that we've just set
+    System.setProperty(SYSTEM_PROPERTY_SOLR_TESTS_USEMERGEPOLICYFACTORY, "true");
+    System.setProperty(SYSTEM_PROPERTY_SOLR_TESTS_USEMERGEPOLICY, "false");
+
     initCore("solrconfig-tlog.xml", "schema-inplace-updates.xml");
 
     // sanity check that autocommits are disabled
@@ -75,6 +87,16 @@ public class TestInPlaceUpdatesStandalone extends SolrTestCaseJ4 {
     assertEquals(-1, h.getCore().getSolrConfig().getUpdateHandlerInfo().autoCommmitMaxDocs);
     assertEquals(-1, h.getCore().getSolrConfig().getUpdateHandlerInfo().autoSoftCommmitMaxDocs);
 
+    // assert that NoMergePolicy was chosen
+    RefCounted<IndexWriter> iw = h.getCore().getSolrCoreState().getIndexWriter(h.getCore());
+    try {
+      IndexWriter writer = iw.get();
+      assertTrue("Actual merge policy is: " + writer.getConfig().getMergePolicy(),
+          writer.getConfig().getMergePolicy() instanceof NoMergePolicy); 
+    } finally {
+      iw.decref();
+    }
+
     // validate that the schema was not changed to an unexpected state
     IndexSchema schema = h.getCore().getLatestSchema();
     for (String fieldName : Arrays.asList("_version_",
@@ -98,6 +120,11 @@ public class TestInPlaceUpdatesStandalone extends SolrTestCaseJ4 {
     client = new EmbeddedSolrServer(h.getCoreContainer(), h.coreName);
   }
 
+  @AfterClass
+  public static void afterClass() {
+    client = null;
+  }
+
   @After
   public void after() {
     System.clearProperty("solr.tests.intClassName");

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdatesTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdatesTest.java b/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdatesTest.java
index 7bae2c9..bfcf015 100644
--- a/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdatesTest.java
+++ b/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdatesTest.java
@@ -1204,7 +1204,6 @@ public class AtomicUpdatesTest extends SolrTestCaseJ4 {
     
   }
 
-  @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/SOLR-9838")
   public void testAtomicUpdateOfFieldsWithDefaultValue() {
     // both fields have the same default value (42)
     for (String fieldToUpdate : Arrays.asList("intDefault", "intDvoDefault")) {
@@ -1254,7 +1253,7 @@ public class AtomicUpdatesTest extends SolrTestCaseJ4 {
               , "count(//doc/*)=6"
               );
       // do atomic update
-      assertU(adoc(sdoc("id", "7", fieldToUpdate, ImmutableMap.of("inc", -555))));
+      assertU(adoc(sdoc("id", "8", fieldToUpdate, ImmutableMap.of("inc", -555))));
       assertQ(fieldToUpdate + ": RTG after atomic update"
               , req("qt", "/get", "id", "8")
               , "count(//doc)=1"

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java b/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
index 8717ad6..35caef8 100644
--- a/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
+++ b/solr/core/src/test/org/apache/solr/util/stats/MetricUtilsTest.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
 import com.codahale.metrics.Histogram;
 import com.codahale.metrics.Meter;
 import com.codahale.metrics.MetricFilter;
@@ -44,7 +45,7 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
       timer.update(Math.abs(random().nextInt()) + 1, TimeUnit.NANOSECONDS);
     }
     // obtain timer metrics
-    NamedList lst = new NamedList(MetricUtils.timerToMap(timer, false));
+    NamedList lst = new NamedList(MetricUtils.convertTimer(timer, false));
     // check that expected metrics were obtained
     assertEquals(14, lst.size());
     final Snapshot snapshot = timer.getSnapshot();
@@ -78,10 +79,15 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
     am.set("foo", 10);
     am.set("bar", 1);
     am.set("bar", 2);
-    MetricUtils.toNamedMaps(registry, Collections.singletonList(MetricFilter.ALL), MetricFilter.ALL,
-        false, false, (k, v) -> {
+    Gauge<String> gauge = () -> "foobar";
+    registry.register("gauge", gauge);
+    MetricUtils.toMaps(registry, Collections.singletonList(MetricFilter.ALL), MetricFilter.ALL,
+        false, false, false, (k, o) -> {
+      Map v = (Map)o;
       if (k.startsWith("counter")) {
         assertEquals(1L, v.get("count"));
+      } else if (k.startsWith("gauge")) {
+        assertEquals("foobar", v.get("value"));
       } else if (k.startsWith("timer")) {
         assertEquals(1L, v.get("count"));
         assertTrue(((Number)v.get("min_ms")).intValue() > 100);
@@ -102,6 +108,47 @@ public class MetricUtilsTest extends SolrTestCaseJ4 {
         assertEquals(2, update.get("updateCount"));
       }
     });
+    // test compact format
+    MetricUtils.toMaps(registry, Collections.singletonList(MetricFilter.ALL), MetricFilter.ALL,
+        false, false, true, (k, o) -> {
+          if (k.startsWith("counter")) {
+            assertTrue(o instanceof Long);
+            assertEquals(1L, o);
+          } else if (k.startsWith("gauge")) {
+            assertTrue(o instanceof String);
+            assertEquals("foobar", o);
+          } else if (k.startsWith("timer")) {
+            assertTrue(o instanceof Map);
+            Map v = (Map)o;
+            assertEquals(1L, v.get("count"));
+            assertTrue(((Number)v.get("min_ms")).intValue() > 100);
+          } else if (k.startsWith("meter")) {
+            assertTrue(o instanceof Map);
+            Map v = (Map)o;
+            assertEquals(1L, v.get("count"));
+          } else if (k.startsWith("histogram")) {
+            assertTrue(o instanceof Map);
+            Map v = (Map)o;
+            assertEquals(1L, v.get("count"));
+          } else if (k.startsWith("aggregate")) {
+            assertTrue(o instanceof Map);
+            Map v = (Map)o;
+            assertEquals(2, v.get("count"));
+            Map<String, Object> values = (Map<String, Object>)v.get("values");
+            assertNotNull(values);
+            assertEquals(2, values.size());
+            Map<String, Object> update = (Map<String, Object>)values.get("foo");
+            assertEquals(10, update.get("value"));
+            assertEquals(1, update.get("updateCount"));
+            update = (Map<String, Object>)values.get("bar");
+            assertEquals(2, update.get("value"));
+            assertEquals(2, update.get("updateCount"));
+          } else {
+            Map v = (Map)o;
+            assertEquals(1L, v.get("count"));
+          }
+        });
+
   }
 
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/server/scripts/cloud-scripts/zkcli.bat
----------------------------------------------------------------------
diff --git a/solr/server/scripts/cloud-scripts/zkcli.bat b/solr/server/scripts/cloud-scripts/zkcli.bat
index c372685..c5d7b72 100644
--- a/solr/server/scripts/cloud-scripts/zkcli.bat
+++ b/solr/server/scripts/cloud-scripts/zkcli.bat
@@ -22,4 +22,4 @@ REM  -DzkDigestUsername=admin-user -DzkDigestPassword=CHANGEME-ADMIN-PASSWORD ^
 REM  -DzkDigestReadonlyUsername=readonly-user -DzkDigestReadonlyPassword=CHANGEME-READONLY-PASSWORD
 
 "%JVM%" %SOLR_ZK_CREDS_AND_ACLS% %ZKCLI_JVM_FLAGS% -Dlog4j.configuration="%LOG4J_CONFIG%" ^
--classpath "%SDIR%\..\..\solr-webapp\webapp\WEB-INF\lib\*;%SDIR%\..\..\lib\ext\*" org.apache.solr.cloud.ZkCLI %*
+-classpath "%SDIR%\..\..\solr-webapp\webapp\WEB-INF\lib\*;%SDIR%\..\..\lib\ext\*;%SDIR%\..\..\lib\*" org.apache.solr.cloud.ZkCLI %*

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/887d1b18/solr/server/scripts/cloud-scripts/zkcli.sh
----------------------------------------------------------------------
diff --git a/solr/server/scripts/cloud-scripts/zkcli.sh b/solr/server/scripts/cloud-scripts/zkcli.sh
index df43265..bd971e9 100755
--- a/solr/server/scripts/cloud-scripts/zkcli.sh
+++ b/solr/server/scripts/cloud-scripts/zkcli.sh
@@ -22,5 +22,5 @@ fi
 #  -DzkDigestReadonlyUsername=readonly-user -DzkDigestReadonlyPassword=CHANGEME-READONLY-PASSWORD"
 
 PATH=$JAVA_HOME/bin:$PATH $JVM $SOLR_ZK_CREDS_AND_ACLS $ZKCLI_JVM_FLAGS -Dlog4j.configuration=$log4j_config \
--classpath "$sdir/../../solr-webapp/webapp/WEB-INF/lib/*:$sdir/../../lib/ext/*" org.apache.solr.cloud.ZkCLI ${1+"$@"}
+-classpath "$sdir/../../solr-webapp/webapp/WEB-INF/lib/*:$sdir/../../lib/ext/*:$sdir/../../lib/*" org.apache.solr.cloud.ZkCLI ${1+"$@"}