1 package org.apache.lucene.facet.search;
3 import java.io.BufferedInputStream;
4 import java.io.BufferedOutputStream;
5 import java.io.DataInputStream;
6 import java.io.DataOutputStream;
8 import java.io.FileInputStream;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.util.HashMap;
12 import java.util.concurrent.atomic.AtomicInteger;
14 import org.apache.lucene.index.IndexReader;
15 import org.apache.lucene.store.LockObtainFailedException;
17 import org.apache.lucene.facet.index.params.CategoryListParams;
18 import org.apache.lucene.facet.index.params.FacetIndexingParams;
19 import org.apache.lucene.facet.search.aggregator.Aggregator;
20 import org.apache.lucene.facet.search.aggregator.CountingAggregator;
21 import org.apache.lucene.facet.search.cache.CategoryListCache;
22 import org.apache.lucene.facet.search.cache.CategoryListData;
23 import org.apache.lucene.facet.search.params.FacetSearchParams;
24 import org.apache.lucene.facet.taxonomy.TaxonomyReader;
25 import org.apache.lucene.facet.util.PartitionsUtils;
26 import org.apache.lucene.facet.util.ScoredDocIdsUtils;
29 * Licensed to the Apache Software Foundation (ASF) under one or more
30 * contributor license agreements. See the NOTICE file distributed with
31 * this work for additional information regarding copyright ownership.
32 * The ASF licenses this file to You under the Apache License, Version 2.0
33 * (the "License"); you may not use this file except in compliance with
34 * the License. You may obtain a copy of the License at
36 * http://www.apache.org/licenses/LICENSE-2.0
38 * Unless required by applicable law or agreed to in writing, software
39 * distributed under the License is distributed on an "AS IS" BASIS,
40 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41 * See the License for the specific language governing permissions and
42 * limitations under the License.
46 * Maintain Total Facet Counts per partition, for given parameters:
48 * <li>Index reader of an index</li>
49 * <li>Taxonomy index reader</li>
50 * <li>Facet indexing params (and particularly the category list params)</li>
53 * The total facet counts are maintained as an array of arrays of integers,
54 * where a separate array is kept for each partition.
56 * @lucene.experimental
58 public class TotalFacetCounts {
60 /** total facet counts per partition: totalCounts[partition][ordinal%partitionLength] */
61 private int[][] totalCounts = null;
63 private final TaxonomyReader taxonomy;
64 private final FacetIndexingParams facetIndexingParams;
66 private final static AtomicInteger atomicGen4Test = new AtomicInteger(1);
67 /** Creation type for test purposes */
68 enum CreationType { Computed, Loaded } // for testing
70 final CreationType createType4test;
73 * Construct by key - from index Directory or by recomputing.
74 * @param key the key mapping of this total facet counts (index, taxonomy, category lists...)
76 private TotalFacetCounts (TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams,
77 int[][] counts, CreationType createType4Test) throws IOException, LockObtainFailedException {
78 this.taxonomy = taxonomy;
79 this.facetIndexingParams = facetIndexingParams;
80 this.totalCounts = counts;
81 this.createType4test = createType4Test;
82 this.gen4test = atomicGen4Test.incrementAndGet();
86 * Fill a partition's array with the TotalCountsArray values.
87 * @param partitionArray array to fill
88 * @param partition number of required partition
90 public void fillTotalCountsForPartition(int[] partitionArray, int partition) {
91 int partitionSize = partitionArray.length;
92 int[] countArray = totalCounts[partition];
93 if (countArray == null) {
94 countArray = new int[partitionSize];
95 totalCounts[partition] = countArray;
97 int length = Math.min(partitionSize, countArray.length);
98 System.arraycopy(countArray, 0, partitionArray, 0, length);
102 * Return the total count of an input category
103 * @param ordinal ordinal of category whose total count is required
105 public int getTotalCount(int ordinal) {
106 int partition = PartitionsUtils.partitionNumber(facetIndexingParams,ordinal);
107 int offset = ordinal % PartitionsUtils.partitionSize(facetIndexingParams, taxonomy);
108 return totalCounts[partition][offset];
111 static TotalFacetCounts loadFromFile(File inputFile, TaxonomyReader taxonomy,
112 FacetIndexingParams facetIndexingParams) throws IOException {
113 DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(inputFile)));
115 int[][] counts = new int[dis.readInt()][];
116 for (int i=0; i<counts.length; i++) {
117 int size = dis.readInt();
121 counts[i] = new int[size];
122 for (int j=0; j<size; j++) {
123 counts[i][j] = dis.readInt();
127 return new TotalFacetCounts(taxonomy, facetIndexingParams, counts, CreationType.Loaded);
133 static void storeToFile(File outputFile, TotalFacetCounts tfc) throws IOException {
134 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
136 dos.writeInt(tfc.totalCounts.length);
137 for (int[] counts : tfc.totalCounts) {
138 if (counts == null) {
141 dos.writeInt(counts.length);
142 for (int i : counts) {
152 static TotalFacetCounts compute(final IndexReader indexReader,
153 final TaxonomyReader taxonomy, final FacetIndexingParams facetIndexingParams,
154 final CategoryListCache clCache) throws IOException {
155 int partitionSize = PartitionsUtils.partitionSize(facetIndexingParams, taxonomy);
156 final int[][] counts = new int[(int) Math.ceil(taxonomy.getSize() /(float) partitionSize)][partitionSize];
157 FacetSearchParams newSearchParams = new FacetSearchParams(facetIndexingParams);
158 //createAllListsSearchParams(facetIndexingParams, this.totalCounts);
159 FacetsAccumulator fe = new StandardFacetsAccumulator(newSearchParams, indexReader, taxonomy) {
161 protected HashMap<CategoryListIterator, Aggregator> getCategoryListMap(
162 FacetArrays facetArrays, int partition) throws IOException {
164 Aggregator aggregator = new CountingAggregator(counts[partition]);
165 HashMap<CategoryListIterator, Aggregator> map = new HashMap<CategoryListIterator, Aggregator>();
166 for (CategoryListParams clp: facetIndexingParams.getAllCategoryListParams()) {
167 final CategoryListIterator cli = clIteraor(clCache, clp, indexReader, partition);
168 map.put(cli, aggregator);
173 fe.setComplementThreshold(FacetsAccumulator.DISABLE_COMPLEMENT);
174 fe.accumulate(ScoredDocIdsUtils.createAllDocsScoredDocIDs(indexReader));
175 return new TotalFacetCounts(taxonomy, facetIndexingParams, counts, CreationType.Computed);
178 static CategoryListIterator clIteraor(CategoryListCache clCache, CategoryListParams clp,
179 IndexReader indexReader, int partition) throws IOException {
180 if (clCache != null) {
181 CategoryListData cld = clCache.get(clp);
183 return cld.iterator(partition);
186 return clp.createCategoryListIterator(indexReader, partition);