/* * 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.lucene.queries.function; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryUtils; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.junit.AfterClass; import org.junit.BeforeClass; public class TestFunctionScoreQuery extends FunctionTestSetup { static IndexReader reader; static IndexSearcher searcher; @BeforeClass public static void beforeClass() throws Exception { createIndex(true); reader = DirectoryReader.open(dir); searcher = new IndexSearcher(reader); } @AfterClass public static void afterClass() throws Exception { reader.close(); } // FunctionQuery equivalent public void testSimpleSourceScore() throws Exception { FunctionScoreQuery q = new FunctionScoreQuery(new TermQuery(new Term(TEXT_FIELD, "first")), DoubleValuesSource.fromIntField(INT_FIELD)); QueryUtils.check(random(), q, searcher, rarely()); int expectedDocs[] = new int[]{ 4, 7, 9 }; TopDocs docs = searcher.search(q, 4); assertEquals(expectedDocs.length, docs.totalHits); for (int i = 0; i < expectedDocs.length; i++) { assertEquals(docs.scoreDocs[i].doc, expectedDocs[i]); } } // CustomScoreQuery and BoostedQuery equivalent public void testScoreModifyingSource() throws Exception { DoubleValuesSource iii = DoubleValuesSource.fromIntField("iii"); DoubleValuesSource score = DoubleValuesSource.scoringFunction(iii, "v * s", (v, s) -> v * s); BooleanQuery bq = new BooleanQuery.Builder() .add(new TermQuery(new Term(TEXT_FIELD, "first")), BooleanClause.Occur.SHOULD) .add(new TermQuery(new Term(TEXT_FIELD, "text")), BooleanClause.Occur.SHOULD) .build(); TopDocs plain = searcher.search(bq, 1); FunctionScoreQuery fq = new FunctionScoreQuery(bq, score); QueryUtils.check(random(), fq, searcher, rarely()); int[] expectedDocs = new int[]{ 4, 7, 9, 8, 12 }; TopDocs docs = searcher.search(fq, 5); assertEquals(plain.totalHits, docs.totalHits); for (int i = 0; i < expectedDocs.length; i++) { assertEquals(expectedDocs[i], docs.scoreDocs[i].doc); } } // check boosts with non-distributive score source public void testBoostsAreAppliedLast() throws Exception { DoubleValuesSource scores = DoubleValuesSource.function(DoubleValuesSource.SCORES, "ln(v + 4)", v -> Math.log(v + 4)); Query q1 = new FunctionScoreQuery(new TermQuery(new Term(TEXT_FIELD, "text")), scores); TopDocs plain = searcher.search(q1, 5); Query boosted = new BoostQuery(q1, 2); TopDocs afterboost = searcher.search(boosted, 5); assertEquals(plain.totalHits, afterboost.totalHits); for (int i = 0; i < 5; i++) { assertEquals(plain.scoreDocs[i].doc, afterboost.scoreDocs[i].doc); assertEquals(plain.scoreDocs[i].score, afterboost.scoreDocs[i].score / 2, 0.0001); } } }