package org.apache.lucene.facet.taxonomy;
import java.io.IOException;
import java.util.Map;
import org.apache.lucene.facet.FacetResult;
import org.apache.lucene.facet.FacetsCollector.MatchingDocs;
import org.apache.lucene.facet.FacetsCollector;
import org.apache.lucene.facet.FacetsConfig.DimConfig;
import org.apache.lucene.facet.FacetsConfig;
import org.apache.lucene.facet.LabelAndValue;
import org.apache.lucene.facet.TopOrdAndIntQueue;
import com.carrotsearch.hppc.IntIntScatterMap;
import com.carrotsearch.hppc.cursors.IntIntCursor;
public abstract class IntTaxonomyFacets extends TaxonomyFacets {
private final int[] values;
private final IntIntScatterMap sparseValues;
protected IntTaxonomyFacets(String indexFieldName, TaxonomyReader taxoReader, FacetsConfig config, FacetsCollector fc) throws IOException {
super(indexFieldName, taxoReader, config);
if (useHashTable(fc, taxoReader)) {
sparseValues = new IntIntScatterMap();
values = null;
} else {
sparseValues = null;
values = new int[taxoReader.getSize()];
}
}
protected boolean useHashTable(FacetsCollector fc, TaxonomyReader taxoReader) {
if (taxoReader.getSize() < 1024) {
return false;
}
if (fc == null) {
return false;
}
int maxDoc = 0;
int sumTotalHits = 0;
for (MatchingDocs docs : fc.getMatchingDocs()) {
sumTotalHits += docs.totalHits;
maxDoc += docs.context.reader().maxDoc();
}
return sumTotalHits < maxDoc/10;
}
protected void increment(int ordinal) {
increment(ordinal, 1);
}
protected void increment(int ordinal, int amount) {
if (sparseValues != null) {
sparseValues.addTo(ordinal, amount);
} else {
values[ordinal] += amount;
}
}
private int getValue(int ordinal) {
if (sparseValues != null) {
return sparseValues.get(ordinal);
} else {
return values[ordinal];
}
}
protected void rollup() throws IOException {
int[] children = null;
for(Map.Entry<String,DimConfig> ent : config.getDimConfigs().entrySet()) {
String dim = ent.getKey();
DimConfig ft = ent.getValue();
if (ft.hierarchical && ft.multiValued == false) {
int dimRootOrd = taxoReader.getOrdinal(new FacetLabel(dim));
if (dimRootOrd > 0) {
if (children == null) {
children = getChildren();
}
increment(dimRootOrd, rollup(children[dimRootOrd]));
}
}
}
}
private int rollup(int ord) throws IOException {
int[] children = getChildren();
int[] siblings = getSiblings();
int sum = 0;
while (ord != TaxonomyReader.INVALID_ORDINAL) {
increment(ord, rollup(children[ord]));
sum += getValue(ord);
ord = siblings[ord];
}
return sum;
}
@Override
public Number getSpecificValue(String dim, String... path) throws IOException {
DimConfig dimConfig = verifyDim(dim);
if (path.length == 0) {
if (dimConfig.hierarchical && dimConfig.multiValued == false) {
} else if (dimConfig.requireDimCount && dimConfig.multiValued) {
} else {
throw new IllegalArgumentException("cannot return dimension-level value alone; use getTopChildren instead");
}
}
int ord = taxoReader.getOrdinal(new FacetLabel(dim, path));
if (ord < 0) {
return -1;
}
return getValue(ord);
}
@Override
public FacetResult getTopChildren(int topN, String dim, String... path) throws IOException {
if (topN <= 0) {
throw new IllegalArgumentException("topN must be > 0 (got: " + topN + ")");
}
DimConfig dimConfig = verifyDim(dim);
FacetLabel cp = new FacetLabel(dim, path);
int dimOrd = taxoReader.getOrdinal(cp);
if (dimOrd == -1) {
return null;
}
TopOrdAndIntQueue q = new TopOrdAndIntQueue(Math.min(taxoReader.getSize(), topN));
int bottomValue = 0;
int totValue = 0;
int childCount = 0;
TopOrdAndIntQueue.OrdAndValue reuse = null;
if (sparseValues != null) {
for (IntIntCursor c : sparseValues) {
int count = c.value;
int ord = c.key;
if (parents[ord] == dimOrd && count > 0) {
totValue += count;
childCount++;
if (count > bottomValue) {
if (reuse == null) {
reuse = new TopOrdAndIntQueue.OrdAndValue();
}
reuse.ord = ord;
reuse.value = count;
reuse = q.insertWithOverflow(reuse);
if (q.size() == topN) {
bottomValue = q.top().value;
}
}
}
}
} else {
int[] children = getChildren();
int[] siblings = getSiblings();
int ord = children[dimOrd];
while(ord != TaxonomyReader.INVALID_ORDINAL) {
int value = values[ord];
if (value > 0) {
totValue += value;
childCount++;
if (value > bottomValue) {
if (reuse == null) {
reuse = new TopOrdAndIntQueue.OrdAndValue();
}
reuse.ord = ord;
reuse.value = value;
reuse = q.insertWithOverflow(reuse);
if (q.size() == topN) {
bottomValue = q.top().value;
}
}
}
ord = siblings[ord];
}
}
if (totValue == 0) {
return null;
}
if (dimConfig.multiValued) {
if (dimConfig.requireDimCount) {
totValue = getValue(dimOrd);
} else {
totValue = -1;
}
} else {
}
LabelAndValue[] labelValues = new LabelAndValue[q.size()];
for(int i=labelValues.length-1;i>=0;i--) {
TopOrdAndIntQueue.OrdAndValue ordAndValue = q.pop();
FacetLabel child = taxoReader.getPath(ordAndValue.ord);
labelValues[i] = new LabelAndValue(child.components[cp.length], ordAndValue.value);
}
return new FacetResult(dim, path, totValue, labelValues, childCount);
}
}