/* * 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. */ using System; using NUnit.Framework; using CorruptIndexException = Lucene.Net.Index.CorruptIndexException; using QueryParser = Lucene.Net.QueryParsers.QueryParser; using Explanation = Lucene.Net.Search.Explanation; using IndexSearcher = Lucene.Net.Search.IndexSearcher; using Query = Lucene.Net.Search.Query; using QueryUtils = Lucene.Net.Search.QueryUtils; using TopDocs = Lucene.Net.Search.TopDocs; using Lucene.Net.Search; using Lucene.Net.Index; namespace Lucene.Net.Search.Function { /// Test CustomScoreQuery search. [TestFixture] public class TestCustomScoreQuery:FunctionTestSetup { /* @override constructor */ public TestCustomScoreQuery(System.String name):base(name, true) { } public TestCustomScoreQuery() : base() { } /// Test that CustomScoreQuery of Type.BYTE returns the expected scores. [Test] public virtual void TestCustomScoreByte() { // 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); } /// Test that CustomScoreQuery of Type.SHORT returns the expected scores. [Test] public virtual void TestCustomScoreShort() { // 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); } /// Test that CustomScoreQuery of Type.INT returns the expected scores. [Test] public virtual void TestCustomScoreInt() { DoTestCustomScore(INT_FIELD, FieldScoreQuery.Type.INT, 1.0); DoTestCustomScore(INT_FIELD, FieldScoreQuery.Type.INT, 4.0); } /// Test that CustomScoreQuery of Type.FLOAT returns the expected scores. [Test] public virtual void TestCustomScoreFloat() { // 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 float format DoTestCustomScore(FLOAT_FIELD, FieldScoreQuery.Type.FLOAT, 1.0); DoTestCustomScore(FLOAT_FIELD, FieldScoreQuery.Type.FLOAT, 6.0); } // must have static class otherwise serialization tests fail [Serializable] private class CustomAddQuery:CustomScoreQuery { // constructor internal CustomAddQuery(Query q, ValueSourceQuery qValSrc):base(q, qValSrc) { } /*(non-Javadoc) @see Lucene.Net.Search.Function.CustomScoreQuery#name() */ public override System.String Name() { return "customAdd"; } protected override CustomScoreProvider GetCustomScoreProvider(IndexReader reader) { return new AnonymousCustomScoreProvider(reader); } class AnonymousCustomScoreProvider : CustomScoreProvider { public AnonymousCustomScoreProvider(IndexReader reader) : base(reader) { } public override float CustomScore(int doc, float subQueryScore, float valSrcScore) { return subQueryScore + valSrcScore; } public override Explanation CustomExplain(int doc, Explanation subQueryExpl, Explanation valSrcExpl) { float valSrcScore = valSrcExpl == null ? 0 : valSrcExpl.Value; Explanation exp = new Explanation(valSrcScore + subQueryExpl.Value, "custom score: sum of:"); exp.AddDetail(subQueryExpl); if (valSrcExpl != null) { exp.AddDetail(valSrcExpl); } return exp; } } } // must have static class otherwise serialization tests fail [Serializable] private class CustomMulAddQuery:CustomScoreQuery { // constructor internal CustomMulAddQuery(Query q, ValueSourceQuery qValSrc1, ValueSourceQuery qValSrc2):base(q, new ValueSourceQuery[]{qValSrc1, qValSrc2}) { } /*(non-Javadoc) @see Lucene.Net.Search.Function.CustomScoreQuery#name() */ public override System.String Name() { return "customMulAdd"; } /*(non-Javadoc) @see Lucene.Net.Search.Function.CustomScoreQuery#customScore(int, float, float) */ protected override CustomScoreProvider GetCustomScoreProvider(IndexReader reader) { return new AnonymousCustomScoreProvider(reader); } class AnonymousCustomScoreProvider : CustomScoreProvider { public AnonymousCustomScoreProvider(IndexReader reader) : base(reader) { } public override float CustomScore(int doc, float subQueryScore, float[] valSrcScores) { if (valSrcScores.Length == 0) { return subQueryScore; } if (valSrcScores.Length == 1) { return subQueryScore + valSrcScores[0]; // confirm that skipping beyond the last doc, on the // previous reader, hits NO_MORE_DOCS } return (subQueryScore + valSrcScores[0]) * valSrcScores[1]; // we know there are two } public override Explanation CustomExplain(int doc, Explanation subQueryExpl, Explanation[] valSrcExpls) { if (valSrcExpls.Length == 0) { return subQueryExpl; } Explanation exp = new Explanation(valSrcExpls[0].Value + subQueryExpl.Value, "sum of:"); exp.AddDetail(subQueryExpl); exp.AddDetail(valSrcExpls[0]); if (valSrcExpls.Length == 1) { exp.Description = "CustomMulAdd, sum of:"; return exp; } Explanation exp2 = new Explanation(valSrcExpls[1].Value * exp.Value, "custom score: product of:"); exp2.AddDetail(valSrcExpls[1]); exp2.AddDetail(exp); return exp2; } } } private class CustomExternalQuery : CustomScoreQuery { protected override CustomScoreProvider GetCustomScoreProvider(IndexReader reader) { int[] values = FieldCache_Fields.DEFAULT.GetInts(reader, INT_FIELD); return new AnonymousCustomScoreProvider(reader,values); } class AnonymousCustomScoreProvider : CustomScoreProvider { int[] values = null; public AnonymousCustomScoreProvider(IndexReader reader, int[] values) : base(reader) { this.values = values; } public override float CustomScore(int doc, float subScore, float valSrcScore) { Assert.IsTrue(doc <= reader.MaxDoc); return (float)values[doc]; } } public CustomExternalQuery(Query q) : base(q) { } } [Test] public void TestCustomExternalQuery() { QueryParser qp = new QueryParser(Util.Version.LUCENE_CURRENT,TEXT_FIELD,anlzr); String qtxt = "first aid text"; // from the doc texts in FunctionQuerySetup. Query q1 = qp.Parse(qtxt); Query q = new CustomExternalQuery(q1); Log(q); IndexSearcher s = new IndexSearcher(dir); TopDocs hits = s.Search(q, 1000); Assert.AreEqual(N_DOCS, hits.TotalHits); for(int i=0;i