/*
 * 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.
 */
package org.apache.lucene.facet.taxonomy;

import static org.apache.lucene.util.ByteBlockPool.BYTE_BLOCK_SIZE;

import java.util.Arrays;

import org.apache.lucene.facet.taxonomy.writercache.LruTaxonomyWriterCache; // javadocs
import org.apache.lucene.facet.taxonomy.writercache.NameHashIntCacheLRU; // javadocs

Holds a sequence of string components, specifying the hierarchical name of a category.
@lucene.internal
/** * Holds a sequence of string components, specifying the hierarchical name of a * category. * * @lucene.internal */
public class FacetLabel implements Comparable<FacetLabel> { /* * copied from DocumentWriterPerThread -- if a FacetLabel is resolved to a * drill-down term which is encoded to a larger term than that length, it is * silently dropped! Therefore we limit the number of characters to MAX/4 to * be on the safe side. */
The maximum number of characters a FacetLabel can have.
/** * The maximum number of characters a {@link FacetLabel} can have. */
public final static int MAX_CATEGORY_PATH_LENGTH = (BYTE_BLOCK_SIZE - 2) / 4;
The components of this FacetLabel. Note that this array may be shared with other FacetLabel instances, e.g. as a result of subpath(int), therefore you should traverse the array up to length for this path's components.
/** * The components of this {@link FacetLabel}. Note that this array may be * shared with other {@link FacetLabel} instances, e.g. as a result of * {@link #subpath(int)}, therefore you should traverse the array up to * {@link #length} for this path's components. */
public final String[] components;
The number of components of this FacetLabel.
/** The number of components of this {@link FacetLabel}. */
public final int length; // Used by subpath private FacetLabel(final FacetLabel copyFrom, final int prefixLen) { // while the code which calls this method is safe, at some point a test // tripped on AIOOBE in toString, but we failed to reproduce. adding the // assert as a safety check. assert prefixLen >= 0 && prefixLen <= copyFrom.components.length : "prefixLen cannot be negative nor larger than the given components' length: prefixLen=" + prefixLen + " components.length=" + copyFrom.components.length; this.components = copyFrom.components; length = prefixLen; }
Construct from the given path components.
/** Construct from the given path components. */
public FacetLabel(final String... components) { this.components = components; length = components.length; checkComponents(); }
Construct from the dimension plus the given path components.
/** Construct from the dimension plus the given path components. */
public FacetLabel(String dim, String[] path) { components = new String[1+path.length]; components[0] = dim; System.arraycopy(path, 0, components, 1, path.length); length = components.length; checkComponents(); } private void checkComponents() { long len = 0; for (String comp : components) { if (comp == null || comp.isEmpty()) { throw new IllegalArgumentException("empty or null components not allowed: " + Arrays.toString(components)); } len += comp.length(); } len += components.length - 1; // add separators if (len > MAX_CATEGORY_PATH_LENGTH) { throw new IllegalArgumentException("category path exceeds maximum allowed path length: max=" + MAX_CATEGORY_PATH_LENGTH + " len=" + len + " path=" + Arrays.toString(components).substring(0, 30) + "..."); } }
Compares this path with another FacetLabel for lexicographic order.
/** * Compares this path with another {@link FacetLabel} for lexicographic * order. */
@Override public int compareTo(FacetLabel other) { final int len = length < other.length ? length : other.length; for (int i = 0, j = 0; i < len; i++, j++) { int cmp = components[i].compareTo(other.components[j]); if (cmp < 0) { return -1; // this is 'before' } if (cmp > 0) { return 1; // this is 'after' } } // one is a prefix of the other return length - other.length; } @Override public boolean equals(Object obj) { if (!(obj instanceof FacetLabel)) { return false; } FacetLabel other = (FacetLabel) obj; if (length != other.length) { return false; // not same length, cannot be equal } // CategoryPaths are more likely to differ at the last components, so start // from last-first for (int i = length - 1; i >= 0; i--) { if (!components[i].equals(other.components[i])) { return false; } } return true; } @Override public int hashCode() { if (length == 0) { return 0; } int hash = length; for (int i = 0; i < length; i++) { hash = hash * 31 + components[i].hashCode(); } return hash; }
Calculate a 64-bit hash function for this path. This is necessary for NameHashIntCacheLRU (the default cache impl for LruTaxonomyWriterCache) to reduce the chance of "silent but deadly" collisions.
/** Calculate a 64-bit hash function for this path. This * is necessary for {@link NameHashIntCacheLRU} (the * default cache impl for {@link * LruTaxonomyWriterCache}) to reduce the chance of * "silent but deadly" collisions. */
public long longHashCode() { if (length == 0) { return 0; } long hash = length; for (int i = 0; i < length; i++) { hash = hash * 65599 + components[i].hashCode(); } return hash; }
Returns a sub-path of this path up to length components.
/** Returns a sub-path of this path up to {@code length} components. */
public FacetLabel subpath(final int length) { if (length >= this.length || length < 0) { return this; } else { return new FacetLabel(this, length); } }
Returns a string representation of the path.
/** * Returns a string representation of the path. */
@Override public String toString() { if (length == 0) { return "FacetLabel: []"; } String[] parts = new String[length]; System.arraycopy(components, 0, parts, 0, length); return "FacetLabel: " + Arrays.toString(parts); } }