package org.apache.lucene.facet.index.params; import java.io.IOException; import java.io.Serializable; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.facet.search.CategoryListIterator; import org.apache.lucene.facet.search.PayloadIntDecodingIterator; import org.apache.lucene.facet.search.TotalFacetCounts; import org.apache.lucene.facet.util.PartitionsUtils; import org.apache.lucene.util.encoding.DGapIntEncoder; import org.apache.lucene.util.encoding.IntDecoder; import org.apache.lucene.util.encoding.IntEncoder; import org.apache.lucene.util.encoding.SortingIntEncoder; import org.apache.lucene.util.encoding.UniqueValuesIntEncoder; import org.apache.lucene.util.encoding.VInt8IntEncoder; /* * 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. */ /** * Contains parameters for a category list * * * @lucene.experimental */ public class CategoryListParams implements Serializable { /** The default term used to store the facets information. */ public static final Term DEFAULT_TERM = new Term("$facets", "$fulltree$"); private final Term term; private final int hashCode; /** * Constructs a default category list parameters object, using * {@link #DEFAULT_TERM}. */ public CategoryListParams() { this(DEFAULT_TERM); } /** * Constructs a category list parameters object, using the given {@link Term}. * @param term who's payload hold the category-list. */ public CategoryListParams(Term term) { this.term = term; // Pre-compute the hashCode because these objects are immutable. Saves // some time on the comparisons later. this.hashCode = term.hashCode(); } /** * A {@link Term} who's payload holds the category-list. */ public final Term getTerm() { return term; } /** * Allows to override how categories are encoded and decoded. A matching * {@link IntDecoder} is provided by the {@link IntEncoder}. * <p> * Default implementation creates a new Sorting(<b>Unique</b>(DGap)) encoder. * Uniqueness in this regard means when the same category appears twice in a * document, only one appearance would be encoded. This has effect on facet * counting results. * <p> * Some possible considerations when overriding may be: * <ul> * <li>an application "knows" that all categories are unique. So no need to * pass through the unique filter.</li> * <li>Another application might wish to count multiple occurrences of the * same category, or, use a faster encoding which will consume more space.</li> * </ul> * In any event when changing this value make sure you know what you are * doing, and test the results - e.g. counts, if the application is about * counting facets. */ public IntEncoder createEncoder() { return new SortingIntEncoder(new UniqueValuesIntEncoder(new DGapIntEncoder(new VInt8IntEncoder()))); } /** * Equality is defined by the 'term' that defines this category list. * Sub-classes should override this method if a more complex calculation * is needed to ensure equality. */ @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof CategoryListParams)) { return false; } CategoryListParams other = (CategoryListParams) o; if (this.hashCode != other.hashCode) { return false; } // The above hashcodes might equal each other in the case of a collision, // so at this point only directly term equality testing will settle // the equality test. return this.term.equals(other.term); } /** * Hashcode is similar to {@link #equals(Object)}, in that it uses * the term that defines this category list to derive the hashcode. * Subclasses need to ensure that equality/hashcode is correctly defined, * or there could be side-effects in the {@link TotalFacetCounts} caching * mechanism (as the filename for a Total Facet Counts array cache * is dependent on the hashCode, so it should consistently return the same * hash for identity). */ @Override public int hashCode() { return this.hashCode; } /** * Create the category list iterator for the specified partition. */ public CategoryListIterator createCategoryListIterator(IndexReader reader, int partition) throws IOException { String categoryListTermStr = PartitionsUtils.partitionName(this, partition); Term payloadTerm = new Term(term.field(), categoryListTermStr); return new PayloadIntDecodingIterator(reader, payloadTerm, createEncoder().createMatchingDecoder()); } }