FileDocCategorySizeDatePackage
TestCustomScoreQuery.javaAPI DocApache Lucene 2.2.010495Sat Jun 16 22:20:26 BST 2007org.apache.lucene.search.function

TestCustomScoreQuery

public class TestCustomScoreQuery extends FunctionTestSetup
Test CustomScoreQuery search.

Fields Summary
Constructors Summary
public TestCustomScoreQuery(String name)

    super(name);
  
Methods Summary
private voiddoTestCustomScore(java.lang.String field, org.apache.lucene.search.function.FieldScoreQuery$Type tp, double dboost)

    float boost = (float) dboost;
    IndexSearcher s = new IndexSearcher(dir);
    FieldScoreQuery qValSrc = new FieldScoreQuery(field,tp); // a query that would score by the field
    QueryParser qp = new QueryParser(TEXT_FIELD,anlzr); 
    String qtxt = "bleeding person chain knowledge"; // from the doc texts in FunctionQuerySetup.
    
    // regular (boolean) query.
    Query q1 = qp.parse(qtxt); 
    log(q1);
    
    // custom query, that should score the same as q1.
    CustomScoreQuery q2CustomNeutral = new CustomScoreQuery(q1);
    q2CustomNeutral.setBoost(boost);
    log(q2CustomNeutral);
    
    // custom query, that should (by default) multiply the scores of q1 by that of the field
    CustomScoreQuery q3CustomMul = new CustomScoreQuery(q1,qValSrc);
    q3CustomMul.setStrict(true);
    q3CustomMul.setBoost(boost);
    log(q3CustomMul);
    
    // custom query, that should add the scores of q1 to that of the field
    CustomScoreQuery q4CustomAdd = new CustomScoreQuery(q1,qValSrc) {
      /*(non-Javadoc) @see org.apache.lucene.search.function.CustomScoreQuery#name() */
      public String name() {
        return "customAdd";
      }
      /*(non-Javadoc) @see org.apache.lucene.search.function.CustomScoreQuery#customScore(int, float, float) */
      public float customScore(int doc, float subQueryScore, float valSrcScore) {
        return subQueryScore + valSrcScore;
      }
      /* (non-Javadoc)@see org.apache.lucene.search.function.CustomScoreQuery#customExplain(int, org.apache.lucene.search.Explanation, org.apache.lucene.search.Explanation)*/
      public Explanation customExplain(int doc, Explanation subQueryExpl, Explanation valSrcExpl) {
        float valSrcScore = valSrcExpl==null ? 0 : valSrcExpl.getValue();
        Explanation exp = new Explanation( valSrcScore + subQueryExpl.getValue(), "custom score: sum of:");
        exp.addDetail(subQueryExpl);
        if (valSrcExpl != null) {
          exp.addDetail(valSrcExpl);
        }
        return exp;      
      } 
    };
    q4CustomAdd.setStrict(true);
    q4CustomAdd.setBoost(boost);
    log(q4CustomAdd);

    // custom query, that multiplies and adds the field score to that of q1
    CustomScoreQuery q5CustomMulAdd = new CustomScoreQuery(q1,qValSrc) {
      /*(non-Javadoc) @see org.apache.lucene.search.function.CustomScoreQuery#name() */
      public String name() {
        return "customMulAdd";
      }
      /*(non-Javadoc) @see org.apache.lucene.search.function.CustomScoreQuery#customScore(int, float, float) */
      public float customScore(int doc, float subQueryScore, float valSrcScore) {
        return (1 + subQueryScore) * valSrcScore;
      } 
      /* (non-Javadoc)@see org.apache.lucene.search.function.CustomScoreQuery#customExplain(int, org.apache.lucene.search.Explanation, org.apache.lucene.search.Explanation)*/
      public Explanation customExplain(int doc, Explanation subQueryExpl, Explanation valSrcExpl) {
        Explanation exp = new Explanation(1 + subQueryExpl.getValue(), "sum of:");
        exp.addDetail(subQueryExpl);
        exp.addDetail(new Explanation(1,"const 1"));
        if (valSrcExpl == null) {
          exp.setDescription("CustomMulAdd, sum of:");
          return exp;
        }
        Explanation exp2 = new Explanation(valSrcExpl.getValue() * exp.getValue(), "custom score: product of:");
        exp2.addDetail(valSrcExpl);
        exp2.addDetail(exp);
        return exp2;      
      } 
    };
    q5CustomMulAdd.setStrict(true);
    q5CustomMulAdd.setBoost(boost);
    log(q5CustomMulAdd);

    // do al the searches 
    TopDocs td1 = s.search(q1,null,1000);
    TopDocs td2CustomNeutral = s.search(q2CustomNeutral,null,1000);
    TopDocs td3CustomMul = s.search(q3CustomMul,null,1000);
    TopDocs td4CustomAdd = s.search(q4CustomAdd,null,1000);
    TopDocs td5CustomMulAdd = s.search(q5CustomMulAdd,null,1000);
    
    // put results in map so we can verify the scores although they have changed
    HashMap h1 = topDocsToMap(td1);
    HashMap h2CustomNeutral = topDocsToMap(td2CustomNeutral);
    HashMap h3CustomMul = topDocsToMap(td3CustomMul);
    HashMap h4CustomAdd = topDocsToMap(td4CustomAdd);
    HashMap h5CustomMulAdd = topDocsToMap(td5CustomMulAdd);
    
    verifyResults(boost, s, 
        h1, h2CustomNeutral, h3CustomMul, h4CustomAdd, h5CustomMulAdd,
        q1, q2CustomNeutral, q3CustomMul, q4CustomAdd, q5CustomMulAdd);
  
private voidlogResult(java.lang.String msg, org.apache.lucene.search.IndexSearcher s, org.apache.lucene.search.Query q, int doc, float score1)

    QueryUtils.check(q,s);
    log(msg+" "+score1);
    log("Explain by: "+q);
    log(s.explain(q,doc));
  
protected voidsetUp()

    // prepare a small index with just a few documents.  
    super.setUp();
  
protected voidtearDown()

    super.tearDown();
  
public voidtestCustomScoreByte()
Test that CustomScoreQuery of Type.BYTE returns the expected scores.

    // INT field values are small enough to be parsed as byte
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.BYTE,1.0);
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.BYTE,2.0);
  
public voidtestCustomScoreFloat()
Test that CustomScoreQuery of Type.FLOAT returns the expected scores.

    // INT field can be parsed as float
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.FLOAT,1.0);
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.FLOAT,5.0);
    // same values, but in flot format
    doTestCustomScore(FLOAT_FIELD,FieldScoreQuery.Type.FLOAT,1.0);
    doTestCustomScore(FLOAT_FIELD,FieldScoreQuery.Type.FLOAT,6.0);
  
public voidtestCustomScoreInt()
Test that CustomScoreQuery of Type.INT returns the expected scores.

    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.INT,1.0);
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.INT,4.0);
  
public voidtestCustomScoreShort()
Test that CustomScoreQuery of Type.SHORT returns the expected scores.

    // INT field values are small enough to be parsed as short
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.SHORT,1.0);
    doTestCustomScore(INT_FIELD,FieldScoreQuery.Type.SHORT,3.0);
  
private java.util.HashMaptopDocsToMap(org.apache.lucene.search.TopDocs td)

    HashMap h = new HashMap(); 
    for (int i=0; i<td.totalHits; i++) {
      h.put(new Integer(td.scoreDocs[i].doc), new Float(td.scoreDocs[i].score));
    }
    return h;
  
private voidverifyResults(float boost, org.apache.lucene.search.IndexSearcher s, java.util.HashMap h1, java.util.HashMap h2customNeutral, java.util.HashMap h3CustomMul, java.util.HashMap h4CustomAdd, java.util.HashMap h5CustomMulAdd, org.apache.lucene.search.Query q1, org.apache.lucene.search.Query q2, org.apache.lucene.search.Query q3, org.apache.lucene.search.Query q4, org.apache.lucene.search.Query q5)

    
    // verify numbers of matches
    log("#hits = "+h1.size());
    assertEquals("queries should have same #hits",h1.size(),h2customNeutral.size());
    assertEquals("queries should have same #hits",h1.size(),h3CustomMul.size());
    assertEquals("queries should have same #hits",h1.size(),h4CustomAdd.size());
    assertEquals("queries should have same #hits",h1.size(),h5CustomMulAdd.size());
    
    // verify scores ratios
    for (Iterator it = h1.keySet().iterator(); it.hasNext();) {
      Integer x = (Integer) it.next();

      int doc =  x.intValue();
      log("doc = "+doc);

      float fieldScore = expectedFieldScore(s.getIndexReader().document(doc).get(ID_FIELD));
      log("fieldScore = "+fieldScore);
      assertTrue("fieldScore should not be 0",fieldScore>0);

      float score1 = ((Float)h1.get(x)).floatValue();
      logResult("score1=", s, q1, doc, score1);
      
      float score2 = ((Float)h2customNeutral.get(x)).floatValue();
      logResult("score2=", s, q2, doc, score2);
      assertEquals("same score (just boosted) for neutral", boost * score1, score2, TEST_SCORE_TOLERANCE_DELTA);

      float score3 = ((Float)h3CustomMul.get(x)).floatValue();
      logResult("score3=", s, q3, doc, score3);
      assertEquals("new score for custom mul", boost * fieldScore * score1, score3, TEST_SCORE_TOLERANCE_DELTA);
      
      float score4 = ((Float)h4CustomAdd.get(x)).floatValue();
      logResult("score4=", s, q4, doc, score4);
      assertEquals("new score for custom add", boost * (fieldScore + score1), score4, TEST_SCORE_TOLERANCE_DELTA);
      
      float score5 = ((Float)h5CustomMulAdd.get(x)).floatValue();
      logResult("score5=", s, q5, doc, score5);
      assertEquals("new score for custom mul add", boost * fieldScore * (score1 + 1), score5, TEST_SCORE_TOLERANCE_DELTA);
    }