1 package org.apache.lucene.facet.search;
3 import java.io.IOException;
4 import java.util.Iterator;
7 import org.apache.lucene.analysis.MockAnalyzer;
8 import org.apache.lucene.analysis.MockTokenizer;
9 import org.apache.lucene.index.CorruptIndexException;
10 import org.apache.lucene.index.IndexReader;
11 import org.apache.lucene.index.IndexWriterConfig;
12 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
13 import org.apache.lucene.index.RandomIndexWriter;
14 import org.apache.lucene.index.Term;
15 import org.apache.lucene.index.TermDocs;
16 import org.apache.lucene.search.IndexSearcher;
17 import org.apache.lucene.search.MatchAllDocsQuery;
18 import org.apache.lucene.search.Query;
19 import org.apache.lucene.search.TopScoreDocCollector;
20 import org.apache.lucene.store.Directory;
21 import org.junit.Test;
23 import org.apache.lucene.util.IOUtils;
24 import org.apache.lucene.util.LuceneTestCase;
25 import org.apache.lucene.search.MultiCollector;
26 import org.apache.lucene.facet.FacetTestUtils;
27 import org.apache.lucene.facet.index.params.CategoryListParams;
28 import org.apache.lucene.facet.index.params.FacetIndexingParams;
29 import org.apache.lucene.facet.index.params.PerDimensionIndexingParams;
30 import org.apache.lucene.facet.search.FacetsCollector;
31 import org.apache.lucene.facet.search.params.CountFacetRequest;
32 import org.apache.lucene.facet.search.params.FacetSearchParams;
33 import org.apache.lucene.facet.search.results.FacetResult;
34 import org.apache.lucene.facet.search.results.FacetResultNode;
35 import org.apache.lucene.facet.taxonomy.CategoryPath;
36 import org.apache.lucene.facet.taxonomy.TaxonomyReader;
37 import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
38 import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
39 import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
42 * Licensed to the Apache Software Foundation (ASF) under one or more
43 * contributor license agreements. See the NOTICE file distributed with
44 * this work for additional information regarding copyright ownership.
45 * The ASF licenses this file to You under the Apache License, Version 2.0
46 * (the "License"); you may not use this file except in compliance with
47 * the License. You may obtain a copy of the License at
49 * http://www.apache.org/licenses/LICENSE-2.0
51 * Unless required by applicable law or agreed to in writing, software
52 * distributed under the License is distributed on an "AS IS" BASIS,
53 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
54 * See the License for the specific language governing permissions and
55 * limitations under the License.
58 public class TestMultipleCategoryLists extends LuceneTestCase {
61 public void testDefault() throws Exception {
62 Directory[][] dirs = getDirs();
63 // create and open an index writer
64 RandomIndexWriter iw = new RandomIndexWriter(random, dirs[0][0], newIndexWriterConfig(
65 TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.WHITESPACE, false)));
66 // create and open a taxonomy writer
67 TaxonomyWriter tw = new DirectoryTaxonomyWriter(dirs[0][1], OpenMode.CREATE);
70 * Configure with no custom counting lists
72 PerDimensionIndexingParams iParams = new PerDimensionIndexingParams();
74 seedIndex(iw, tw, iParams);
76 IndexReader ir = iw.getReader();
79 // prepare index reader and taxonomy.
80 TaxonomyReader tr = new DirectoryTaxonomyReader(dirs[0][1]);
82 // prepare searcher to search against
83 IndexSearcher searcher = newSearcher(ir);
85 FacetsCollector facetsCollector = performSearch(iParams, tr, ir,
88 // Obtain facets results and hand-test them
89 assertCorrectResults(facetsCollector);
91 TermDocs td = ir.termDocs(new Term("$facets", "$fulltree$"));
92 assertTrue(td.next());
99 IOUtils.close(dirs[0]);
103 public void testCustom() throws Exception {
104 Directory[][] dirs = getDirs();
105 // create and open an index writer
106 RandomIndexWriter iw = new RandomIndexWriter(random, dirs[0][0], newIndexWriterConfig(
107 TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.WHITESPACE, false)));
108 // create and open a taxonomy writer
109 TaxonomyWriter tw = new DirectoryTaxonomyWriter(dirs[0][1],
112 PerDimensionIndexingParams iParams = new PerDimensionIndexingParams();
113 iParams.addCategoryListParams(new CategoryPath("Author"),
114 new CategoryListParams(new Term("$author", "Authors")));
115 seedIndex(iw, tw, iParams);
117 IndexReader ir = iw.getReader();
120 // prepare index reader and taxonomy.
121 TaxonomyReader tr = new DirectoryTaxonomyReader(dirs[0][1]);
123 // prepare searcher to search against
124 IndexSearcher searcher = newSearcher(ir);
126 FacetsCollector facetsCollector = performSearch(iParams, tr, ir,
129 // Obtain facets results and hand-test them
130 assertCorrectResults(facetsCollector);
132 assertPostingListExists("$facets", "$fulltree$", ir);
133 assertPostingListExists("$author", "Authors", ir);
140 IOUtils.close(dirs[0]);
144 public void testTwoCustomsSameField() throws Exception {
145 Directory[][] dirs = getDirs();
146 // create and open an index writer
147 RandomIndexWriter iw = new RandomIndexWriter(random, dirs[0][0], newIndexWriterConfig(
148 TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.WHITESPACE, false)));
149 // create and open a taxonomy writer
150 TaxonomyWriter tw = new DirectoryTaxonomyWriter(dirs[0][1],
153 PerDimensionIndexingParams iParams = new PerDimensionIndexingParams();
154 iParams.addCategoryListParams(new CategoryPath("Band"),
155 new CategoryListParams(new Term("$music", "Bands")));
156 iParams.addCategoryListParams(new CategoryPath("Composer"),
157 new CategoryListParams(new Term("$music", "Composers")));
158 seedIndex(iw, tw, iParams);
160 IndexReader ir = iw.getReader();
163 // prepare index reader and taxonomy.
164 TaxonomyReader tr = new DirectoryTaxonomyReader(dirs[0][1]);
166 // prepare searcher to search against
167 IndexSearcher searcher = newSearcher(ir);
169 FacetsCollector facetsCollector = performSearch(iParams, tr, ir,
172 // Obtain facets results and hand-test them
173 assertCorrectResults(facetsCollector);
175 assertPostingListExists("$facets", "$fulltree$", ir);
176 assertPostingListExists("$music", "Bands", ir);
177 assertPostingListExists("$music", "Composers", ir);
184 IOUtils.close(dirs[0]);
187 private void assertPostingListExists(String field, String text, IndexReader ir) throws IOException {
189 Term term = new Term(field, text);
190 td = ir.termDocs(term);
191 assertTrue(td.next());
195 public void testDifferentFieldsAndText() throws Exception {
196 Directory[][] dirs = getDirs();
197 // create and open an index writer
198 RandomIndexWriter iw = new RandomIndexWriter(random, dirs[0][0], newIndexWriterConfig(
199 TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.WHITESPACE, false)));
200 // create and open a taxonomy writer
201 TaxonomyWriter tw = new DirectoryTaxonomyWriter(dirs[0][1], OpenMode.CREATE);
203 PerDimensionIndexingParams iParams = new PerDimensionIndexingParams();
204 iParams.addCategoryListParams(new CategoryPath("Band"),
205 new CategoryListParams(new Term("$bands", "Bands")));
206 iParams.addCategoryListParams(new CategoryPath("Composer"),
207 new CategoryListParams(new Term("$composers", "Composers")));
208 seedIndex(iw, tw, iParams);
210 IndexReader ir = iw.getReader();
213 // prepare index reader and taxonomy.
214 TaxonomyReader tr = new DirectoryTaxonomyReader(dirs[0][1]);
216 // prepare searcher to search against
217 IndexSearcher searcher = newSearcher(ir);
219 FacetsCollector facetsCollector = performSearch(iParams, tr, ir,
222 // Obtain facets results and hand-test them
223 assertCorrectResults(facetsCollector);
224 assertPostingListExists("$facets", "$fulltree$", ir);
225 assertPostingListExists("$bands", "Bands", ir);
226 assertPostingListExists("$composers", "Composers", ir);
232 IOUtils.close(dirs[0]);
236 public void testSomeSameSomeDifferent() throws Exception {
237 Directory[][] dirs = getDirs();
238 // create and open an index writer
239 RandomIndexWriter iw = new RandomIndexWriter(random, dirs[0][0], newIndexWriterConfig(
240 TEST_VERSION_CURRENT, new MockAnalyzer(random, MockTokenizer.WHITESPACE, false)));
241 // create and open a taxonomy writer
242 TaxonomyWriter tw = new DirectoryTaxonomyWriter(dirs[0][1],
245 PerDimensionIndexingParams iParams = new PerDimensionIndexingParams();
246 iParams.addCategoryListParams(new CategoryPath("Band"),
247 new CategoryListParams(new Term("$music", "music")));
248 iParams.addCategoryListParams(new CategoryPath("Composer"),
249 new CategoryListParams(new Term("$music", "music")));
250 iParams.addCategoryListParams(new CategoryPath("Author"),
251 new CategoryListParams(new Term("$literature", "Authors")));
253 seedIndex(iw, tw, iParams);
255 IndexReader ir = iw.getReader();
258 // prepare index reader and taxonomy.
259 TaxonomyReader tr = new DirectoryTaxonomyReader(dirs[0][1]);
261 // prepare searcher to search against
262 IndexSearcher searcher = newSearcher(ir);
264 FacetsCollector facetsCollector = performSearch(iParams, tr, ir,
267 // Obtain facets results and hand-test them
268 assertCorrectResults(facetsCollector);
269 assertPostingListExists("$music", "music", ir);
270 assertPostingListExists("$literature", "Authors", ir);
277 IOUtils.close(dirs[0]);
280 private Directory[][] getDirs() throws IOException {
281 return FacetTestUtils.createIndexTaxonomyDirs(1);
284 private void assertCorrectResults(FacetsCollector facetsCollector)
285 throws IOException, IllegalAccessException, InstantiationException {
286 List<FacetResult> res = facetsCollector.getFacetResults();
288 FacetResult results = res.get(0);
289 FacetResultNode resNode = results.getFacetResultNode();
290 Iterable<? extends FacetResultNode> subResults = resNode
292 Iterator<? extends FacetResultNode> subIter = subResults.iterator();
294 checkResult(resNode, "Band", 5.0);
295 checkResult(subIter.next(), "Band/Rock & Pop", 4.0);
296 checkResult(subIter.next(), "Band/Punk", 1.0);
298 results = res.get(1);
299 resNode = results.getFacetResultNode();
300 subResults = resNode.getSubResults();
301 subIter = subResults.iterator();
303 checkResult(resNode, "Band", 5.0);
304 checkResult(subIter.next(), "Band/Rock & Pop", 4.0);
305 checkResult(subIter.next(), "Band/Rock & Pop/Dave Matthews Band", 1.0);
306 checkResult(subIter.next(), "Band/Rock & Pop/REM", 1.0);
307 checkResult(subIter.next(), "Band/Rock & Pop/U2", 1.0);
308 checkResult(subIter.next(), "Band/Punk/The Ramones", 1.0);
309 checkResult(subIter.next(), "Band/Punk", 1.0);
310 checkResult(subIter.next(), "Band/Rock & Pop/The Beatles", 1.0);
312 results = res.get(2);
313 resNode = results.getFacetResultNode();
314 subResults = resNode.getSubResults();
315 subIter = subResults.iterator();
317 checkResult(resNode, "Author", 3.0);
318 checkResult(subIter.next(), "Author/Kurt Vonnegut", 1.0);
319 checkResult(subIter.next(), "Author/Stephen King", 1.0);
320 checkResult(subIter.next(), "Author/Mark Twain", 1.0);
322 results = res.get(3);
323 resNode = results.getFacetResultNode();
324 subResults = resNode.getSubResults();
325 subIter = subResults.iterator();
327 checkResult(resNode, "Band/Rock & Pop", 4.0);
328 checkResult(subIter.next(), "Band/Rock & Pop/Dave Matthews Band", 1.0);
329 checkResult(subIter.next(), "Band/Rock & Pop/REM", 1.0);
330 checkResult(subIter.next(), "Band/Rock & Pop/U2", 1.0);
331 checkResult(subIter.next(), "Band/Rock & Pop/The Beatles", 1.0);
334 private FacetsCollector performSearch(FacetIndexingParams iParams,
335 TaxonomyReader tr, IndexReader ir,
336 IndexSearcher searcher) throws IOException {
337 // step 1: collect matching documents into a collector
338 Query q = new MatchAllDocsQuery();
339 TopScoreDocCollector topDocsCollector = TopScoreDocCollector.create(10,
342 // Faceted search parameters indicate which facets are we interested in
343 FacetSearchParams facetSearchParams = new FacetSearchParams(iParams);
345 facetSearchParams.addFacetRequest(new CountFacetRequest(
346 new CategoryPath("Band"), 10));
347 CountFacetRequest bandDepth = new CountFacetRequest(new CategoryPath(
349 bandDepth.setDepth(2);
350 facetSearchParams.addFacetRequest(bandDepth);
351 facetSearchParams.addFacetRequest(new CountFacetRequest(
352 new CategoryPath("Author"), 10));
353 facetSearchParams.addFacetRequest(new CountFacetRequest(
354 new CategoryPath("Band", "Rock & Pop"), 10));
356 // perform documents search and facets accumulation
357 FacetsCollector facetsCollector = new FacetsCollector(facetSearchParams, ir, tr);
358 searcher.search(q, MultiCollector.wrap(topDocsCollector, facetsCollector));
359 return facetsCollector;
362 private void seedIndex(RandomIndexWriter iw, TaxonomyWriter tw,
363 FacetIndexingParams iParams) throws IOException, CorruptIndexException {
364 FacetTestUtils.add(iParams, iw, tw, "Author", "Mark Twain");
365 FacetTestUtils.add(iParams, iw, tw, "Author", "Stephen King");
366 FacetTestUtils.add(iParams, iw, tw, "Author", "Kurt Vonnegut");
367 FacetTestUtils.add(iParams, iw, tw, "Band", "Rock & Pop",
369 FacetTestUtils.add(iParams, iw, tw, "Band", "Punk", "The Ramones");
370 FacetTestUtils.add(iParams, iw, tw, "Band", "Rock & Pop", "U2");
371 FacetTestUtils.add(iParams, iw, tw, "Band", "Rock & Pop", "REM");
372 FacetTestUtils.add(iParams, iw, tw, "Band", "Rock & Pop",
373 "Dave Matthews Band");
374 FacetTestUtils.add(iParams, iw, tw, "Composer", "Bach");
377 private static void checkResult(FacetResultNode sub, String label, double value) {
378 assertEquals("Label of subresult " + sub.getLabel() + " was incorrect",
379 label, sub.getLabel().toString());
381 "Value for " + sub.getLabel() + " subresult was incorrect",
382 value, sub.getValue(), 0.0);