You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sa...@apache.org on 2016/06/10 07:01:49 UTC

[01/11] lucene-solr:master: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_5_5 9f5fae7ed -> 508f8f83e
  refs/heads/branch_5x 5955712ab -> 1dff75c64
  refs/heads/branch_6_0 c6b048862 -> d5712fea6
  refs/heads/branch_6_1 80d6d26cc -> e0c6762de
  refs/heads/branch_6x a60518c56 -> 74d94ec26
  refs/heads/master 963206969 -> 387143997


SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/38714399
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/38714399
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/38714399

Branch: refs/heads/master
Commit: 38714399760889d2d7b188a87341aade6139ffef
Parents: 9632069
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:29:26 2016 -0400

----------------------------------------------------------------------
 solr/CHANGES.txt                                |   4 +
 .../solr/search/ExtendedDismaxQParser.java      |  37 ++++-
 .../solr/search/TestExtendedDismaxParser.java   | 155 +++++++++++++++++++
 3 files changed, 191 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/38714399/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index ceb7a4a..73a60f2 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -203,6 +203,10 @@ Bug Fixes
 
 * SOLR-9198: config APIs unable to add multiple values with same name (noble)
 
+* SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided
+  and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
+  (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
+
 Optimizations
 ----------------------
 * SOLR-8722: Don't force a full ZkStateReader refresh on every Overseer operation.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/38714399/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
index 8401f3e..c6e5116 100644
--- a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
@@ -337,11 +337,17 @@ public class ExtendedDismaxQParser extends QParser {
     if(query == null) {
       return null;
     }
-
-    // For correct lucene queries, turn off mm processing if there
-    // were explicit operators (except for AND).
+    // For correct lucene queries, turn off mm processing if no explicit mm spec was provided
+    // and there were explicit operators (except for AND).
     if (query instanceof BooleanQuery) {
-      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, config.minShouldMatch, config.mmAutoRelax);
+      // config.minShouldMatch holds the value of mm which MIGHT have come from the user,
+      // but could also have been derived from q.op.
+      String mmSpec = config.minShouldMatch;
+
+      if (foundOperators(clauses, config.lowercaseOperators)) {
+        mmSpec = params.get(DisMaxParams.MM, "0%"); // Use provided mm spec if present, otherwise turn off mm processing
+      }
+      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, mmSpec, config.mmAutoRelax);
     }
     return query;
   }
@@ -391,7 +397,28 @@ public class ExtendedDismaxQParser extends QParser {
     }
     return sb.toString();
   }
-  
+
+  /**
+   * Returns true if at least one of the clauses is/has an explicit operator (except for AND)
+   */
+  private boolean foundOperators(List<Clause> clauses, boolean lowercaseOperators) {
+    for (Clause clause : clauses) {
+      if (clause.must == '+') return true;
+      if (clause.must == '-') return true;
+      if (clause.isBareWord()) {
+        String s = clause.val;
+        if ("OR".equals(s)) {
+          return true;
+        } else if ("NOT".equals(s)) {
+          return true;
+        } else if (lowercaseOperators && "or".equals(s)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /**
    * Generates a query string from the raw clauses, uppercasing 
    * 'and' and 'or' as needed.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/38714399/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
index 019c54d..9b305f2 100644
--- a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
@@ -81,6 +81,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "63", "text_sw", "gold stocks"));
     assertU(adoc("id", "64", "text_sw", "stocks gold stockade"));
     assertU(adoc("id", "65", "text_sw", "snake oil"));
+    // SOLR-8812 user query example
+    assertU(adoc("id", "66", "text_sw", "hair ties barbie"));
+    assertU(adoc("id", "67", "text_sw", "hair ties"));
+    assertU(adoc("id", "68", "text_sw", "hair barbie"));
+    assertU(adoc("id", "69", "text_sw", "ties barbie"));
+    assertU(adoc("id", "70", "text_sw", "hair"));
+    assertU(adoc("id", "71", "text_sw", "ties"));
     assertU(commit());
   }
 
@@ -1145,6 +1152,154 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
             "mm", "100%",
             "defType", "edismax")
         , "*[count(//doc)=0]");
+
+    // SOLR-9174
+    assertQ("test minShouldMatch=1<-1 with explicit OR, one impossible clause, and no explicit q.op",
+        req("q", "barbie OR (hair AND nonexistentword)",
+            "qf", "text_sw",
+            "mm", "1<-1",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+  }
+
+  /* SOLR-8812 */
+  @Test
+  public void testDefaultMM() throws Exception {
+    // Ensure MM is off when explicit operators (+/-/OR/NOT) are used and no explicit mm spec is specified.
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit 'or' in query with lowercaseOperators=true, no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil or stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair and ties barbie",
+            "qf", "text_sw",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit OR in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+
+    assertQ("Explicit '+' operator in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair ties +barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
   }
 
   public void testEdismaxSimpleExtension() throws SyntaxError {


[02/11] lucene-solr:branch_6x: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3c789e9d
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3c789e9d
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3c789e9d

Branch: refs/heads/branch_6x
Commit: 3c789e9d274fb670c53c8eb6eb9dfceace2cd120
Parents: a60518c
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:33:30 2016 -0400

----------------------------------------------------------------------
 .../solr/search/ExtendedDismaxQParser.java      |  37 ++++-
 .../solr/search/TestExtendedDismaxParser.java   | 155 +++++++++++++++++++
 2 files changed, 187 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c789e9d/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
index 8401f3e..c6e5116 100644
--- a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
@@ -337,11 +337,17 @@ public class ExtendedDismaxQParser extends QParser {
     if(query == null) {
       return null;
     }
-
-    // For correct lucene queries, turn off mm processing if there
-    // were explicit operators (except for AND).
+    // For correct lucene queries, turn off mm processing if no explicit mm spec was provided
+    // and there were explicit operators (except for AND).
     if (query instanceof BooleanQuery) {
-      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, config.minShouldMatch, config.mmAutoRelax);
+      // config.minShouldMatch holds the value of mm which MIGHT have come from the user,
+      // but could also have been derived from q.op.
+      String mmSpec = config.minShouldMatch;
+
+      if (foundOperators(clauses, config.lowercaseOperators)) {
+        mmSpec = params.get(DisMaxParams.MM, "0%"); // Use provided mm spec if present, otherwise turn off mm processing
+      }
+      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, mmSpec, config.mmAutoRelax);
     }
     return query;
   }
@@ -391,7 +397,28 @@ public class ExtendedDismaxQParser extends QParser {
     }
     return sb.toString();
   }
-  
+
+  /**
+   * Returns true if at least one of the clauses is/has an explicit operator (except for AND)
+   */
+  private boolean foundOperators(List<Clause> clauses, boolean lowercaseOperators) {
+    for (Clause clause : clauses) {
+      if (clause.must == '+') return true;
+      if (clause.must == '-') return true;
+      if (clause.isBareWord()) {
+        String s = clause.val;
+        if ("OR".equals(s)) {
+          return true;
+        } else if ("NOT".equals(s)) {
+          return true;
+        } else if (lowercaseOperators && "or".equals(s)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /**
    * Generates a query string from the raw clauses, uppercasing 
    * 'and' and 'or' as needed.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3c789e9d/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
index 019c54d..9b305f2 100644
--- a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
@@ -81,6 +81,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "63", "text_sw", "gold stocks"));
     assertU(adoc("id", "64", "text_sw", "stocks gold stockade"));
     assertU(adoc("id", "65", "text_sw", "snake oil"));
+    // SOLR-8812 user query example
+    assertU(adoc("id", "66", "text_sw", "hair ties barbie"));
+    assertU(adoc("id", "67", "text_sw", "hair ties"));
+    assertU(adoc("id", "68", "text_sw", "hair barbie"));
+    assertU(adoc("id", "69", "text_sw", "ties barbie"));
+    assertU(adoc("id", "70", "text_sw", "hair"));
+    assertU(adoc("id", "71", "text_sw", "ties"));
     assertU(commit());
   }
 
@@ -1145,6 +1152,154 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
             "mm", "100%",
             "defType", "edismax")
         , "*[count(//doc)=0]");
+
+    // SOLR-9174
+    assertQ("test minShouldMatch=1<-1 with explicit OR, one impossible clause, and no explicit q.op",
+        req("q", "barbie OR (hair AND nonexistentword)",
+            "qf", "text_sw",
+            "mm", "1<-1",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+  }
+
+  /* SOLR-8812 */
+  @Test
+  public void testDefaultMM() throws Exception {
+    // Ensure MM is off when explicit operators (+/-/OR/NOT) are used and no explicit mm spec is specified.
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit 'or' in query with lowercaseOperators=true, no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil or stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair and ties barbie",
+            "qf", "text_sw",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit OR in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+
+    assertQ("Explicit '+' operator in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair ties +barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
   }
 
   public void testEdismaxSimpleExtension() throws SyntaxError {


[03/11] lucene-solr:branch_6x: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/74d94ec2
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/74d94ec2
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/74d94ec2

Branch: refs/heads/branch_6x
Commit: 74d94ec26585d57d6991f99c892f7be1278346f9
Parents: 3c789e9
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:34:56 2016 -0400

----------------------------------------------------------------------
 solr/CHANGES.txt | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/74d94ec2/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 5d2b594..a2f36c4 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -170,6 +170,10 @@ Bug Fixes
 
 * SOLR-9191: OverseerTaskQueue.peekTopN() fatally flawed (Scott Blum, Noble Paul)
 
+* SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided
+  and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
+  (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
+
 Optimizations
 ----------------------
 * SOLR-8722: Don't force a full ZkStateReader refresh on every Overseer operation.


[07/11] lucene-solr:branch_6_0: SOLR-8812: CHANGES.txt entry

Posted by sa...@apache.org.
SOLR-8812: CHANGES.txt entry


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/d5712fea
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/d5712fea
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/d5712fea

Branch: refs/heads/branch_6_0
Commit: d5712fea6058ed5fe905f4e157466d117a1f38c0
Parents: 202b993
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:42:48 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:42:48 2016 -0400

----------------------------------------------------------------------
 solr/CHANGES.txt | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/d5712fea/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 90cc88f..2b27844 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -23,6 +23,10 @@ Bug Fixes
 
 * SOLR-9191: OverseerTaskQueue.peekTopN() fatally flawed (Scott Blum, Noble Paul)
 
+* SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided
+  and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
+  (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
+
 ==================  6.0.1 ==================
 
 Upgrade Notes


[04/11] lucene-solr:branch_6_1: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/c2aac7d0
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/c2aac7d0
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/c2aac7d0

Branch: refs/heads/branch_6_1
Commit: c2aac7d005424094e129045e834aa6ffb2c7aa82
Parents: 80d6d26
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:39:49 2016 -0400

----------------------------------------------------------------------
 .../solr/search/ExtendedDismaxQParser.java      |  37 ++++-
 .../solr/search/TestExtendedDismaxParser.java   | 155 +++++++++++++++++++
 2 files changed, 187 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c2aac7d0/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
index 8401f3e..c6e5116 100644
--- a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
@@ -337,11 +337,17 @@ public class ExtendedDismaxQParser extends QParser {
     if(query == null) {
       return null;
     }
-
-    // For correct lucene queries, turn off mm processing if there
-    // were explicit operators (except for AND).
+    // For correct lucene queries, turn off mm processing if no explicit mm spec was provided
+    // and there were explicit operators (except for AND).
     if (query instanceof BooleanQuery) {
-      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, config.minShouldMatch, config.mmAutoRelax);
+      // config.minShouldMatch holds the value of mm which MIGHT have come from the user,
+      // but could also have been derived from q.op.
+      String mmSpec = config.minShouldMatch;
+
+      if (foundOperators(clauses, config.lowercaseOperators)) {
+        mmSpec = params.get(DisMaxParams.MM, "0%"); // Use provided mm spec if present, otherwise turn off mm processing
+      }
+      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, mmSpec, config.mmAutoRelax);
     }
     return query;
   }
@@ -391,7 +397,28 @@ public class ExtendedDismaxQParser extends QParser {
     }
     return sb.toString();
   }
-  
+
+  /**
+   * Returns true if at least one of the clauses is/has an explicit operator (except for AND)
+   */
+  private boolean foundOperators(List<Clause> clauses, boolean lowercaseOperators) {
+    for (Clause clause : clauses) {
+      if (clause.must == '+') return true;
+      if (clause.must == '-') return true;
+      if (clause.isBareWord()) {
+        String s = clause.val;
+        if ("OR".equals(s)) {
+          return true;
+        } else if ("NOT".equals(s)) {
+          return true;
+        } else if (lowercaseOperators && "or".equals(s)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /**
    * Generates a query string from the raw clauses, uppercasing 
    * 'and' and 'or' as needed.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c2aac7d0/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
index 019c54d..9b305f2 100644
--- a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
@@ -81,6 +81,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "63", "text_sw", "gold stocks"));
     assertU(adoc("id", "64", "text_sw", "stocks gold stockade"));
     assertU(adoc("id", "65", "text_sw", "snake oil"));
+    // SOLR-8812 user query example
+    assertU(adoc("id", "66", "text_sw", "hair ties barbie"));
+    assertU(adoc("id", "67", "text_sw", "hair ties"));
+    assertU(adoc("id", "68", "text_sw", "hair barbie"));
+    assertU(adoc("id", "69", "text_sw", "ties barbie"));
+    assertU(adoc("id", "70", "text_sw", "hair"));
+    assertU(adoc("id", "71", "text_sw", "ties"));
     assertU(commit());
   }
 
@@ -1145,6 +1152,154 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
             "mm", "100%",
             "defType", "edismax")
         , "*[count(//doc)=0]");
+
+    // SOLR-9174
+    assertQ("test minShouldMatch=1<-1 with explicit OR, one impossible clause, and no explicit q.op",
+        req("q", "barbie OR (hair AND nonexistentword)",
+            "qf", "text_sw",
+            "mm", "1<-1",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+  }
+
+  /* SOLR-8812 */
+  @Test
+  public void testDefaultMM() throws Exception {
+    // Ensure MM is off when explicit operators (+/-/OR/NOT) are used and no explicit mm spec is specified.
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit 'or' in query with lowercaseOperators=true, no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil or stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair and ties barbie",
+            "qf", "text_sw",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit OR in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+
+    assertQ("Explicit '+' operator in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair ties +barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
   }
 
   public void testEdismaxSimpleExtension() throws SyntaxError {


[08/11] lucene-solr:branch_5_5: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/5bc34949
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/5bc34949
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/5bc34949

Branch: refs/heads/branch_5_5
Commit: 5bc34949adc911dacba29c08f1e522de4679aee6
Parents: 9f5fae7
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:56:56 2016 -0400

----------------------------------------------------------------------
 .../solr/search/ExtendedDismaxQParser.java      |  37 ++++-
 .../solr/search/TestExtendedDismaxParser.java   | 155 +++++++++++++++++++
 2 files changed, 187 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5bc34949/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
index e273e7d..4a952cd 100644
--- a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
@@ -337,11 +337,17 @@ public class ExtendedDismaxQParser extends QParser {
     if(query == null) {
       return null;
     }
-
-    // For correct lucene queries, turn off mm processing if there
-    // were explicit operators (except for AND).
+    // For correct lucene queries, turn off mm processing if no explicit mm spec was provided
+    // and there were explicit operators (except for AND).
     if (query instanceof BooleanQuery) {
-      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, config.minShouldMatch);
+      // config.minShouldMatch holds the value of mm which MIGHT have come from the user,
+      // but could also have been derived from q.op.
+      String mmSpec = config.minShouldMatch;
+
+      if (foundOperators(clauses, config.lowercaseOperators)) {
+        mmSpec = params.get(DisMaxParams.MM, "0%"); // Use provided mm spec if present, otherwise turn off mm processing
+      }
+      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, mmSpec);
     }
     return query;
   }
@@ -391,7 +397,28 @@ public class ExtendedDismaxQParser extends QParser {
     }
     return sb.toString();
   }
-  
+
+  /**
+   * Returns true if at least one of the clauses is/has an explicit operator (except for AND)
+   */
+  private boolean foundOperators(List<Clause> clauses, boolean lowercaseOperators) {
+    for (Clause clause : clauses) {
+      if (clause.must == '+') return true;
+      if (clause.must == '-') return true;
+      if (clause.isBareWord()) {
+        String s = clause.val;
+        if ("OR".equals(s)) {
+          return true;
+        } else if ("NOT".equals(s)) {
+          return true;
+        } else if (lowercaseOperators && "or".equals(s)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /**
    * Generates a query string from the raw clauses, uppercasing 
    * 'and' and 'or' as needed.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5bc34949/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
index f68c33a..f61a4d0 100644
--- a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
@@ -81,6 +81,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "63", "text_sw", "gold stocks"));
     assertU(adoc("id", "64", "text_sw", "stocks gold stockade"));
     assertU(adoc("id", "65", "text_sw", "snake oil"));
+    // SOLR-8812 user query example
+    assertU(adoc("id", "66", "text_sw", "hair ties barbie"));
+    assertU(adoc("id", "67", "text_sw", "hair ties"));
+    assertU(adoc("id", "68", "text_sw", "hair barbie"));
+    assertU(adoc("id", "69", "text_sw", "ties barbie"));
+    assertU(adoc("id", "70", "text_sw", "hair"));
+    assertU(adoc("id", "71", "text_sw", "ties"));
     assertU(commit());
   }
 
@@ -1150,6 +1157,154 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
             "mm", "100%",
             "defType", "edismax")
         , "*[count(//doc)=0]");
+
+    // SOLR-9174
+    assertQ("test minShouldMatch=1<-1 with explicit OR, one impossible clause, and no explicit q.op",
+        req("q", "barbie OR (hair AND nonexistentword)",
+            "qf", "text_sw",
+            "mm", "1<-1",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+  }
+
+  /* SOLR-8812 */
+  @Test
+  public void testDefaultMM() throws Exception {
+    // Ensure MM is off when explicit operators (+/-/OR/NOT) are used and no explicit mm spec is specified.
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit 'or' in query with lowercaseOperators=true, no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil or stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair and ties barbie",
+            "qf", "text_sw",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit OR in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+
+    assertQ("Explicit '+' operator in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair ties +barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
   }
 
   public void testEdismaxSimpleExtension() throws SyntaxError {


[10/11] lucene-solr:branch_5x: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/e88a64a0
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/e88a64a0
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/e88a64a0

Branch: refs/heads/branch_5x
Commit: e88a64a0490ac2139e0aa55a8ca8b3588ce41395
Parents: 5955712
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:59:41 2016 -0400

----------------------------------------------------------------------
 .../solr/search/ExtendedDismaxQParser.java      |  37 ++++-
 .../solr/search/TestExtendedDismaxParser.java   | 155 +++++++++++++++++++
 2 files changed, 187 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e88a64a0/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
index e273e7d..4a952cd 100644
--- a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
@@ -337,11 +337,17 @@ public class ExtendedDismaxQParser extends QParser {
     if(query == null) {
       return null;
     }
-
-    // For correct lucene queries, turn off mm processing if there
-    // were explicit operators (except for AND).
+    // For correct lucene queries, turn off mm processing if no explicit mm spec was provided
+    // and there were explicit operators (except for AND).
     if (query instanceof BooleanQuery) {
-      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, config.minShouldMatch);
+      // config.minShouldMatch holds the value of mm which MIGHT have come from the user,
+      // but could also have been derived from q.op.
+      String mmSpec = config.minShouldMatch;
+
+      if (foundOperators(clauses, config.lowercaseOperators)) {
+        mmSpec = params.get(DisMaxParams.MM, "0%"); // Use provided mm spec if present, otherwise turn off mm processing
+      }
+      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, mmSpec);
     }
     return query;
   }
@@ -391,7 +397,28 @@ public class ExtendedDismaxQParser extends QParser {
     }
     return sb.toString();
   }
-  
+
+  /**
+   * Returns true if at least one of the clauses is/has an explicit operator (except for AND)
+   */
+  private boolean foundOperators(List<Clause> clauses, boolean lowercaseOperators) {
+    for (Clause clause : clauses) {
+      if (clause.must == '+') return true;
+      if (clause.must == '-') return true;
+      if (clause.isBareWord()) {
+        String s = clause.val;
+        if ("OR".equals(s)) {
+          return true;
+        } else if ("NOT".equals(s)) {
+          return true;
+        } else if (lowercaseOperators && "or".equals(s)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /**
    * Generates a query string from the raw clauses, uppercasing 
    * 'and' and 'or' as needed.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e88a64a0/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
index f68c33a..f61a4d0 100644
--- a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
@@ -81,6 +81,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "63", "text_sw", "gold stocks"));
     assertU(adoc("id", "64", "text_sw", "stocks gold stockade"));
     assertU(adoc("id", "65", "text_sw", "snake oil"));
+    // SOLR-8812 user query example
+    assertU(adoc("id", "66", "text_sw", "hair ties barbie"));
+    assertU(adoc("id", "67", "text_sw", "hair ties"));
+    assertU(adoc("id", "68", "text_sw", "hair barbie"));
+    assertU(adoc("id", "69", "text_sw", "ties barbie"));
+    assertU(adoc("id", "70", "text_sw", "hair"));
+    assertU(adoc("id", "71", "text_sw", "ties"));
     assertU(commit());
   }
 
@@ -1150,6 +1157,154 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
             "mm", "100%",
             "defType", "edismax")
         , "*[count(//doc)=0]");
+
+    // SOLR-9174
+    assertQ("test minShouldMatch=1<-1 with explicit OR, one impossible clause, and no explicit q.op",
+        req("q", "barbie OR (hair AND nonexistentword)",
+            "qf", "text_sw",
+            "mm", "1<-1",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+  }
+
+  /* SOLR-8812 */
+  @Test
+  public void testDefaultMM() throws Exception {
+    // Ensure MM is off when explicit operators (+/-/OR/NOT) are used and no explicit mm spec is specified.
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit 'or' in query with lowercaseOperators=true, no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil or stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair and ties barbie",
+            "qf", "text_sw",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit OR in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+
+    assertQ("Explicit '+' operator in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair ties +barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
   }
 
   public void testEdismaxSimpleExtension() throws SyntaxError {


[05/11] lucene-solr:branch_6_1: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/e0c6762d
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/e0c6762d
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/e0c6762d

Branch: refs/heads/branch_6_1
Commit: e0c6762de8dd91e02a79a6d12b3164a052bf07ff
Parents: c2aac7d
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:39:55 2016 -0400

----------------------------------------------------------------------
 solr/CHANGES.txt | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/e0c6762d/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 56eea0b..673c1ab 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -165,6 +165,10 @@ Bug Fixes
 
 * SOLR-9191: OverseerTaskQueue.peekTopN() fatally flawed (Scott Blum, Noble Paul)
 
+* SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided
+  and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
+  (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
+
 Optimizations
 ----------------------
 * SOLR-8722: Don't force a full ZkStateReader refresh on every Overseer operation.


[09/11] lucene-solr:branch_5_5: SOLR-8812: CHANGES.txt entry

Posted by sa...@apache.org.
SOLR-8812: CHANGES.txt entry


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/508f8f83
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/508f8f83
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/508f8f83

Branch: refs/heads/branch_5_5
Commit: 508f8f83e1ed3bb8c7f8ca37d767e95b5b7b87c3
Parents: 5bc3494
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:57:34 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:57:34 2016 -0400

----------------------------------------------------------------------
 solr/CHANGES.txt | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/508f8f83/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 27cfd02..ac59af2 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -16,6 +16,10 @@ Bug Fixes
 
 * SOLR-9191: OverseerTaskQueue.peekTopN() fatally flawed (Scott Blum, Noble Paul)
 
+* SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided
+  and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
+  (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
+
 ======================= 5.5.1 =======================
 
 Bug Fixes


[11/11] lucene-solr:branch_5x: SOLR-8812: CHANGES.txt entry

Posted by sa...@apache.org.
SOLR-8812: CHANGES.txt entry


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/1dff75c6
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/1dff75c6
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/1dff75c6

Branch: refs/heads/branch_5x
Commit: 1dff75c643f17c5447264fecb9b71530e05f017f
Parents: e88a64a
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 03:00:46 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 03:00:46 2016 -0400

----------------------------------------------------------------------
 solr/CHANGES.txt | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/1dff75c6/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index d76a853..faec8ce 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -24,6 +24,10 @@ Bug Fixes
 
 * SOLR-9191: OverseerTaskQueue.peekTopN() fatally flawed (Scott Blum, Noble Paul)
 
+* SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided
+  and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
+  (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
+
 Other Changes
 ----------------------
 


[06/11] lucene-solr:branch_6_0: SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649

Posted by sa...@apache.org.
SOLR-8812: edismax: turn off mm processing if no explicit mm spec is provided and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/202b9933
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/202b9933
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/202b9933

Branch: refs/heads/branch_6_0
Commit: 202b993335a370be06db02b866c62a876350b01d
Parents: c6b0488
Author: Steve Rowe <sa...@apache.org>
Authored: Fri Jun 10 02:29:26 2016 -0400
Committer: Steve Rowe <sa...@apache.org>
Committed: Fri Jun 10 02:41:28 2016 -0400

----------------------------------------------------------------------
 .../solr/search/ExtendedDismaxQParser.java      |  37 ++++-
 .../solr/search/TestExtendedDismaxParser.java   | 155 +++++++++++++++++++
 2 files changed, 187 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/202b9933/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
index 8401f3e..c6e5116 100644
--- a/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
+++ b/solr/core/src/java/org/apache/solr/search/ExtendedDismaxQParser.java
@@ -337,11 +337,17 @@ public class ExtendedDismaxQParser extends QParser {
     if(query == null) {
       return null;
     }
-
-    // For correct lucene queries, turn off mm processing if there
-    // were explicit operators (except for AND).
+    // For correct lucene queries, turn off mm processing if no explicit mm spec was provided
+    // and there were explicit operators (except for AND).
     if (query instanceof BooleanQuery) {
-      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, config.minShouldMatch, config.mmAutoRelax);
+      // config.minShouldMatch holds the value of mm which MIGHT have come from the user,
+      // but could also have been derived from q.op.
+      String mmSpec = config.minShouldMatch;
+
+      if (foundOperators(clauses, config.lowercaseOperators)) {
+        mmSpec = params.get(DisMaxParams.MM, "0%"); // Use provided mm spec if present, otherwise turn off mm processing
+      }
+      query = SolrPluginUtils.setMinShouldMatch((BooleanQuery)query, mmSpec, config.mmAutoRelax);
     }
     return query;
   }
@@ -391,7 +397,28 @@ public class ExtendedDismaxQParser extends QParser {
     }
     return sb.toString();
   }
-  
+
+  /**
+   * Returns true if at least one of the clauses is/has an explicit operator (except for AND)
+   */
+  private boolean foundOperators(List<Clause> clauses, boolean lowercaseOperators) {
+    for (Clause clause : clauses) {
+      if (clause.must == '+') return true;
+      if (clause.must == '-') return true;
+      if (clause.isBareWord()) {
+        String s = clause.val;
+        if ("OR".equals(s)) {
+          return true;
+        } else if ("NOT".equals(s)) {
+          return true;
+        } else if (lowercaseOperators && "or".equals(s)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   /**
    * Generates a query string from the raw clauses, uppercasing 
    * 'and' and 'or' as needed.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/202b9933/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
index 019c54d..9b305f2 100644
--- a/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestExtendedDismaxParser.java
@@ -81,6 +81,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
     assertU(adoc("id", "63", "text_sw", "gold stocks"));
     assertU(adoc("id", "64", "text_sw", "stocks gold stockade"));
     assertU(adoc("id", "65", "text_sw", "snake oil"));
+    // SOLR-8812 user query example
+    assertU(adoc("id", "66", "text_sw", "hair ties barbie"));
+    assertU(adoc("id", "67", "text_sw", "hair ties"));
+    assertU(adoc("id", "68", "text_sw", "hair barbie"));
+    assertU(adoc("id", "69", "text_sw", "ties barbie"));
+    assertU(adoc("id", "70", "text_sw", "hair"));
+    assertU(adoc("id", "71", "text_sw", "ties"));
     assertU(commit());
   }
 
@@ -1145,6 +1152,154 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
             "mm", "100%",
             "defType", "edismax")
         , "*[count(//doc)=0]");
+
+    // SOLR-9174
+    assertQ("test minShouldMatch=1<-1 with explicit OR, one impossible clause, and no explicit q.op",
+        req("q", "barbie OR (hair AND nonexistentword)",
+            "qf", "text_sw",
+            "mm", "1<-1",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+  }
+
+  /* SOLR-8812 */
+  @Test
+  public void testDefaultMM() throws Exception {
+    // Ensure MM is off when explicit operators (+/-/OR/NOT) are used and no explicit mm spec is specified.
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit 'or' in query with lowercaseOperators=true, no explicit mm and q.op=AND => mm = 0%",
+        req("q", "oil or stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "oil OR stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+    assertQ("No operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "oil stocks",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=4]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties -barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair AND ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+    assertQ("No explicit non-AND operator in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair and ties barbie",
+            "qf", "text_sw",
+            "lowercaseOperators", "true",
+            "defType", "edismax")
+        , "*[count(//doc)=2]");
+
+    assertQ("Explicit '-' operator in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties -barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+    assertQ("Explicit NOT in query with no explicit mm and q.op=AND => mm = 100%",
+        req("q", "hair ties NOT barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
+
+    assertQ("Explicit OR in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=3]");
+    assertQ("Explicit OR in query with no explicit mm and q.op=OR => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "q.op", "OR",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+    assertQ("Explicit OR in query with no explicit mm and no explicit q.op => mm = 0%",
+        req("q", "hair OR ties barbie",
+            "qf", "text_sw",
+            "defType", "edismax")
+        , "*[count(//doc)=6]");
+
+    assertQ("Explicit '+' operator in query with no explicit mm and q.op=AND => mm = 0%",
+        req("q", "hair ties +barbie",
+            "qf", "text_sw",
+            "q.op", "AND",
+            "defType", "edismax")
+        , "*[count(//doc)=1]");
   }
 
   public void testEdismaxSimpleExtension() throws SyntaxError {