001: package org.apache.lucene.search.function;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import org.apache.lucene.index.CorruptIndexException;
021: import org.apache.lucene.search.Hits;
022: import org.apache.lucene.search.IndexSearcher;
023: import org.apache.lucene.search.Query;
024: import org.apache.lucene.search.QueryUtils;
025: import org.apache.lucene.search.ScoreDoc;
026: import org.apache.lucene.search.TopDocs;
027:
028: /**
029: * Test search based on OrdFieldSource and ReverseOrdFieldSource.
030: * <p>
031: * Tests here create an index with a few documents, each having
032: * an indexed "id" field.
033: * The ord values of this field are later used for scoring.
034: * <p>
035: * The order tests use Hits to verify that docs are ordered as expected.
036: * <p>
037: * The exact score tests use TopDocs top to verify the exact score.
038: */
039: public class TestOrdValues extends FunctionTestSetup {
040:
041: /* @override constructor */
042: public TestOrdValues(String name) {
043: super (name);
044: }
045:
046: /* @override */
047: protected void tearDown() throws Exception {
048: super .tearDown();
049: }
050:
051: /* @override */
052: protected void setUp() throws Exception {
053: // prepare a small index with just a few documents.
054: super .setUp();
055: }
056:
057: /** Test OrdFieldSource */
058: public void testOrdFieldRank() throws CorruptIndexException,
059: Exception {
060: doTestRank(ID_FIELD, true);
061: }
062:
063: /** Test ReverseOrdFieldSource */
064: public void testReverseOrdFieldRank() throws CorruptIndexException,
065: Exception {
066: doTestRank(ID_FIELD, false);
067: }
068:
069: // Test that queries based on reverse/ordFieldScore scores correctly
070: private void doTestRank(String field, boolean inOrder)
071: throws CorruptIndexException, Exception {
072: IndexSearcher s = new IndexSearcher(dir);
073: ValueSource vs;
074: if (inOrder) {
075: vs = new OrdFieldSource(field);
076: } else {
077: vs = new ReverseOrdFieldSource(field);
078: }
079:
080: Query q = new ValueSourceQuery(vs);
081: log("test: " + q);
082: QueryUtils.check(q, s);
083: Hits h = s.search(q);
084: assertEquals("All docs should be matched!", N_DOCS, h.length());
085: String prevID = inOrder ? "IE" // greater than all ids of docs in this test ("ID0001", etc.)
086: : "IC"; // smaller than all ids of docs in this test ("ID0001", etc.)
087:
088: for (int i = 0; i < h.length(); i++) {
089: String resID = h.doc(i).get(ID_FIELD);
090: log(i + ". score=" + h.score(i) + " - " + resID);
091: log(s.explain(q, h.id(i)));
092: if (inOrder) {
093: assertTrue("res id " + resID
094: + " should be < prev res id " + prevID, resID
095: .compareTo(prevID) < 0);
096: } else {
097: assertTrue("res id " + resID
098: + " should be > prev res id " + prevID, resID
099: .compareTo(prevID) > 0);
100: }
101: prevID = resID;
102: }
103: }
104:
105: /** Test exact score for OrdFieldSource */
106: public void testOrdFieldExactScore() throws CorruptIndexException,
107: Exception {
108: doTestExactScore(ID_FIELD, true);
109: }
110:
111: /** Test exact score for ReverseOrdFieldSource */
112: public void testReverseOrdFieldExactScore()
113: throws CorruptIndexException, Exception {
114: doTestExactScore(ID_FIELD, false);
115: }
116:
117: // Test that queries based on reverse/ordFieldScore returns docs with expected score.
118: private void doTestExactScore(String field, boolean inOrder)
119: throws CorruptIndexException, Exception {
120: IndexSearcher s = new IndexSearcher(dir);
121: ValueSource vs;
122: if (inOrder) {
123: vs = new OrdFieldSource(field);
124: } else {
125: vs = new ReverseOrdFieldSource(field);
126: }
127: Query q = new ValueSourceQuery(vs);
128: TopDocs td = s.search(q, null, 1000);
129: assertEquals("All docs should be matched!", N_DOCS,
130: td.totalHits);
131: ScoreDoc sd[] = td.scoreDocs;
132: for (int i = 0; i < sd.length; i++) {
133: float score = sd[i].score;
134: String id = s.getIndexReader().document(sd[i].doc).get(
135: ID_FIELD);
136: log("-------- " + i + ". Explain doc " + id);
137: log(s.explain(q, sd[i].doc));
138: float expectedScore = N_DOCS - i;
139: assertEquals("score of result " + i + " shuould be "
140: + expectedScore + " != " + score, expectedScore,
141: score, TEST_SCORE_TOLERANCE_DELTA);
142: String expectedId = inOrder ? id2String(N_DOCS - i) // in-order ==> larger values first
143: : id2String(i + 1); // reverse ==> smaller values first
144: assertTrue("id of result " + i + " shuould be "
145: + expectedId + " != " + score, expectedId
146: .equals(id));
147: }
148: }
149:
150: /** Test caching OrdFieldSource */
151: public void testCachingOrd() throws CorruptIndexException,
152: Exception {
153: doTestCaching(ID_FIELD, true);
154: }
155:
156: /** Test caching for ReverseOrdFieldSource */
157: public void tesCachingReverseOrd() throws CorruptIndexException,
158: Exception {
159: doTestCaching(ID_FIELD, false);
160: }
161:
162: // Test that values loaded for FieldScoreQuery are cached properly and consumes the proper RAM resources.
163: private void doTestCaching(String field, boolean inOrder)
164: throws CorruptIndexException, Exception {
165: IndexSearcher s = new IndexSearcher(dir);
166: Object innerArray = null;
167:
168: boolean warned = false; // print warning once
169:
170: for (int i = 0; i < 10; i++) {
171: ValueSource vs;
172: if (inOrder) {
173: vs = new OrdFieldSource(field);
174: } else {
175: vs = new ReverseOrdFieldSource(field);
176: }
177: ValueSourceQuery q = new ValueSourceQuery(vs);
178: Hits h = s.search(q);
179: try {
180: assertEquals("All docs should be matched!", N_DOCS, h
181: .length());
182: if (i == 0) {
183: innerArray = q.valSrc.getValues(s.getIndexReader())
184: .getInnerArray();
185: } else {
186: log(i
187: + ". compare: "
188: + innerArray
189: + " to "
190: + q.valSrc.getValues(s.getIndexReader())
191: .getInnerArray());
192: assertSame(
193: "field values should be cached and reused!",
194: innerArray, q.valSrc.getValues(
195: s.getIndexReader()).getInnerArray());
196: }
197: } catch (UnsupportedOperationException e) {
198: if (!warned) {
199: System.err.println("WARNING: " + testName()
200: + " cannot fully test values of " + q);
201: warned = true;
202: }
203: }
204: }
205:
206: ValueSource vs;
207: ValueSourceQuery q;
208: Hits h;
209:
210: // verify that different values are loaded for a different field
211: String field2 = INT_FIELD;
212: assertFalse(field.equals(field2)); // otherwise this test is meaningless.
213: if (inOrder) {
214: vs = new OrdFieldSource(field2);
215: } else {
216: vs = new ReverseOrdFieldSource(field2);
217: }
218: q = new ValueSourceQuery(vs);
219: h = s.search(q);
220: assertEquals("All docs should be matched!", N_DOCS, h.length());
221: try {
222: log("compare (should differ): "
223: + innerArray
224: + " to "
225: + q.valSrc.getValues(s.getIndexReader())
226: .getInnerArray());
227: assertNotSame(
228: "different values shuold be loaded for a different field!",
229: innerArray, q.valSrc.getValues(s.getIndexReader())
230: .getInnerArray());
231: } catch (UnsupportedOperationException e) {
232: if (!warned) {
233: System.err.println("WARNING: " + testName()
234: + " cannot fully test values of " + q);
235: warned = true;
236: }
237: }
238:
239: // verify new values are reloaded (not reused) for a new reader
240: s = new IndexSearcher(dir);
241: if (inOrder) {
242: vs = new OrdFieldSource(field);
243: } else {
244: vs = new ReverseOrdFieldSource(field);
245: }
246: q = new ValueSourceQuery(vs);
247: h = s.search(q);
248: assertEquals("All docs should be matched!", N_DOCS, h.length());
249: try {
250: log("compare (should differ): "
251: + innerArray
252: + " to "
253: + q.valSrc.getValues(s.getIndexReader())
254: .getInnerArray());
255: assertNotSame(
256: "cached field values should not be reused if reader as changed!",
257: innerArray, q.valSrc.getValues(s.getIndexReader())
258: .getInnerArray());
259: } catch (UnsupportedOperationException e) {
260: if (!warned) {
261: System.err.println("WARNING: " + testName()
262: + " cannot fully test values of " + q);
263: warned = true;
264: }
265: }
266: }
267:
268: private String testName() {
269: return getClass().getName() + "." + getName();
270: }
271:
272: }
|