/** * Copyright 2014 National University of Ireland, Galway. * * This file is part of the SIREn project. Project and contact information: * * https://github.com/rdelbru/SIREn * * Licensed 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.sindice.siren.search.node; import static org.sindice.siren.analysis.MockSirenToken.node; import static org.sindice.siren.search.AbstractTestSirenScorer.NodeTermQueryBuilder.ntq; import java.io.IOException; import org.apache.lucene.index.CorruptIndexException; import org.junit.Test; import org.sindice.siren.index.DocsAndNodesIterator; import org.sindice.siren.index.codecs.RandomSirenCodec.PostingsFormatType; import org.sindice.siren.search.AbstractTestSirenScorer; public class TestNodeDisjunctionScorerNodeQueue extends AbstractTestSirenScorer { @Override protected void configure() throws IOException { this.setAnalyzer(AnalyzerType.TUPLE); this.setPostingsFormat(PostingsFormatType.RANDOM); } /** * Test method for {@link org.sindice.siren.search.node.NodeDisjunctionScorerQueue#top()}. * @throws IOException * @throws CorruptIndexException */ @Test public void testTop() throws IOException { this.addDocument("\"term1\" . "); this.addDocument("\"term2\" . "); this.addDocument("\"term3\" . \"term4\" . "); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(5); final NodeScorer s1 = this.getScorer(ntq("term1")); final NodeScorer s2 = this.getScorer(ntq("term2")); final NodeScorer s3 = this.getScorer(ntq("term3")); final NodeScorer s4 = this.getScorer(ntq("term4")); q.put(s3); assertSame(s3, q.top()); q.put(s2); assertSame(s2, q.top()); // s2 should be the least scorer q.put(s4); assertSame(s2, q.top()); q.put(s1); assertSame(s1, q.top()); // s1 should be the least scorer } @Test public void testNextCandidateDocumentAndAdjustElsePop() throws IOException { this.addDocument("\"term1\" \"term2\" . \"term3\" . \"term4\" . "); this.addDocument("\"term5\" \"term2\" . \"term3\" . "); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(4); q.put(this.getScorer(ntq("term2"))); q.put(this.getScorer(ntq("term3"))); q.put(this.getScorer(ntq("term4"))); q.put(this.getScorer(ntq("term5"))); assertEquals(0, q.doc()); assertEquals(4, q.size()); assertTrue(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(1, q.doc()); assertEquals(3, q.size()); // term4 scorer should have been removed assertFalse(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(DocsAndNodesIterator.NO_MORE_DOC, q.doc()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); } @Test public void testNextNodeAndAdjust() throws IOException { this.addDocument("\"term1\" \"term2\" . \"term3\" . \"term4\" . "); this.addDocument("\"term2\" \"term3\" . \"term5\" . "); this.addDocument("\"term2\" \"term1\" . \"term5\" . "); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(2); q.put(this.getScorer(ntq("term1"))); q.put(this.getScorer(ntq("term5"))); assertEquals(0, q.doc()); assertTrue(q.nextNodeAndAdjust()); assertEquals(node(0,0), q.node()); assertFalse(q.nextNodeAndAdjust()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); assertTrue(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(1, q.doc()); assertTrue(q.nextNodeAndAdjust()); assertEquals(node(1,0), q.node()); assertFalse(q.nextNodeAndAdjust()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); assertTrue(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(2, q.doc()); assertTrue(q.nextNodeAndAdjust()); assertEquals(node(0,1), q.node()); assertTrue(q.nextNodeAndAdjust()); assertEquals(node(1,0), q.node()); assertFalse(q.nextNodeAndAdjust()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); assertFalse(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(DocsAndNodesIterator.NO_MORE_DOC, q.doc()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); } @Test public void testNrMatches() throws IOException { this.addDocument("\"term1\" \"term2\" . \"term3\" . \"term4\" . "); this.addDocument("\"term2\" \"term3\" . \"term5\" . "); this.addDocument("\"term2\" \"term1 term5\" . "); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(2); q.put(this.getScorer(ntq("term1"))); q.put(this.getScorer(ntq("term5"))); assertEquals(0, q.doc()); assertTrue(q.nextNodeAndAdjust()); q.countAndSumMatchers(); // there must be 1 matchers for node {0,0} assertEquals(1, q.nrMatchersInNode()); assertTrue(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(1, q.doc()); assertTrue(q.nextNodeAndAdjust()); q.countAndSumMatchers(); // there must be 1 matchers for node {1,0} assertEquals(1, q.nrMatchersInNode()); assertTrue(q.nextCandidateDocumentAndAdjustElsePop()); assertEquals(2, q.doc()); assertTrue(q.nextNodeAndAdjust()); q.countAndSumMatchers(); // there must be 2 matchers for node {0,1} assertEquals(2, q.nrMatchersInNode()); } @Test public void testScoreSum() throws IOException { this.addDocument("\"term1 term2 term3\" . \"term4\" . "); final NodeScorer s1 = this.getScorer(ntq("term1")); final NodeScorer s2 = this.getScorer(ntq("term2")); final NodeScorer s3 = this.getScorer(ntq("term3")); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(3); q.put(s1); q.put(s2); q.put(s3); assertEquals(0, q.doc()); assertTrue(q.nextNodeAndAdjust()); q.countAndSumMatchers(); // there must be 3 matchers assertEquals(3, q.nrMatchersInNode()); final float scoreInNode = q.scoreInNode(); assertEquals(s1.scoreInNode() + s2.scoreInNode() + s3.scoreInNode(), scoreInNode, 0f); assertTrue(scoreInNode != 0); } @Test public void testskipToCandidateAndAdjustElsePop() throws IOException { this.addDocument("\"term1\" \"term2\" . "); this.addDocument("\"term3\" . \"term1\" . "); this.addDocument("\"term2\" \"term3\" . "); this.addDocument("\"term3\" . \"term1\" . "); this.addDocument("\"term3\" . \"term3\" . "); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(3); q.put(this.getScorer(ntq("term1"))); q.put(this.getScorer(ntq("term2"))); q.put(this.getScorer(ntq("term3"))); assertEquals(0, q.doc()); assertTrue(q.skipToCandidateAndAdjustElsePop(3)); assertEquals(3, q.doc()); assertEquals(2, q.size()); // term2 should have been removed assertTrue(q.nextNodeAndAdjust()); assertEquals(node(0,0), q.node()); assertTrue(q.nextNodeAndAdjust()); assertEquals(node(1,0), q.node()); assertFalse(q.nextNodeAndAdjust()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); assertTrue(q.skipToCandidateAndAdjustElsePop(2)); assertEquals(3, q.doc()); // queue should have not moved q.skipToCandidateAndAdjustElsePop(3); assertEquals(3, q.doc()); // queue should have not moved assertTrue(q.skipToCandidateAndAdjustElsePop(4)); assertEquals(4, q.doc()); assertEquals(1, q.size()); // term1 should have been removed assertTrue(q.nextNodeAndAdjust()); assertEquals(node(0,0), q.node()); assertTrue(q.nextNodeAndAdjust()); assertEquals(node(1,0), q.node()); assertFalse(q.nextNodeAndAdjust()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); assertFalse(q.skipToCandidateAndAdjustElsePop(7)); assertEquals(DocsAndNodesIterator.NO_MORE_DOC, q.doc()); assertEquals(DocsAndNodesIterator.NO_MORE_NOD, q.node()); } @Test public void testNextNodeHeapTraversal() throws IOException { this.addDocument("\"term1 term3\" \"term5 term2\" . \"term1 term3\" . \"term5 term4 term3\" . "); final NodeDisjunctionScorerQueue q = new NodeDisjunctionScorerQueue(4); q.put(this.getScorer(ntq("term2"))); q.put(this.getScorer(ntq("term3"))); q.put(this.getScorer(ntq("term4"))); q.put(this.getScorer(ntq("term5"))); // test if the heap traversal is done properly. for (int i = 0; i < 4; i++) { q.nextNodeAndAdjust(); } assertFalse(q.nextNodeAndAdjust()); } }