mazerone
mazerone

Reputation: 121

change score in Lucene 5.2.1

I want to change the scoring function of my Search Engine in Lucene 5.2.1. I just want to add the output of a function f to the default lucene's score. Something like this:

myScore = defaultScore + f(field1, field2)

Where f is a simple calculus on two indexed document fields (containing a numeric value). This link proves that it should be possible to do this kind of things, but no snippet is provided at all.

Finally, you can extend the low level Similarity directly to implement a new retrieval model, or to use external scoring factors particular to your application. For example, a custom Similarity can access per-document values via NumericDocValues and integrate them into the score.

Anybody knows how to do it? Many thanks

Upvotes: 0

Views: 759

Answers (1)

Allen Chou
Allen Chou

Reputation: 1237

I think CustomScoreQuery may be what you want. The link of CustomScoreQuery is in Lucene 5.2.1. Following is code snippet about trying to get your problem done with Lucene 3.6.2 in Scala.

import org.apache.lucene.index.{ Term, IndexReader }
import org.apache.lucene.search.{ TermQuery, Query }
import org.apache.lucene.search.function.{ CustomScoreProvider, CustomScoreQuery }

class CustomizedScoreProvider(reader: IndexReader) extends 
    CustomScoreProvider(reader) {

    protected override def customScore(doc: Int, 
        subQueryScore: Float, valSrcScores: Array[Float]): Float = {
        try {
            // subQueryScore is the default score you get from  
            // the original Query
            val currentDocument = reader.document(doc)

            // get the value of two field1, field2, 
            // make sure the two fields are stored since you have to retrieve the value
            val field1Value = currentDocument.get("field1")
            val field2Value = currentDocument.get("field2")

            // write your own logical to compute the extra score, assuming 0 here
            val extraScore = 0F

            // ignore the valSrcScores here, the original calculation      
            // is modifiedScore = subQueryScore*valSrcScores[0]*..
            subQueryScore + extraScore
        } catch {
            case _: Exception => subQueryScore
        }
    }
}

/**
 * Create a CustomScoreQuery over input subQuery.
 * @param subQuery the sub query whose scored is being customized. Must not be null.
 */
class CustomizedScoreQuery(val subQuery: Query, reader: IndexReader) 
    extends CustomScoreQuery(subQuery) {
    protected override def getCustomScoreProvider(reader: IndexReader) = {
        try {
            new CustomizedScoreProvider(reader)
        } catch {
            case _: Exception => super.getCustomScoreProvider(reader)
        }
    }
}


object CustomizedScoreQueryTest extends App {

    val termQuery = new TermQuery(new Term("field", "xxx"))
    // get indexSearch, indexReader and  wrap the original query
    ...
    val wrappedQuery = new CustomizedScoreQuery(termQuery, indexReader)
    val topDocs = indexSearch.search(wrappedQuery, 5)
    ...

}

Actually, I got stuck with the same problem when I saw your question and finally got it done with CustomScoreQuery. When you use CustomScoreQuery to change the default score, say when sorting by relevance, the document order will change according to the modified score.

Anyway, hope it helps.

Upvotes: 1

Related Questions