You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2013/05/12 23:23:38 UTC

svn commit: r1481651 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/search/ core/src/test/org/apache/solr/search/

Author: janhoy
Date: Sun May 12 21:23:37 2013
New Revision: 1481651

URL: http://svn.apache.org/r1481651
Log:
SOLR-4785: New MaxScoreQParserPlugin

Added:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParser.java   (with props)
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParserPlugin.java   (with props)
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/QParserPlugin.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1481651&r1=1481650&r2=1481651&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Sun May 12 21:23:37 2013
@@ -78,6 +78,8 @@ New Features
   in cases where exact hit-counts are unnecessary.  Also, when "collateExtendedResults"
   is false, this optimization is always made (James Dyer).
 
+* SOLR-4785: New MaxScoreQParserPlugin returning max() instead of sum() of terms (janhoy)
+
 Bug Fixes
 ----------------------
 

Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParser.java?rev=1481651&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParser.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParser.java Sun May 12 21:23:37 2013
@@ -0,0 +1,83 @@
+/*
+ * 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 org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.DisjunctionMaxQuery;
+import org.apache.lucene.search.Query;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @see MaxScoreQParserPlugin
+ */
+public class MaxScoreQParser extends LuceneQParser {
+  float tie = 0.0f;
+
+  public MaxScoreQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
+    super(qstr, localParams, params, req);
+    if (getParam("tie") != null) {
+      tie = Float.parseFloat(getParam("tie"));
+    }
+  }
+
+  /**
+   * Parses the query exactly like the Lucene parser does, but
+   * delegates all SHOULD clauses to DisjunctionMaxQuery with
+   * meaning only the clause with the max score will contribute
+   * to the overall score, unless the tie parameter is specified.
+   * <br/>
+   * The max() is only calculated from the SHOULD clauses.
+   * Any MUST clauses will be passed through as separate
+   * BooleanClauses and thus always contribute to the score.
+   * @return the resulting Query
+   * @throws org.apache.solr.search.SyntaxError if parsing fails
+   */
+  @Override
+  public Query parse() throws SyntaxError {
+    Query q = super.parse();
+    if (!(q instanceof BooleanQuery)) {
+      return q;
+    }
+    BooleanQuery obq = (BooleanQuery)q;
+    Collection<Query> should = new ArrayList<Query>();
+    Collection<BooleanClause> prohibOrReq = new ArrayList<BooleanClause>();
+    BooleanQuery newq = new BooleanQuery();
+
+    for (BooleanClause clause : obq.getClauses()) {
+      if(clause.isProhibited() || clause.isRequired()) {
+        prohibOrReq.add(clause);
+      } else {
+        BooleanQuery bq = new BooleanQuery();
+        bq.add(clause);
+        should.add(bq);
+      }
+    }
+    if (should.size() > 0) {
+      DisjunctionMaxQuery dmq = new DisjunctionMaxQuery(should, tie);
+      newq.add(dmq, BooleanClause.Occur.SHOULD);
+    }
+    for(BooleanClause c : prohibOrReq) {
+      newq.add(c);
+    }
+    return newq;
+  }
+}
\ No newline at end of file

Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParserPlugin.java?rev=1481651&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParserPlugin.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/MaxScoreQParserPlugin.java Sun May 12 21:23:37 2013
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrQueryRequest;
+
+/**
+ * Parses a query like Lucene query parser, but scoring with max score, not sum
+ * <br>Accepts the "tie" request parameter as with dismax. 0.0=max, 1.0=sum
+ * <br>All other parameters are as with Lucene parser
+ * <br>Example: <code>q=foo {!maxscore v=$myq}&myq=A OR B OR C</code>
+ */
+public class MaxScoreQParserPlugin extends LuceneQParserPlugin {
+  public static String NAME = "maxscore";
+
+  @Override
+  public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
+    return new MaxScoreQParser(qstr, localParams, params, req);
+  }
+}
+

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/QParserPlugin.java?rev=1481651&r1=1481650&r2=1481651&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/QParserPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/QParserPlugin.java Sun May 12 21:23:37 2013
@@ -43,6 +43,7 @@ public abstract class QParserPlugin impl
     JoinQParserPlugin.NAME, JoinQParserPlugin.class,
     SurroundQParserPlugin.NAME, SurroundQParserPlugin.class,
     SwitchQParserPlugin.NAME, SwitchQParserPlugin.class,
+    MaxScoreQParserPlugin.NAME, MaxScoreQParserPlugin.class
   };
 
   /** return a {@link QParser} */

Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java?rev=1481651&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestMaxScoreQueryParser.java Sun May 12 21:23:37 2013
@@ -0,0 +1,117 @@
+package org.apache.solr.search;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.search.*;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.util.AbstractSolrTestCase;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class TestMaxScoreQueryParser extends AbstractSolrTestCase {
+  Query q;
+  BooleanClause[] clauses;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig.xml", "schema.xml");
+  }
+
+  @Test
+  public void testFallbackToLucene() {
+    q = parse("foo");
+    assertTrue(q instanceof TermQuery);
+
+    q = parse("price:[0 TO 10]");
+    assertTrue(q instanceof NumericRangeQuery);
+  }
+
+  @Test
+  public void testNoShouldClauses() {
+    q = parse("+foo +bar");
+    clauses = clauses(q);
+    assertEquals(2, clauses.length);
+    assertTrue(clauses[0].isRequired());
+    assertTrue(clauses[1].isRequired());
+
+    q = parse("+foo -bar");
+    clauses = clauses(q);
+    assertEquals(2, clauses.length);
+    assertTrue(clauses[0].isRequired());
+    assertTrue(clauses[1].isProhibited());
+  }
+
+  @Test
+  public void testPureMax() {
+    q = parse("foo bar");
+    clauses = clauses(q);
+    assertEquals(1, clauses.length);
+    assertTrue(clauses[0].getQuery() instanceof DisjunctionMaxQuery);
+    assertEquals(0.0, ((DisjunctionMaxQuery) clauses[0].getQuery()).getTieBreakerMultiplier(), 1e-15);
+    ArrayList<Query> qa = ((DisjunctionMaxQuery) clauses[0].getQuery()).getDisjuncts();
+    assertEquals(2, qa.size());
+    assertEquals("text:foo", qa.get(0).toString());
+  }
+
+  @Test
+  public void testMaxAndProhibited() {
+    q = parse("foo bar -baz");
+    clauses = clauses(q);
+    assertEquals(2, clauses.length);
+    assertTrue(clauses[0].getQuery() instanceof DisjunctionMaxQuery);
+    assertTrue(clauses[1].getQuery() instanceof TermQuery);
+    assertEquals("text:baz", clauses[1].getQuery().toString());
+    assertTrue(clauses[1].isProhibited());
+  }
+
+  @Test
+  public void testTie() {
+    q = parse("foo bar", "tie", "0.5");
+    clauses = clauses(q);
+    assertEquals(1, clauses.length);
+    assertTrue(clauses[0].getQuery() instanceof DisjunctionMaxQuery);
+    assertEquals(0.5, ((DisjunctionMaxQuery) clauses[0].getQuery()).getTieBreakerMultiplier(), 1e-15);
+  }
+
+  //
+  // Helper methods
+  //
+
+  private Query parse(String q, String... params) {
+    try {
+      ModifiableSolrParams p = new ModifiableSolrParams();
+      ArrayList<String> al = new ArrayList<String>(Arrays.asList(params));
+      while(al.size() >= 2) {
+        p.add(al.remove(0), al.remove(0));
+      }
+      return new MaxScoreQParser(q, p, new ModifiableSolrParams(), req(q)).parse();
+    } catch (SyntaxError syntaxError) {
+      fail("Failed with exception "+syntaxError.getMessage());
+    }
+    fail("Parse failed");
+    return null;
+  }
+
+  private BooleanClause[] clauses(Query q) {
+    return ((BooleanQuery) q).getClauses();
+  }
+}