mirror of https://github.com/apache/lucene.git
LUCENE-4697: make FacetResultNode a simple bin
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1436277 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c1272c83bc
commit
d77d05d44d
|
@ -29,6 +29,9 @@ Changes in backwards compatibility policy
|
|||
support in-memory caching, CategoryListCache was removed too.
|
||||
(Shai Erera, Michael McCandless)
|
||||
|
||||
* LUCENE-4697: FacetResultNode is now a concrete class with public members
|
||||
(instead of getter methods). (Shai Erera)
|
||||
|
||||
Optimizations
|
||||
|
||||
* LUCENE-4687: BloomFilterPostingsFormat now lazily initializes delegate
|
||||
|
|
|
@ -148,9 +148,9 @@ public class SimpleSearcher {
|
|||
|
||||
// assume the user is interested in the second sub-result
|
||||
// (just take the second sub-result returned by the iterator - we know there are 3 results!)
|
||||
Iterator<? extends FacetResultNode> resIterator = fres.getFacetResultNode().getSubResults().iterator();
|
||||
Iterator<? extends FacetResultNode> resIterator = fres.getFacetResultNode().subResults.iterator();
|
||||
resIterator.next(); // skip first result
|
||||
CategoryPath categoryOfInterest = resIterator.next().getLabel();
|
||||
CategoryPath categoryOfInterest = resIterator.next().label;
|
||||
|
||||
// drill-down preparation: turn the base query into a drill-down query for the category of interest
|
||||
Query q2 = DrillDown.query(indexingParams, baseQuery, categoryOfInterest);
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.apache.lucene.index.IndexReader;
|
|||
* <p>
|
||||
* Note: Sampling accumulation (Accumulation over a sampled-set of the results),
|
||||
* does not guarantee accurate values for
|
||||
* {@link FacetResult#getNumValidDescendants()} &
|
||||
* {@link FacetResultNode#getResidue()}.
|
||||
* {@link FacetResult#getNumValidDescendants()} and
|
||||
* {@link FacetResultNode#residue}.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
|
|
|
@ -120,7 +120,7 @@ public abstract class FacetResultsHandler {
|
|||
* rendered facet results, fixed their counts, and now it is needed
|
||||
* to sort the results differently according to the fixed counts.
|
||||
* @param facetResult result to be rearranged.
|
||||
* @see FacetResultNode#setValue(double)
|
||||
* @see FacetResultNode#value
|
||||
*/
|
||||
public abstract FacetResult rearrangeFacetResult(FacetResult facetResult);
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ import org.apache.lucene.facet.search.sampling.Sampler.SampleResult;
|
|||
* <p>
|
||||
* Note: Sampling accumulation (Accumulation over a sampled-set of the results),
|
||||
* does not guarantee accurate values for
|
||||
* {@link FacetResult#getNumValidDescendants()} &
|
||||
* {@link FacetResultNode#getResidue()}.
|
||||
* {@link FacetResult#getNumValidDescendants()} and
|
||||
* {@link FacetResultNode#residue}.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,6 @@ import org.apache.lucene.facet.search.params.FacetRequest;
|
|||
import org.apache.lucene.facet.search.results.FacetResult;
|
||||
import org.apache.lucene.facet.search.results.FacetResultNode;
|
||||
import org.apache.lucene.facet.search.results.IntermediateFacetResult;
|
||||
import org.apache.lucene.facet.search.results.MutableFacetResultNode;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
import org.apache.lucene.facet.taxonomy.directory.ParallelTaxonomyArrays;
|
||||
import org.apache.lucene.facet.util.ResultSortUtils;
|
||||
|
@ -64,8 +63,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
}
|
||||
|
||||
// TODO (Facet): should initial value of "residue" depend on aggregator if not sum?
|
||||
MutableFacetResultNode parentResultNode =
|
||||
new MutableFacetResultNode(ordinal, value);
|
||||
FacetResultNode parentResultNode = new FacetResultNode(ordinal, value);
|
||||
|
||||
Heap<FacetResultNode> heap = ResultSortUtils.createSuitableHeap(facetRequest);
|
||||
int totalFacets = heapDescendants(ordinal, heap, parentResultNode, facetArrays, offset);
|
||||
|
@ -80,7 +78,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
public IntermediateFacetResult mergeResults(IntermediateFacetResult... tmpResults) throws IOException {
|
||||
|
||||
int ordinal = taxonomyReader.getOrdinal(facetRequest.categoryPath);
|
||||
MutableFacetResultNode resNode = new MutableFacetResultNode(ordinal, 0);
|
||||
FacetResultNode resNode = new FacetResultNode(ordinal, 0);
|
||||
|
||||
int totalFacets = 0;
|
||||
Heap<FacetResultNode> heap = null;
|
||||
|
@ -91,7 +89,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
TopKFacetResult fres = (TopKFacetResult) tmpFres;
|
||||
totalFacets += fres.getNumValidDescendants();
|
||||
// set the value for the result node representing the facet request
|
||||
resNode.increaseValue(fres.getFacetResultNode().getValue());
|
||||
resNode.value += fres.getFacetResultNode().value;
|
||||
Heap<FacetResultNode> tmpHeap = fres.getHeap();
|
||||
if (heap == null) {
|
||||
heap = tmpHeap;
|
||||
|
@ -102,7 +100,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
|
||||
FacetResultNode a = heap.insertWithOverflow(tmpHeap.pop());
|
||||
if (a != null) {
|
||||
resNode.increaseResidue(a.getResidue());
|
||||
resNode.residue += a.residue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,8 +117,8 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
* they join the overall priority queue pq of size K.
|
||||
* @return total number of descendants considered here by pq, excluding ordinal itself.
|
||||
*/
|
||||
private int heapDescendants(int ordinal, Heap<FacetResultNode> pq,
|
||||
MutableFacetResultNode parentResultNode, FacetArrays facetArrays, int offset) throws IOException {
|
||||
private int heapDescendants(int ordinal, Heap<FacetResultNode> pq, FacetResultNode parentResultNode,
|
||||
FacetArrays facetArrays, int offset) throws IOException {
|
||||
int partitionSize = facetArrays.arrayLength;
|
||||
int endOffset = offset + partitionSize;
|
||||
ParallelTaxonomyArrays childrenArray = taxonomyReader.getParallelTaxonomyArrays();
|
||||
|
@ -172,16 +170,20 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
if (value != 0 && !Double.isNaN(value)) {
|
||||
// Count current ordinal -- the TOS
|
||||
if (reusable == null) {
|
||||
reusable = new MutableFacetResultNode(tosOrdinal, value);
|
||||
reusable = new FacetResultNode(tosOrdinal, value);
|
||||
} else {
|
||||
// it is safe to cast since reusable was created here.
|
||||
((MutableFacetResultNode)reusable).reset(tosOrdinal, value);
|
||||
reusable.ordinal = tosOrdinal;
|
||||
reusable.value = value;
|
||||
reusable.subResults.clear();
|
||||
reusable.label = null;
|
||||
reusable.residue = 0;
|
||||
}
|
||||
++childrenCounter;
|
||||
reusable = pq.insertWithOverflow(reusable);
|
||||
if (reusable != null) {
|
||||
// TODO (Facet): is other logic (not add) needed, per aggregator?
|
||||
parentResultNode.increaseResidue(reusable.getValue());
|
||||
parentResultNode.residue += reusable.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,9 +207,12 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
TopKFacetResult res = (TopKFacetResult) tmpResult; // cast is safe by contract of this class
|
||||
if (res != null) {
|
||||
Heap<FacetResultNode> heap = res.getHeap();
|
||||
MutableFacetResultNode resNode = (MutableFacetResultNode)res.getFacetResultNode(); // cast safe too
|
||||
FacetResultNode resNode = res.getFacetResultNode();
|
||||
if (resNode.subResults == FacetResultNode.EMPTY_SUB_RESULTS) {
|
||||
resNode.subResults = new ArrayList<FacetResultNode>();
|
||||
}
|
||||
for (int i = heap.size(); i > 0; i--) {
|
||||
resNode.insertSubResult(heap.pop());
|
||||
resNode.subResults.add(0, heap.pop());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
@ -218,8 +223,8 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
TopKFacetResult res = (TopKFacetResult) facetResult; // cast is safe by contract of this class
|
||||
Heap<FacetResultNode> heap = res.getHeap();
|
||||
heap.clear(); // just to be safe
|
||||
MutableFacetResultNode topFrn = (MutableFacetResultNode) res.getFacetResultNode(); // safe cast
|
||||
for (FacetResultNode frn : topFrn.getSubResults()) {
|
||||
FacetResultNode topFrn = res.getFacetResultNode();
|
||||
for (FacetResultNode frn : topFrn.subResults) {
|
||||
heap.add(frn);
|
||||
}
|
||||
int size = heap.size();
|
||||
|
@ -227,23 +232,22 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
for (int i = heap.size(); i > 0; i--) {
|
||||
subResults.add(0,heap.pop());
|
||||
}
|
||||
topFrn.setSubResults(subResults);
|
||||
topFrn.subResults = subResults;
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
// label top K sub results
|
||||
public void labelResult(FacetResult facetResult) throws IOException {
|
||||
if (facetResult != null) { // any result to label?
|
||||
FacetResultNode facetResultNode = facetResult.getFacetResultNode();
|
||||
if (facetResultNode != null) { // any result to label?
|
||||
facetResultNode.getLabel(taxonomyReader);
|
||||
facetResultNode.label = taxonomyReader.getPath(facetResultNode.ordinal);
|
||||
int num2label = facetRequest.getNumLabel();
|
||||
for (FacetResultNode frn : facetResultNode.getSubResults()) {
|
||||
for (FacetResultNode frn : facetResultNode.subResults) {
|
||||
if (--num2label < 0) {
|
||||
break;
|
||||
}
|
||||
frn.getLabel(taxonomyReader);
|
||||
frn.label = taxonomyReader.getPath(frn.ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +271,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
|
|||
* @param facetResultNode top result node for this facet result.
|
||||
* @param totalFacets - number of children of the targetFacet, up till the requested depth.
|
||||
*/
|
||||
TopKFacetResult(FacetRequest facetRequest, MutableFacetResultNode facetResultNode, int totalFacets) {
|
||||
TopKFacetResult(FacetRequest facetRequest, FacetResultNode facetResultNode, int totalFacets) {
|
||||
super(facetRequest, facetResultNode, totalFacets);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.apache.lucene.facet.search.params.FacetRequest.SortOrder;
|
|||
import org.apache.lucene.facet.search.results.FacetResult;
|
||||
import org.apache.lucene.facet.search.results.FacetResultNode;
|
||||
import org.apache.lucene.facet.search.results.IntermediateFacetResult;
|
||||
import org.apache.lucene.facet.search.results.MutableFacetResultNode;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
import org.apache.lucene.facet.taxonomy.directory.ParallelTaxonomyArrays;
|
||||
import org.apache.lucene.util.PriorityQueue;
|
||||
|
@ -39,7 +38,7 @@ import org.apache.lucene.util.collections.IntToObjectMap;
|
|||
* subtree of the taxonomy tree. Its root node,
|
||||
* {@link FacetResult#getFacetResultNode()}, is the facet specified by
|
||||
* {@link FacetRequest#categoryPath}, and the enumerated children,
|
||||
* {@link FacetResultNode#getSubResults()}, of each node in that
|
||||
* {@link FacetResultNode#subResults}, of each node in that
|
||||
* {@link FacetResult} are the top K ( = {@link FacetRequest#getNumResults()})
|
||||
* among its children in the taxonomy. Top in the sense
|
||||
* {@link FacetRequest#getSortBy()}, which can be by the values aggregated in
|
||||
|
@ -70,8 +69,7 @@ import org.apache.lucene.util.collections.IntToObjectMap;
|
|||
*/
|
||||
public class TopKInEachNodeHandler extends FacetResultsHandler {
|
||||
|
||||
public TopKInEachNodeHandler(TaxonomyReader taxonomyReader,
|
||||
FacetRequest facetRequest) {
|
||||
public TopKInEachNodeHandler(TaxonomyReader taxonomyReader, FacetRequest facetRequest) {
|
||||
super(taxonomyReader, facetRequest);
|
||||
}
|
||||
|
||||
|
@ -546,7 +544,7 @@ public class TopKInEachNodeHandler extends FacetResultsHandler {
|
|||
|
||||
@Override
|
||||
protected boolean lessThan(FacetResultNode arg1, FacetResultNode arg2) {
|
||||
return merger.leftGoesNow(arg2.getOrdinal(), arg2.getValue(), arg1.getOrdinal(), arg1.getValue());
|
||||
return merger.leftGoesNow(arg2.ordinal, arg2.value, arg1.ordinal, arg1.value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -718,14 +716,11 @@ public class TopKInEachNodeHandler extends FacetResultsHandler {
|
|||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
node.getLabel(this.taxonomyReader); // attach a label -- category path -- to the node
|
||||
if (null == node.getSubResults()) {
|
||||
return; // if node has no children -- done
|
||||
}
|
||||
node.label = taxonomyReader.getPath(node.ordinal);
|
||||
|
||||
// otherwise, label the first numToLabel of these children, and recursively -- their children.
|
||||
// label the first numToLabel of these children, and recursively -- their children.
|
||||
int numLabeled = 0;
|
||||
for (FacetResultNode frn : node.getSubResults()) {
|
||||
for (FacetResultNode frn : node.subResults) {
|
||||
// go over the children of node from first to last, no more than numToLable of them
|
||||
recursivelyLabel(frn, numToLabel);
|
||||
if (++numLabeled >= numToLabel) {
|
||||
|
@ -743,24 +738,23 @@ public class TopKInEachNodeHandler extends FacetResultsHandler {
|
|||
public FacetResult rearrangeFacetResult(FacetResult facetResult) {
|
||||
PriorityQueue<FacetResultNode> nodesHeap =
|
||||
new ResultNodeHeap(this.facetRequest.getNumResults(), this.getSuitableACComparator());
|
||||
MutableFacetResultNode topFrn = (MutableFacetResultNode) facetResult.getFacetResultNode(); // safe cast
|
||||
FacetResultNode topFrn = facetResult.getFacetResultNode();
|
||||
rearrangeChilrenOfNode(topFrn, nodesHeap);
|
||||
return facetResult;
|
||||
}
|
||||
|
||||
private void rearrangeChilrenOfNode(FacetResultNode node,
|
||||
PriorityQueue<FacetResultNode> nodesHeap) {
|
||||
private void rearrangeChilrenOfNode(FacetResultNode node, PriorityQueue<FacetResultNode> nodesHeap) {
|
||||
nodesHeap.clear(); // just to be safe
|
||||
for (FacetResultNode frn : node.getSubResults()) {
|
||||
for (FacetResultNode frn : node.subResults) {
|
||||
nodesHeap.add(frn);
|
||||
}
|
||||
int size = nodesHeap.size();
|
||||
ArrayList<FacetResultNode> subResults = new ArrayList<FacetResultNode>(size);
|
||||
while (nodesHeap.size()>0) {
|
||||
subResults.add(0,nodesHeap.pop());
|
||||
while (nodesHeap.size() > 0) {
|
||||
subResults.add(0, nodesHeap.pop());
|
||||
}
|
||||
((MutableFacetResultNode)node).setSubResults(subResults);
|
||||
for (FacetResultNode frn : node.getSubResults()) {
|
||||
node.subResults = subResults;
|
||||
for (FacetResultNode frn : node.subResults) {
|
||||
rearrangeChilrenOfNode(frn, nodesHeap);
|
||||
}
|
||||
|
||||
|
@ -777,13 +771,13 @@ public class TopKInEachNodeHandler extends FacetResultsHandler {
|
|||
if (tmp.isRootNodeIncluded) {
|
||||
value = tmp.rootNodeValue;
|
||||
}
|
||||
MutableFacetResultNode root = generateNode (ordinal, value, tmp.mapToAACOs);
|
||||
FacetResultNode root = generateNode(ordinal, value, tmp.mapToAACOs);
|
||||
return new FacetResult (tmp.facetRequest, root, tmp.totalNumOfFacetsConsidered);
|
||||
|
||||
}
|
||||
|
||||
private MutableFacetResultNode generateNode (int ordinal, double val, IntToObjectMap<AACO> mapToAACOs) {
|
||||
MutableFacetResultNode node = new MutableFacetResultNode(ordinal, val);
|
||||
private FacetResultNode generateNode(int ordinal, double val, IntToObjectMap<AACO> mapToAACOs) {
|
||||
FacetResultNode node = new FacetResultNode(ordinal, val);
|
||||
AACO aaco = mapToAACOs.get(ordinal);
|
||||
if (null == aaco) {
|
||||
return node;
|
||||
|
@ -792,8 +786,8 @@ public class TopKInEachNodeHandler extends FacetResultsHandler {
|
|||
for (int i = 0; i < aaco.ordinals.length; i++) {
|
||||
list.add(generateNode(aaco.ordinals[i], aaco.values[i], mapToAACOs));
|
||||
}
|
||||
node.setSubResults(list);
|
||||
node.setResidue(aaco.residue);
|
||||
node.subResults = list;
|
||||
node.residue = aaco.residue;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package org.apache.lucene.facet.search.results;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.facet.search.FacetResultsHandler;
|
||||
import org.apache.lucene.facet.search.params.CountFacetRequest;
|
||||
import org.apache.lucene.facet.search.params.FacetRequest;
|
||||
import org.apache.lucene.facet.search.sampling.SampleFixer;
|
||||
import org.apache.lucene.facet.search.params.FacetRequest.ResultMode;
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
|
||||
|
@ -26,85 +27,86 @@ import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
|||
*/
|
||||
|
||||
/**
|
||||
* Result of faceted search for a certain taxonomy node.
|
||||
* Result of faceted search for a certain taxonomy node. This class serves as a
|
||||
* bin of different attributes of the result node, such as its {@link #ordinal}
|
||||
* as well as {@link #label}. You are not expected to modify those values.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public interface FacetResultNode {
|
||||
public class FacetResultNode {
|
||||
|
||||
public static final List<FacetResultNode> EMPTY_SUB_RESULTS = Collections.emptyList();
|
||||
|
||||
/** The category ordinal of this node. */
|
||||
public int ordinal;
|
||||
|
||||
/**
|
||||
* String representation of this facet result node.
|
||||
* Use with caution: might return a very long string.
|
||||
* @param prefix prefix for each result line
|
||||
*/
|
||||
public String toString(String prefix);
|
||||
|
||||
/**
|
||||
* Ordinal of the category of this result.
|
||||
*/
|
||||
public int getOrdinal();
|
||||
|
||||
/**
|
||||
* Category path of the category of this result, or null if not computed,
|
||||
* because the application did not request to compute it.
|
||||
* To force computing the label in case not yet computed use
|
||||
* {@link #getLabel(TaxonomyReader)}.
|
||||
* @see FacetRequest#getNumLabel()
|
||||
* @see #getLabel(TaxonomyReader)
|
||||
*/
|
||||
public CategoryPath getLabel();
|
||||
|
||||
/**
|
||||
* Category path of the category of this result.
|
||||
* If not already computed, will be computed now.
|
||||
* <p>
|
||||
* Use with <b>caution</b>: loading a label for results is costly, performance wise.
|
||||
* Therefore force labels loading only when really needed.
|
||||
* @param taxonomyReader taxonomy reader for forcing (lazy) labeling of this result.
|
||||
* @throws IOException on error
|
||||
* @see FacetRequest#getNumLabel()
|
||||
*/
|
||||
public CategoryPath getLabel(TaxonomyReader taxonomyReader) throws IOException;
|
||||
|
||||
/**
|
||||
* Value of this result - usually either count or a value derived from some
|
||||
* computing on the association of it.
|
||||
*/
|
||||
public double getValue();
|
||||
|
||||
/**
|
||||
* Value of screened out sub results.
|
||||
* The {@link CategoryPath label} of this result. May be {@code null} if not
|
||||
* computed, in which case use {@link TaxonomyReader#getPath(int)} to label
|
||||
* it.
|
||||
* <p>
|
||||
* If only part of valid results are returned, e.g. because top K were requested,
|
||||
* provide info on "what else is there under this result node".
|
||||
* <b>NOTE:</b> by default, all nodes are labeled. Only when
|
||||
* {@link FacetRequest#getNumLabel()} <
|
||||
* {@link FacetRequest#getNumResults()} there will be unlabeled nodes.
|
||||
*/
|
||||
public double getResidue();
|
||||
public CategoryPath label;
|
||||
|
||||
/**
|
||||
* The value of this result. Its actual type depends on the
|
||||
* {@link FacetRequest} used (e.g. in case of {@link CountFacetRequest} it is
|
||||
* {@code int}).
|
||||
*/
|
||||
public double value;
|
||||
|
||||
/**
|
||||
* Contained sub results.
|
||||
* These are either child facets, if a tree result was requested, or simply descendants, in case
|
||||
* tree result was not requested. In the first case, all returned are both descendants of
|
||||
* this node in the taxonomy and siblings of each other in the taxonomy.
|
||||
* In the latter case they are only guaranteed to be descendants of
|
||||
* this node in the taxonomy.
|
||||
* The total value of screened out sub results. If only part of the results
|
||||
* were returned (usually because only the top-K categories are requested),
|
||||
* then this provides information on "what else is there under this result
|
||||
* node".
|
||||
*/
|
||||
public Iterable<? extends FacetResultNode> getSubResults();
|
||||
|
||||
public double residue;
|
||||
|
||||
/**
|
||||
* Number of sub results
|
||||
*/
|
||||
public int getNumSubResults();
|
||||
|
||||
/**
|
||||
* Expert: Set a new value for this result node.
|
||||
* The sub-results of this result. If {@link FacetRequest#getResultMode()} is
|
||||
* {@link ResultMode#PER_NODE_IN_TREE}, every sub result denotes an immediate
|
||||
* child of this node. Otherwise, it is a descendant of any level.
|
||||
* <p>
|
||||
* Allows to modify the value of this facet node.
|
||||
* Used for example to tune a sampled value, e.g. by
|
||||
* {@link SampleFixer#fixResult(org.apache.lucene.facet.search.ScoredDocIDs, FacetResult)}
|
||||
* @param value the new value to set
|
||||
* @see #getValue()
|
||||
* @see FacetResultsHandler#rearrangeFacetResult(FacetResult)
|
||||
* <b>NOTE:</b> this member should not be {@code null}. To denote that a
|
||||
* result does not have sub results, set it to {@link #EMPTY_SUB_RESULTS} (or
|
||||
* don't modify it).
|
||||
*/
|
||||
public void setValue(double value);
|
||||
public List<FacetResultNode> subResults = EMPTY_SUB_RESULTS;
|
||||
|
||||
}
|
||||
public FacetResultNode() {
|
||||
// empty constructor
|
||||
}
|
||||
|
||||
public FacetResultNode(int ordinal, double value) {
|
||||
this.ordinal = ordinal;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString("");
|
||||
}
|
||||
|
||||
/** Returns a String representation of this facet result node. */
|
||||
public String toString(String prefix) {
|
||||
StringBuilder sb = new StringBuilder(prefix);
|
||||
if (label == null) {
|
||||
sb.append("not labeled (ordinal=").append(ordinal).append(")");
|
||||
} else {
|
||||
sb.append(label.toString());
|
||||
}
|
||||
sb.append(" (").append(Double.toString(value)).append(")");
|
||||
if (residue > 0) {
|
||||
sb.append(" (residue=").append(residue).append(")");
|
||||
}
|
||||
for (FacetResultNode sub : subResults) {
|
||||
sb.append("\n").append(prefix).append(sub.toString(prefix + " "));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,353 +0,0 @@
|
|||
package org.apache.lucene.facet.search.results;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mutable implementation for Result of faceted search for a certain taxonomy node.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public class MutableFacetResultNode implements FacetResultNode {
|
||||
|
||||
/**
|
||||
* Empty sub results to be returned when there are no results.
|
||||
* We never return null, so that code using this can remain simpler.
|
||||
*/
|
||||
private static final ArrayList<FacetResultNode> EMPTY_SUB_RESULTS = new ArrayList<FacetResultNode>();
|
||||
|
||||
private int ordinal;
|
||||
private CategoryPath label = null;
|
||||
private double value;
|
||||
private double residue;
|
||||
private List<FacetResultNode> subResults;
|
||||
|
||||
/**
|
||||
* Create a Facet Result Node.
|
||||
*
|
||||
* @param ordinal
|
||||
* ordinal in the taxonomy of the category of this result.
|
||||
* @param value
|
||||
* value this result.
|
||||
*/
|
||||
public MutableFacetResultNode(int ordinal, double value) {
|
||||
this(ordinal, value, 0, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a facet Result Node.
|
||||
* <p>
|
||||
* Used at the population of facet results, not intended for regular use by
|
||||
* applications.
|
||||
*
|
||||
* @param ordinal
|
||||
* ordinal in the taxonomy of the category of this result.
|
||||
* @param value
|
||||
* value of this result.
|
||||
*/
|
||||
public void reset(int ordinal, double value) {
|
||||
this.ordinal = ordinal;
|
||||
this.value = value;
|
||||
if (subResults != null) {
|
||||
subResults.clear();
|
||||
}
|
||||
label = null;
|
||||
residue = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Facet Result Node.
|
||||
*
|
||||
* @param ordinal
|
||||
* ordinal in the taxonomy of the category of this result.
|
||||
* @param value
|
||||
* value of this result.
|
||||
* @param residue
|
||||
* Value of screened out sub results.
|
||||
* @param label
|
||||
* label of the category path of this result.
|
||||
* @param subResults
|
||||
* - sub results, usually descendants, sometimes child results, of
|
||||
* this result - depending on the request.
|
||||
*/
|
||||
public MutableFacetResultNode(int ordinal, double value, double residue,
|
||||
CategoryPath label, List<FacetResultNode> subResults) {
|
||||
this.ordinal = ordinal;
|
||||
this.value = value;
|
||||
this.residue = residue;
|
||||
this.label = label;
|
||||
this.subResults = subResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a mutable facet result node from another result node
|
||||
* @param other other result node to copy from
|
||||
* @param takeSubResults set to true to take also sub results of other node
|
||||
*/
|
||||
public MutableFacetResultNode(FacetResultNode other, boolean takeSubResults) {
|
||||
this(other.getOrdinal(), other.getValue(), other.getResidue(), other
|
||||
.getLabel(), takeSubResults ? resultsToList(other.getSubResults())
|
||||
: null);
|
||||
}
|
||||
|
||||
private static List<FacetResultNode> resultsToList(
|
||||
Iterable<? extends FacetResultNode> subResults) {
|
||||
if (subResults == null) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<FacetResultNode> res = new ArrayList<FacetResultNode>();
|
||||
for (FacetResultNode r : subResults) {
|
||||
res.add(r);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of sub results.
|
||||
*/
|
||||
private int numSubResults() {
|
||||
if (subResults == null) {
|
||||
return 0;
|
||||
}
|
||||
return subResults.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.apache.lucene.facet.search.results2.FacetResultNode#toString(java.lang.
|
||||
* String)
|
||||
*/
|
||||
@Override
|
||||
public String toString(String prefix) {
|
||||
StringBuilder sb = new StringBuilder(prefix);
|
||||
|
||||
sb.append("Facet Result Node with ").append(numSubResults()).append(
|
||||
" sub result nodes.\n");
|
||||
|
||||
// label
|
||||
sb.append(prefix).append("Name: ").append(getLabel()).append("\n");
|
||||
|
||||
// value
|
||||
sb.append(prefix).append("Value: ").append(value).append("\n");
|
||||
|
||||
// residue
|
||||
sb.append(prefix).append("Residue: ").append(residue).append("\n");
|
||||
|
||||
if (subResults != null) {
|
||||
int i = 0;
|
||||
for (FacetResultNode subRes : subResults) {
|
||||
sb.append("\n").append(prefix).append("Subresult #").append(i++)
|
||||
.append("\n").append(subRes.toString(prefix + "\t"));
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getOrdinal() {
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CategoryPath getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label of the category of this result.
|
||||
* @param label the label to set.
|
||||
* @see #getLabel()
|
||||
*/
|
||||
public void setLabel(CategoryPath label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this result.
|
||||
*
|
||||
* @param value
|
||||
* the value to set
|
||||
* @see #getValue()
|
||||
*/
|
||||
@Override
|
||||
public void setValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* increase the value for this result.
|
||||
* @param addedValue the value to add
|
||||
* @see #getValue()
|
||||
*/
|
||||
public void increaseValue(double addedValue) {
|
||||
this.value += addedValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getResidue() {
|
||||
return residue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the residue.
|
||||
* @param residue the residue to set
|
||||
* @see #getResidue()
|
||||
*/
|
||||
public void setResidue(double residue) {
|
||||
this.residue = residue;
|
||||
}
|
||||
|
||||
/**
|
||||
* increase the residue for this result.
|
||||
* @param addedResidue the residue to add
|
||||
* @see #getResidue()
|
||||
*/
|
||||
public void increaseResidue(double addedResidue) {
|
||||
this.residue += addedResidue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Iterable<? extends FacetResultNode> getSubResults() {
|
||||
return subResults != null ? subResults : EMPTY_SUB_RESULTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim sub results to a given size.
|
||||
* <p>
|
||||
* Note: Although the {@link #getResidue()} is not guaranteed to be
|
||||
* accurate, it is worth fixing it, as possible, by taking under account the
|
||||
* trimmed sub-nodes.
|
||||
*/
|
||||
public void trimSubResults(int size) {
|
||||
if (subResults == null || subResults.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<FacetResultNode> trimmed = new ArrayList<FacetResultNode>(size);
|
||||
for (int i = 0; i < subResults.size() && i < size; i++) {
|
||||
MutableFacetResultNode trimmedNode = toImpl(subResults.get(i));
|
||||
trimmedNode.trimSubResults(size);
|
||||
trimmed.add(trimmedNode);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are trimming, it means Sampling is in effect and the extra
|
||||
* (over-sampled) results are being trimmed. Although the residue is not
|
||||
* guaranteed to be accurate for Sampling, we try our best to fix it.
|
||||
* The node's residue now will take under account the sub-nodes we're
|
||||
* trimming.
|
||||
*/
|
||||
for (int i = size; i < subResults.size(); i++) {
|
||||
increaseResidue(subResults.get(i).getValue());
|
||||
}
|
||||
|
||||
subResults = trimmed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sub results.
|
||||
* @param subResults the sub-results to set
|
||||
*/
|
||||
public void setSubResults(List<FacetResultNode> subResults) {
|
||||
this.subResults = subResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a sub result (as last).
|
||||
* @param subRes sub-result to be appended
|
||||
*/
|
||||
public void appendSubResult(FacetResultNode subRes) {
|
||||
if (subResults == null) {
|
||||
subResults = new ArrayList<FacetResultNode>();
|
||||
}
|
||||
subResults.add(subRes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert sub result (as first).
|
||||
* @param subRes sub-result to be inserted
|
||||
*/
|
||||
public void insertSubResult(FacetResultNode subRes) {
|
||||
if (subResults == null) {
|
||||
subResults = new ArrayList<FacetResultNode>();
|
||||
}
|
||||
subResults.add(0, subRes);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.apache.lucene.facet.search.results.FacetResultNode#getLabel(org.apache.lucene
|
||||
* .facet.taxonomy.TaxonomyReader)
|
||||
*/
|
||||
@Override
|
||||
public final CategoryPath getLabel(TaxonomyReader taxonomyReader)
|
||||
throws IOException {
|
||||
if (label == null) {
|
||||
label = taxonomyReader.getPath(ordinal);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.apache.lucene.facet.search.results.FacetResultNode#getNumSubResults()
|
||||
*/
|
||||
@Override
|
||||
public final int getNumSubResults() {
|
||||
return subResults == null ? 0 : subResults.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal utility: turn a result node into an implementation class
|
||||
* with richer API that allows modifying it.
|
||||
* <p>
|
||||
* In case that input result node is already of an implementation
|
||||
* class only casting is done, but in any case we pay the price
|
||||
* of checking "instance of".
|
||||
* @param frn facet result node to be turned into an implementation class object
|
||||
*/
|
||||
public static MutableFacetResultNode toImpl(FacetResultNode frn) {
|
||||
if (frn instanceof MutableFacetResultNode) {
|
||||
return (MutableFacetResultNode) frn;
|
||||
}
|
||||
return new MutableFacetResultNode(frn, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,6 @@ import org.apache.lucene.facet.search.params.FacetRequest;
|
|||
import org.apache.lucene.facet.search.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.search.results.FacetResult;
|
||||
import org.apache.lucene.facet.search.results.FacetResultNode;
|
||||
import org.apache.lucene.facet.search.results.MutableFacetResultNode;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
|
||||
|
@ -41,7 +40,7 @@ import org.apache.lucene.index.IndexReader;
|
|||
* Note: Sampling accumulation (Accumulation over a sampled-set of the results),
|
||||
* does not guarantee accurate values for
|
||||
* {@link FacetResult#getNumValidDescendants()} &
|
||||
* {@link FacetResultNode#getResidue()}.
|
||||
* {@link FacetResultNode#residue}.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
|
@ -169,12 +168,39 @@ public abstract class Sampler {
|
|||
|
||||
FacetRequest origFrq = sampledFreq.orig;
|
||||
|
||||
MutableFacetResultNode trimmedRootNode = MutableFacetResultNode.toImpl(facetResult.getFacetResultNode());
|
||||
trimmedRootNode.trimSubResults(origFrq.getNumResults());
|
||||
FacetResultNode trimmedRootNode = facetResult.getFacetResultNode();
|
||||
trimSubResults(trimmedRootNode, origFrq.getNumResults());
|
||||
|
||||
return new FacetResult(origFrq, trimmedRootNode, facetResult.getNumValidDescendants());
|
||||
}
|
||||
|
||||
/** Trim sub results to a given size. */
|
||||
private void trimSubResults(FacetResultNode node, int size) {
|
||||
if (node.subResults == FacetResultNode.EMPTY_SUB_RESULTS || node.subResults.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<FacetResultNode> trimmed = new ArrayList<FacetResultNode>(size);
|
||||
for (int i = 0; i < node.subResults.size() && i < size; i++) {
|
||||
FacetResultNode trimmedNode = node.subResults.get(i);
|
||||
trimSubResults(trimmedNode, size);
|
||||
trimmed.add(trimmedNode);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are trimming, it means Sampling is in effect and the extra
|
||||
* (over-sampled) results are being trimmed. Although the residue is not
|
||||
* guaranteed to be accurate for Sampling, we try our best to fix it.
|
||||
* The node's residue now will take under account the sub-nodes we're
|
||||
* trimming.
|
||||
*/
|
||||
for (int i = size; i < node.subResults.size(); i++) {
|
||||
node.residue += node.subResults.get(i).value;
|
||||
}
|
||||
|
||||
node.subResults = trimmed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Over-sampled search params, wrapping each request with an over-sampled one.
|
||||
*/
|
||||
|
|
|
@ -49,7 +49,7 @@ import org.apache.lucene.index.IndexReader;
|
|||
* Note: Sampling accumulation (Accumulation over a sampled-set of the results),
|
||||
* does not guarantee accurate values for
|
||||
* {@link FacetResult#getNumValidDescendants()} &
|
||||
* {@link FacetResultNode#getResidue()}.
|
||||
* {@link FacetResultNode#residue}.
|
||||
*
|
||||
* @see Sampler
|
||||
* @lucene.experimental
|
||||
|
|
|
@ -74,10 +74,9 @@ class TakmiSampleFixer implements SampleFixer {
|
|||
* docids in effect
|
||||
* @throws IOException If there is a low-level I/O error.
|
||||
*/
|
||||
private void fixResultNode(FacetResultNode facetResNode, ScoredDocIDs docIds)
|
||||
throws IOException {
|
||||
private void fixResultNode(FacetResultNode facetResNode, ScoredDocIDs docIds) throws IOException {
|
||||
recount(facetResNode, docIds);
|
||||
for (FacetResultNode frn : facetResNode.getSubResults()) {
|
||||
for (FacetResultNode frn : facetResNode.subResults) {
|
||||
fixResultNode(frn, docIds);
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +100,10 @@ class TakmiSampleFixer implements SampleFixer {
|
|||
* facet results was exercise, we need to calculate them anyway, so
|
||||
* in essence sampling with recounting spends some extra cycles for
|
||||
* labeling results for which labels are not required. */
|
||||
CategoryPath catPath = fresNode.getLabel(taxonomyReader); // force labeling
|
||||
if (fresNode.label == null) {
|
||||
fresNode.label = taxonomyReader.getPath(fresNode.ordinal);
|
||||
}
|
||||
CategoryPath catPath = fresNode.label;
|
||||
|
||||
Term drillDownTerm = DrillDown.term(searchParams, catPath);
|
||||
// TODO (Facet): avoid Multi*?
|
||||
|
@ -109,8 +111,7 @@ class TakmiSampleFixer implements SampleFixer {
|
|||
int updatedCount = countIntersection(MultiFields.getTermDocsEnum(indexReader, liveDocs,
|
||||
drillDownTerm.field(), drillDownTerm.bytes(),
|
||||
0), docIds.iterator());
|
||||
|
||||
fresNode.setValue(updatedCount);
|
||||
fresNode.value = updatedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,12 +73,12 @@ public class ResultSortUtils {
|
|||
|
||||
@Override
|
||||
protected boolean lessThan(FacetResultNode arg0, FacetResultNode arg1) {
|
||||
double value0 = arg0.getValue();
|
||||
double value1 = arg1.getValue();
|
||||
double value0 = arg0.value;
|
||||
double value1 = arg1.value;
|
||||
|
||||
int valueCompare = Double.compare(value0, value1);
|
||||
if (valueCompare == 0) {
|
||||
return arg0.getOrdinal() < arg1.getOrdinal();
|
||||
return arg0.ordinal < arg1.ordinal;
|
||||
}
|
||||
|
||||
return valueCompare < 0;
|
||||
|
@ -93,40 +93,38 @@ public class ResultSortUtils {
|
|||
|
||||
@Override
|
||||
protected boolean lessThan(FacetResultNode arg0, FacetResultNode arg1) {
|
||||
double value0 = arg0.getValue();
|
||||
double value1 = arg1.getValue();
|
||||
double value0 = arg0.value;
|
||||
double value1 = arg1.value;
|
||||
|
||||
int valueCompare = Double.compare(value0, value1);
|
||||
if (valueCompare == 0) {
|
||||
return arg0.getOrdinal() > arg1.getOrdinal();
|
||||
return arg0.ordinal > arg1.ordinal;
|
||||
}
|
||||
|
||||
return valueCompare > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MinOrdinalHeap extends
|
||||
PriorityQueue<FacetResultNode> implements Heap<FacetResultNode> {
|
||||
private static class MinOrdinalHeap extends PriorityQueue<FacetResultNode> implements Heap<FacetResultNode> {
|
||||
public MinOrdinalHeap(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean lessThan(FacetResultNode arg0, FacetResultNode arg1) {
|
||||
return arg0.getOrdinal() < arg1.getOrdinal();
|
||||
return arg0.ordinal < arg1.ordinal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MaxOrdinalHeap extends
|
||||
PriorityQueue<FacetResultNode> implements Heap<FacetResultNode> {
|
||||
private static class MaxOrdinalHeap extends PriorityQueue<FacetResultNode> implements Heap<FacetResultNode> {
|
||||
public MaxOrdinalHeap(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean lessThan(FacetResultNode arg0, FacetResultNode arg1) {
|
||||
return arg0.getOrdinal() > arg1.getOrdinal();
|
||||
return arg0.ordinal > arg1.ordinal;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -156,10 +154,9 @@ public class ResultSortUtils {
|
|||
Collections.sort(resultNodes, new Comparator<FacetResultNode>() {
|
||||
@Override
|
||||
public int compare(FacetResultNode o1, FacetResultNode o2) {
|
||||
int value = Double.compare(o1.getValue(), o2
|
||||
.getValue());
|
||||
int value = Double.compare(o1.value, o2.value);
|
||||
if (value == 0) {
|
||||
value = o1.getOrdinal() - o2.getOrdinal();
|
||||
value = o1.ordinal - o2.ordinal;
|
||||
}
|
||||
if (accending) {
|
||||
value = -value;
|
||||
|
@ -198,4 +195,5 @@ public class ResultSortUtils {
|
|||
resultNodes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -246,7 +246,7 @@ public abstract class FacetTestBase extends LuceneTestCase {
|
|||
/** convenience method: convert sub results to an array */
|
||||
protected static FacetResultNode[] resultNodesAsArray(FacetResultNode parentRes) {
|
||||
ArrayList<FacetResultNode> a = new ArrayList<FacetResultNode>();
|
||||
for (FacetResultNode frn : parentRes.getSubResults()) {
|
||||
for (FacetResultNode frn : parentRes.subResults) {
|
||||
a.add(frn);
|
||||
}
|
||||
return a.toArray(new FacetResultNode[0]);
|
||||
|
@ -305,42 +305,27 @@ public abstract class FacetTestBase extends LuceneTestCase {
|
|||
|
||||
/** Validate counts for returned facets, and that there are not too many results */
|
||||
private static void assertCountsAndCardinality(Map<CategoryPath,Integer> facetCountsTruth, FacetResultNode resNode, int reqNumResults) throws Exception {
|
||||
int actualNumResults = resNode.getNumSubResults();
|
||||
int actualNumResults = resNode.subResults.size();
|
||||
if (VERBOSE) {
|
||||
System.out.println("NumResults: " + actualNumResults);
|
||||
}
|
||||
assertTrue("Too many results!", actualNumResults <= reqNumResults);
|
||||
for (FacetResultNode subRes : resNode.getSubResults()) {
|
||||
assertEquals("wrong count for: "+subRes, facetCountsTruth.get(subRes.getLabel()).intValue(), (int)subRes.getValue());
|
||||
for (FacetResultNode subRes : resNode.subResults) {
|
||||
assertEquals("wrong count for: "+subRes, facetCountsTruth.get(subRes.label).intValue(), (int)subRes.value);
|
||||
assertCountsAndCardinality(facetCountsTruth, subRes, reqNumResults); // recurse into child results
|
||||
}
|
||||
}
|
||||
|
||||
/** Validate results equality */
|
||||
protected static void assertSameResults(List<FacetResult> expected, List<FacetResult> actual) {
|
||||
String expectedResults = resStringValueOnly(expected);
|
||||
String actualResults = resStringValueOnly(actual);
|
||||
if (!expectedResults.equals(actualResults)) {
|
||||
System.err.println("Results are not the same!");
|
||||
System.err.println("Expected:\n" + expectedResults);
|
||||
System.err.println("Actual:\n" + actualResults);
|
||||
throw new NotSameResultError();
|
||||
}
|
||||
}
|
||||
|
||||
/** exclude the residue and numDecendants because it is incorrect in sampling */
|
||||
private static final String resStringValueOnly(List<FacetResult> results) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (FacetResult facetRes : results) {
|
||||
sb.append(facetRes.toString()).append('\n');
|
||||
}
|
||||
return sb.toString().replaceAll("Residue:.*.0", "").replaceAll("Num valid Descendants.*", "");
|
||||
}
|
||||
|
||||
/** Special Error class for ability to ignore only this error and retry... */
|
||||
public static class NotSameResultError extends Error {
|
||||
public NotSameResultError() {
|
||||
super("Results are not the same!");
|
||||
assertEquals("wrong number of facet results", expected.size(), actual.size());
|
||||
int size = expected.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
FacetResult expectedResult = expected.get(i);
|
||||
FacetResult actualResult = actual.get(i);
|
||||
String expectedStr = FacetTestUtils.toSimpleString(expectedResult);
|
||||
String actualStr = FacetTestUtils.toSimpleString(actualResult);
|
||||
assertEquals("Results not the same!\nExpected:" + expectedStr + "\nActual:\n" + actualStr, expectedStr, actualStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.apache.lucene.facet.search.FacetsCollector;
|
|||
import org.apache.lucene.facet.search.params.CountFacetRequest;
|
||||
import org.apache.lucene.facet.search.params.FacetRequest;
|
||||
import org.apache.lucene.facet.search.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.search.results.FacetResult;
|
||||
import org.apache.lucene.facet.search.results.FacetResultNode;
|
||||
import org.apache.lucene.facet.taxonomy.CategoryPath;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
|
||||
|
@ -45,6 +47,33 @@ import org.apache.lucene.util.LuceneTestCase;
|
|||
|
||||
public class FacetTestUtils {
|
||||
|
||||
public static class IndexTaxonomyReaderPair {
|
||||
public DirectoryReader indexReader;
|
||||
public DirectoryTaxonomyReader taxReader;
|
||||
public IndexSearcher indexSearcher;
|
||||
|
||||
public void close() throws IOException {
|
||||
indexReader.close();
|
||||
taxReader.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class IndexTaxonomyWriterPair {
|
||||
public IndexWriter indexWriter;
|
||||
public TaxonomyWriter taxWriter;
|
||||
|
||||
public void close() throws IOException {
|
||||
indexWriter.close();
|
||||
taxWriter.close();
|
||||
}
|
||||
|
||||
public void commit() throws IOException {
|
||||
indexWriter.commit();
|
||||
taxWriter.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public static Directory[][] createIndexTaxonomyDirs(int number) {
|
||||
Directory[][] dirs = new Directory[number][2];
|
||||
for (int i = 0; i < number; i++) {
|
||||
|
@ -66,7 +95,7 @@ public class FacetTestUtils {
|
|||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
|
||||
public static IndexTaxonomyWriterPair[] createIndexTaxonomyWriterPair(
|
||||
Directory[][] dirs) throws IOException {
|
||||
IndexTaxonomyWriterPair[] pairs = new IndexTaxonomyWriterPair[dirs.length];
|
||||
|
@ -109,31 +138,17 @@ public class FacetTestUtils {
|
|||
searcher.search(new MatchAllDocsQuery(), mColl);
|
||||
return collectors;
|
||||
}
|
||||
|
||||
public static class IndexTaxonomyReaderPair {
|
||||
public DirectoryReader indexReader;
|
||||
public DirectoryTaxonomyReader taxReader;
|
||||
public IndexSearcher indexSearcher;
|
||||
|
||||
public void close() throws IOException {
|
||||
indexReader.close();
|
||||
taxReader.close();
|
||||
}
|
||||
|
||||
public static String toSimpleString(FacetResult fr) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toSimpleString(0, sb, fr.getFacetResultNode(), "");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static class IndexTaxonomyWriterPair {
|
||||
public IndexWriter indexWriter;
|
||||
public TaxonomyWriter taxWriter;
|
||||
|
||||
public void close() throws IOException {
|
||||
indexWriter.close();
|
||||
taxWriter.close();
|
||||
}
|
||||
|
||||
public void commit() throws IOException {
|
||||
indexWriter.commit();
|
||||
taxWriter.commit();
|
||||
|
||||
private static void toSimpleString(int depth, StringBuilder sb, FacetResultNode node, String indent) {
|
||||
sb.append(indent + node.label.components[depth] + " (" + (int) node.value + ")\n");
|
||||
for (FacetResultNode childNode : node.subResults) {
|
||||
toSimpleString(depth + 1, sb, childNode, indent + " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,10 +45,10 @@ public class TestAssociationExample extends LuceneTestCase {
|
|||
assertEquals("Wrong number of results!", 1, res.getFacetResults().size());
|
||||
assertEquals("Wrong number of facets!", 2, res.getFacetResults().get(0).getNumValidDescendants());
|
||||
|
||||
Iterable<? extends FacetResultNode> it = res.getFacetResults().get(0).getFacetResultNode().getSubResults();
|
||||
Iterable<? extends FacetResultNode> it = res.getFacetResults().get(0).getFacetResultNode().subResults;
|
||||
int i = 0;
|
||||
for (FacetResultNode fResNode : it) {
|
||||
assertEquals("Wrong result for facet "+fResNode.getLabel(), expectedResults[i++], fResNode.getValue(), 1E-5);
|
||||
assertEquals("Wrong result for facet "+fResNode.label, expectedResults[i++], fResNode.value, 1E-5);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,45 +43,35 @@ public class TestMultiCLExample extends LuceneTestCase {
|
|||
List<FacetResult> results = exampleResults.getFacetResults();
|
||||
FacetResult result = results.get(0);
|
||||
assertNotNull("Result should not be null", result);
|
||||
assertEquals("Invalid label", "5", result.getFacetResultNode()
|
||||
.getLabel().toString());
|
||||
assertEquals("Invalid value", 2.0, result.getFacetResultNode()
|
||||
.getValue(), 0.0);
|
||||
assertEquals("Invalid # of subresults", 3, result.getFacetResultNode()
|
||||
.getNumSubResults());
|
||||
FacetResultNode node = result.getFacetResultNode();
|
||||
assertEquals("Invalid label", "5", node.label.toString());
|
||||
assertEquals("Invalid value", 2.0, node.value, 0.0);
|
||||
assertEquals("Invalid # of subresults", 3, node.subResults.size());
|
||||
|
||||
Iterator<? extends FacetResultNode> subResults = result
|
||||
.getFacetResultNode().getSubResults().iterator();
|
||||
Iterator<? extends FacetResultNode> subResults = node.subResults.iterator();
|
||||
FacetResultNode sub = subResults.next();
|
||||
assertEquals("Invalid subresult value", 1.0, sub.getValue(), 0.0);
|
||||
assertEquals("Invalid subresult label", "5/2", sub.getLabel()
|
||||
.toString());
|
||||
assertEquals("Invalid subresult value", 1.0, sub.value, 0.0);
|
||||
assertEquals("Invalid subresult label", "5/2", sub.label.toString());
|
||||
sub = subResults.next();
|
||||
assertEquals("Invalid subresult value", 1.0, sub.getValue(), 0.0);
|
||||
assertEquals("Invalid subresult label", "5/7", sub.getLabel()
|
||||
.toString());
|
||||
assertEquals("Invalid subresult value", 1.0, sub.value, 0.0);
|
||||
assertEquals("Invalid subresult label", "5/7", sub.label.toString());
|
||||
sub = subResults.next();
|
||||
assertEquals("Invalid subresult value", 1.0, sub.getValue(), 0.0);
|
||||
assertEquals("Invalid subresult label", "5/5", sub.getLabel()
|
||||
.toString());
|
||||
assertEquals("Invalid subresult value", 1.0, sub.value, 0.0);
|
||||
assertEquals("Invalid subresult label", "5/5", sub.label.toString());
|
||||
|
||||
result = results.get(1);
|
||||
node = result.getFacetResultNode();
|
||||
assertNotNull("Result should not be null", result);
|
||||
assertEquals("Invalid label", "5/5", result.getFacetResultNode()
|
||||
.getLabel().toString());
|
||||
assertEquals("Invalid value", 1,
|
||||
result.getFacetResultNode().getValue(), 0.0);
|
||||
assertEquals("Invalid number of subresults", 0, result
|
||||
.getFacetResultNode().getNumSubResults());
|
||||
assertEquals("Invalid label", "5/5", node.label.toString());
|
||||
assertEquals("Invalid value", 1, node.value, 0.0);
|
||||
assertEquals("Invalid number of subresults", 0, node.subResults.size());
|
||||
|
||||
result = results.get(2);
|
||||
node = result.getFacetResultNode();
|
||||
assertNotNull("Result should not be null", result);
|
||||
assertEquals("Invalid label", "6/2", result.getFacetResultNode()
|
||||
.getLabel().toString());
|
||||
assertEquals("Invalid value", 1,
|
||||
result.getFacetResultNode().getValue(), 0.0);
|
||||
assertEquals("Invalid number of subresults", 0, result
|
||||
.getFacetResultNode().getNumSubResults());
|
||||
assertEquals("Invalid label", "6/2", node.label.toString());
|
||||
assertEquals("Invalid value", 1, node.value, 0.0);
|
||||
assertEquals("Invalid number of subresults", 0, node.subResults.size());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,11 @@ public class TestSimpleExample extends LuceneTestCase {
|
|||
FacetResult facetResult = res.getFacetResults().get(0);
|
||||
assertEquals("Wrong number of facets!",2, facetResult.getNumValidDescendants());
|
||||
|
||||
Iterator<? extends FacetResultNode> resIterator = facetResult.getFacetResultNode().getSubResults().iterator();
|
||||
Iterator<? extends FacetResultNode> resIterator = facetResult.getFacetResultNode().subResults.iterator();
|
||||
assertTrue("Too few results", resIterator.hasNext());
|
||||
assertEquals("wrong count for first result out of 2", 1, (int)resIterator.next().getValue());
|
||||
assertEquals("wrong count for first result out of 2", 1, (int)resIterator.next().value);
|
||||
assertTrue("Too few results", resIterator.hasNext());
|
||||
assertEquals("wrong count for second result out of 2", 1, (int)resIterator.next().getValue());
|
||||
assertEquals("wrong count for second result out of 2", 1, (int)resIterator.next().value);
|
||||
assertFalse("Too many results!", resIterator.hasNext());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,9 +75,9 @@ public class OrdinalMappingReaderTest extends LuceneTestCase {
|
|||
searcher.search(new MatchAllDocsQuery(), collector);
|
||||
FacetResult result = collector.getFacetResults().get(0);
|
||||
FacetResultNode node = result.getFacetResultNode();
|
||||
for (FacetResultNode facet: node.getSubResults()) {
|
||||
int weight = (int)facet.getValue();
|
||||
int label = Integer.parseInt(facet.getLabel().components[1]);
|
||||
for (FacetResultNode facet: node.subResults) {
|
||||
int weight = (int)facet.value;
|
||||
int label = Integer.parseInt(facet.label.components[1]);
|
||||
//System.out.println(label + ": " + weight);
|
||||
if (VERBOSE) {
|
||||
System.out.println(label + ": " + weight);
|
||||
|
|
|
@ -273,8 +273,8 @@ public class TestFacetsPayloadMigrationReader extends LuceneTestCase {
|
|||
assertEquals(requests.size(), facetResults.size());
|
||||
for (FacetResult res : facetResults) {
|
||||
FacetResultNode node = res.getFacetResultNode();
|
||||
String dim = node.getLabel().components[0];
|
||||
assertEquals("wrong count for " + dim, expectedCounts.get(dim).intValue(), (int) node.getValue());
|
||||
String dim = node.label.components[0];
|
||||
assertEquals("wrong count for " + dim, expectedCounts.get(dim).intValue(), (int) node.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ public class TestFacetsPayloadMigrationReader extends LuceneTestCase {
|
|||
List<FacetResult> facetResults = fc.getFacetResults();
|
||||
assertEquals(1, facetResults.size());
|
||||
FacetResultNode rootNode = facetResults.get(0).getFacetResultNode();
|
||||
assertEquals("wrong count for " + dim, expectedCounts.get(dim).intValue(), (int) rootNode.getValue());
|
||||
assertEquals("wrong count for " + dim, expectedCounts.get(dim).intValue(), (int) rootNode.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,8 +129,8 @@ public class TestDemoFacets extends LuceneTestCase {
|
|||
}
|
||||
|
||||
private void toSimpleString(int depth, StringBuilder sb, FacetResultNode node, String indent) {
|
||||
sb.append(indent + node.getLabel().components[depth] + " (" + (int) node.getValue() + ")\n");
|
||||
for(FacetResultNode childNode : node.getSubResults()) {
|
||||
sb.append(indent + node.label.components[depth] + " (" + (int) node.value + ")\n");
|
||||
for(FacetResultNode childNode : node.subResults) {
|
||||
toSimpleString(depth+1, sb, childNode, indent + " ");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,8 +118,8 @@ public class TestFacetsAccumulatorWithComplement extends FacetTestBase {
|
|||
FacetResultNode parentResWithComp = countResWithComplement.get(0).getFacetResultNode();
|
||||
FacetResultNode parentResNoComp = countResWithComplement.get(0).getFacetResultNode();
|
||||
|
||||
assertEquals("Wrong number of top count aggregated categories with complement!",3,parentResWithComp.getNumSubResults());
|
||||
assertEquals("Wrong number of top count aggregated categories no complement!",3,parentResNoComp.getNumSubResults());
|
||||
assertEquals("Wrong number of top count aggregated categories with complement!",3,parentResWithComp.subResults.size());
|
||||
assertEquals("Wrong number of top count aggregated categories no complement!",3,parentResNoComp.subResults.size());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public class TestFacetsCollector extends LuceneTestCase {
|
|||
new IndexSearcher(r).search(new MatchAllDocsQuery(), MultiCollector.wrap(fc, topDocs));
|
||||
|
||||
List<FacetResult> res = fc.getFacetResults();
|
||||
double value = res.get(0).getFacetResultNode().getValue();
|
||||
double value = res.get(0).getFacetResultNode().value;
|
||||
double expected = topDocs.topDocs().getMaxScore() * r.numDocs();
|
||||
assertEquals(expected, value, 1E-10);
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ public class TestMultipleCategoryLists extends LuceneTestCase {
|
|||
|
||||
FacetResult results = res.get(0);
|
||||
FacetResultNode resNode = results.getFacetResultNode();
|
||||
Iterable<? extends FacetResultNode> subResults = resNode.getSubResults();
|
||||
Iterable<? extends FacetResultNode> subResults = resNode.subResults;
|
||||
Iterator<? extends FacetResultNode> subIter = subResults.iterator();
|
||||
|
||||
checkResult(resNode, "Band", 5.0);
|
||||
|
@ -280,7 +280,7 @@ public class TestMultipleCategoryLists extends LuceneTestCase {
|
|||
|
||||
results = res.get(1);
|
||||
resNode = results.getFacetResultNode();
|
||||
subResults = resNode.getSubResults();
|
||||
subResults = resNode.subResults;
|
||||
subIter = subResults.iterator();
|
||||
|
||||
checkResult(resNode, "Band", 5.0);
|
||||
|
@ -294,7 +294,7 @@ public class TestMultipleCategoryLists extends LuceneTestCase {
|
|||
|
||||
results = res.get(2);
|
||||
resNode = results.getFacetResultNode();
|
||||
subResults = resNode.getSubResults();
|
||||
subResults = resNode.subResults;
|
||||
subIter = subResults.iterator();
|
||||
|
||||
checkResult(resNode, "Author", 3.0);
|
||||
|
@ -304,7 +304,7 @@ public class TestMultipleCategoryLists extends LuceneTestCase {
|
|||
|
||||
results = res.get(3);
|
||||
resNode = results.getFacetResultNode();
|
||||
subResults = resNode.getSubResults();
|
||||
subResults = resNode.subResults;
|
||||
subIter = subResults.iterator();
|
||||
|
||||
checkResult(resNode, "Band/Rock & Pop", 4.0);
|
||||
|
@ -350,8 +350,8 @@ public class TestMultipleCategoryLists extends LuceneTestCase {
|
|||
}
|
||||
|
||||
private static void checkResult(FacetResultNode sub, String label, double value) {
|
||||
assertEquals("Label of subresult " + sub.getLabel() + " was incorrect", label, sub.getLabel().toString());
|
||||
assertEquals("Value for " + sub.getLabel() + " subresult was incorrect", value, sub.getValue(), 0.0);
|
||||
assertEquals("Label of subresult " + sub.label + " was incorrect", label, sub.label.toString());
|
||||
assertEquals("Value for " + sub.label + " subresult was incorrect", value, sub.value, 0.0);
|
||||
}
|
||||
|
||||
}
|
|
@ -89,10 +89,8 @@ public class TestScoredDocIdCollector extends FacetTestBase {
|
|||
FacetResultNode parentCountRes = countRes.get(0).getFacetResultNode();
|
||||
FacetResultNode parentScoreRes = scoreRes.get(0).getFacetResultNode();
|
||||
|
||||
assertEquals("Wrong number of top count aggregated categories!", 3,
|
||||
parentCountRes.getNumSubResults());
|
||||
assertEquals("Wrong number of top score aggregated categories!", 3,
|
||||
parentScoreRes.getNumSubResults());
|
||||
assertEquals("Wrong number of top count aggregated categories!", 3, parentCountRes.subResults.size());
|
||||
assertEquals("Wrong number of top score aggregated categories!", 3, parentScoreRes.subResults.size());
|
||||
|
||||
// rely on that facet value is computed as doc-score, and
|
||||
// accordingly compare values of the two top-category results.
|
||||
|
@ -101,12 +99,8 @@ public class TestScoredDocIdCollector extends FacetTestBase {
|
|||
FacetResultNode[] scoreResNodes = resultNodesAsArray(parentScoreRes);
|
||||
|
||||
for (int i = 0; i < scoreResNodes.length; i++) {
|
||||
assertEquals("Ordinals differ!",
|
||||
countResNodes[i].getOrdinal(), scoreResNodes[i].getOrdinal());
|
||||
assertEquals("Wrong scores!",
|
||||
constScore * countResNodes[i].getValue(),
|
||||
scoreResNodes[i].getValue(),
|
||||
Double.MIN_VALUE);
|
||||
assertEquals("Ordinals differ!", countResNodes[i].ordinal, scoreResNodes[i].ordinal);
|
||||
assertEquals("Wrong scores!", constScore * countResNodes[i].value, scoreResNodes[i].value, Double.MIN_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -116,10 +116,10 @@ public class TestStandardFacetsAccumulator extends LuceneTestCase {
|
|||
List<FacetResult> results = fc.getFacetResults();
|
||||
assertEquals("received too many facet results", 1, results.size());
|
||||
FacetResultNode frn = results.get(0).getFacetResultNode();
|
||||
assertEquals("wrong weight for \"A\"", 4, (int) frn.getValue());
|
||||
assertEquals("wrong number of children", 2, frn.getNumSubResults());
|
||||
for (FacetResultNode node : frn.getSubResults()) {
|
||||
assertEquals("wrong weight for child " + node.getLabel(), 2, (int) node.getValue());
|
||||
assertEquals("wrong weight for \"A\"", 4, (int) frn.value);
|
||||
assertEquals("wrong number of children", 2, frn.subResults.size());
|
||||
for (FacetResultNode node : frn.subResults) {
|
||||
assertEquals("wrong weight for child " + node.label, 2, (int) node.value);
|
||||
}
|
||||
IOUtils.close(indexReader, taxoReader);
|
||||
|
||||
|
|
|
@ -181,40 +181,40 @@ public class TestTopKInEachNodeResultHandler extends LuceneTestCase {
|
|||
boolean hasDoctor = "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(9, fr.getNumValidDescendants());
|
||||
FacetResultNode parentRes = fr.getFacetResultNode();
|
||||
assertEquals(16.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.getNumSubResults());
|
||||
assertEquals(16.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.subResults.size());
|
||||
// two nodes sorted by descending values: a/b with 8 and a/c with 6
|
||||
// a/b has residue 2 and two children a/b/2 with value 3, and a/b/1 with value 2.
|
||||
// a/c has residue 0, and one child a/c/1 with value 1.
|
||||
double [] expectedValues0 = { 8.0, 2.0, 3.0, 0.0, 2.0, 0.0, 6.0, 0.0, 1.0, 0.0 };
|
||||
int i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues0[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node.getResidue(), Double.MIN_VALUE);
|
||||
for (FacetResultNode node2 : node.getSubResults()) {
|
||||
assertEquals(expectedValues0[i++], node2.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node2.getResidue(), Double.MIN_VALUE);
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues0[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node.residue, Double.MIN_VALUE);
|
||||
for (FacetResultNode node2 : node.subResults) {
|
||||
assertEquals(expectedValues0[i++], node2.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node2.residue, Double.MIN_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
// now just change the value of the first child of the root to 5, and then rearrange
|
||||
// expected are: first a/c of value 6 and residue 0, and one child a/c/1 with value 1
|
||||
// then a/b with value 5 and residue 2, and both children: a/b/2 with value 3, and a/b/1 with value 2.
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
node.setValue(5.0);
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
node.value = 5.0;
|
||||
break;
|
||||
}
|
||||
// now rearrange
|
||||
double [] expectedValues00 = { 6.0, 0.0, 1.0, 0.0, 5.0, 2.0, 3.0, 0.0, 2.0, 0.0 };
|
||||
fr = cfra23.createFacetResultsHandler(tr).rearrangeFacetResult(fr);
|
||||
i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues00[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues00[i++], node.getResidue(), Double.MIN_VALUE);
|
||||
for (FacetResultNode node2 : node.getSubResults()) {
|
||||
assertEquals(expectedValues00[i++], node2.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues00[i++], node2.getResidue(), Double.MIN_VALUE);
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues00[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues00[i++], node.residue, Double.MIN_VALUE);
|
||||
for (FacetResultNode node2 : node.subResults) {
|
||||
assertEquals(expectedValues00[i++], node2.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues00[i++], node2.residue, Double.MIN_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,19 +222,19 @@ public class TestTopKInEachNodeResultHandler extends LuceneTestCase {
|
|||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(9, fr.getNumValidDescendants());
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(16.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.getNumSubResults());
|
||||
assertEquals(16.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.subResults.size());
|
||||
// two nodes sorted by descending values: a/b with 8 and a/c with 6
|
||||
// a/b has residue 2 and two children a/b/2 with value 3, and a/b/1 with value 2.
|
||||
// a/c has residue 0, and one child a/c/1 with value 1.
|
||||
i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues0[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node.getResidue(), Double.MIN_VALUE);
|
||||
for (FacetResultNode node2 : node.getSubResults()) {
|
||||
assertEquals(expectedValues0[i++], node2.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node2.getResidue(), Double.MIN_VALUE);
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues0[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node.residue, Double.MIN_VALUE);
|
||||
for (FacetResultNode node2 : node.subResults) {
|
||||
assertEquals(expectedValues0[i++], node2.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues0[i++], node2.residue, Double.MIN_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,70 +242,70 @@ public class TestTopKInEachNodeResultHandler extends LuceneTestCase {
|
|||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(4, fr.getNumValidDescendants(), 4);
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(16.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.getNumSubResults());
|
||||
assertEquals(16.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.subResults.size());
|
||||
// two nodes sorted by descending values:
|
||||
// a/b with value 8 and residue 0 (because no children considered),
|
||||
// and a/c with value 6 and residue 0 (because no children considered)
|
||||
double [] expectedValues2 = { 8.0, 0.0, 6.0, 0.0 };
|
||||
i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues2[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(expectedValues2[i++], node.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(node.getNumSubResults(), 0);
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues2[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(expectedValues2[i++], node.residue, Double.MIN_VALUE);
|
||||
assertEquals(node.subResults.size(), 0);
|
||||
}
|
||||
|
||||
fr = facetResults.get(3); // a/b, depth=3, K=2
|
||||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(4, fr.getNumValidDescendants());
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(8.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.getNumSubResults());
|
||||
assertEquals(8.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.subResults.size());
|
||||
double [] expectedValues3 = { 3.0, 2.0 };
|
||||
i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues3[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(0.0, node.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(0, node.getNumSubResults());
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues3[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(0.0, node.residue, Double.MIN_VALUE);
|
||||
assertEquals(0, node.subResults.size());
|
||||
}
|
||||
|
||||
fr = facetResults.get(4); // a/b, depth=2, K=2
|
||||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(4, fr.getNumValidDescendants());
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(8.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.getNumSubResults());
|
||||
assertEquals(8.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.subResults.size());
|
||||
i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues3[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(0.0, node.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(0, node.getNumSubResults());
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues3[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(0.0, node.residue, Double.MIN_VALUE);
|
||||
assertEquals(0, node.subResults.size());
|
||||
}
|
||||
|
||||
fr = facetResults.get(5); // a/b, depth=1, K=2
|
||||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(4, fr.getNumValidDescendants());
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(8.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.getNumSubResults());
|
||||
assertEquals(8.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(2, parentRes.subResults.size());
|
||||
i = 0;
|
||||
for (FacetResultNode node : parentRes.getSubResults()) {
|
||||
assertEquals(expectedValues3[i++], node.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(0.0, node.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(0, node.getNumSubResults());
|
||||
for (FacetResultNode node : parentRes.subResults) {
|
||||
assertEquals(expectedValues3[i++], node.value, Double.MIN_VALUE);
|
||||
assertEquals(0.0, node.residue, Double.MIN_VALUE);
|
||||
assertEquals(0, node.subResults.size());
|
||||
}
|
||||
|
||||
fr = facetResults.get(6); // a/b, depth=0, K=2
|
||||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
assertEquals(0, fr.getNumValidDescendants()); // 0 descendants but rootnode
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(8.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(0.0, parentRes.getResidue(), Double.MIN_VALUE);
|
||||
assertEquals(0, parentRes.getNumSubResults());
|
||||
assertEquals(8.0, parentRes.value, Double.MIN_VALUE);
|
||||
assertEquals(0.0, parentRes.residue, Double.MIN_VALUE);
|
||||
assertEquals(0, parentRes.subResults.size());
|
||||
hasDoctor |= "Doctor".equals(fr.getFacetRequest().categoryPath.components[0]);
|
||||
|
||||
// doctor, depth=1, K=2
|
||||
|
|
|
@ -99,52 +99,46 @@ public class TestTopKResultsHandler extends BaseTestTopK {
|
|||
};
|
||||
|
||||
searcher.search(new MatchAllDocsQuery(), fc);
|
||||
long start = System.currentTimeMillis();
|
||||
List<FacetResult> facetResults = fc.getFacetResults();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
if (VERBOSE) {
|
||||
System.out.println("Time: " + (end - start));
|
||||
}
|
||||
|
||||
FacetResult fr = facetResults.get(0);
|
||||
FacetResultNode parentRes = fr.getFacetResultNode();
|
||||
assertEquals(13.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(13.0, parentRes.value, Double.MIN_VALUE);
|
||||
FacetResultNode[] frn = resultNodesAsArray(parentRes);
|
||||
assertEquals(7.0, frn[0].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(6.0, frn[1].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(7.0, frn[0].value, Double.MIN_VALUE);
|
||||
assertEquals(6.0, frn[1].value, Double.MIN_VALUE);
|
||||
|
||||
fr = facetResults.get(1);
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(13.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(13.0, parentRes.value, Double.MIN_VALUE);
|
||||
frn = resultNodesAsArray(parentRes);
|
||||
assertEquals(7.0, frn[0].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(6.0, frn[1].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[2].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[3].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[4].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[5].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(7.0, frn[0].value, Double.MIN_VALUE);
|
||||
assertEquals(6.0, frn[1].value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[2].value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[3].value, Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[4].value, Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[5].value, Double.MIN_VALUE);
|
||||
|
||||
fr = facetResults.get(2);
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(7.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(7.0, parentRes.value, Double.MIN_VALUE);
|
||||
frn = resultNodesAsArray(parentRes);
|
||||
assertEquals(2.0, frn[0].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[1].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[2].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[3].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[0].value, Double.MIN_VALUE);
|
||||
assertEquals(2.0, frn[1].value, Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[2].value, Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[3].value, Double.MIN_VALUE);
|
||||
|
||||
fr = facetResults.get(3);
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(2.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(2.0, parentRes.value, Double.MIN_VALUE);
|
||||
frn = resultNodesAsArray(parentRes);
|
||||
assertEquals(0, frn.length);
|
||||
|
||||
fr = facetResults.get(4);
|
||||
parentRes = fr.getFacetResultNode();
|
||||
assertEquals(6.0, parentRes.getValue(), Double.MIN_VALUE);
|
||||
assertEquals(6.0, parentRes.value, Double.MIN_VALUE);
|
||||
frn = resultNodesAsArray(parentRes);
|
||||
assertEquals(1.0, frn[0].getValue(), Double.MIN_VALUE);
|
||||
assertEquals(1.0, frn[0].value, Double.MIN_VALUE);
|
||||
closeAll();
|
||||
}
|
||||
}
|
||||
|
@ -172,13 +166,7 @@ public class TestTopKResultsHandler extends BaseTestTopK {
|
|||
};
|
||||
|
||||
searcher.search(new MatchAllDocsQuery(), fc);
|
||||
long start = System.currentTimeMillis();
|
||||
List<FacetResult> results = fc.getFacetResults();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
if (VERBOSE) {
|
||||
System.out.println("Time: " + (end - start));
|
||||
}
|
||||
|
||||
assertEquals("Should only be one result as there's only one request", 1, results.size());
|
||||
FacetResult res = results.get(0);
|
||||
|
@ -230,14 +218,8 @@ public class TestTopKResultsHandler extends BaseTestTopK {
|
|||
|
||||
searcher.search(new MatchAllDocsQuery(), fc);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
List<FacetResult> facetResults = fc.getFacetResults();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
if (VERBOSE) {
|
||||
System.out.println("Time: " + (end - start));
|
||||
}
|
||||
|
||||
assertEquals("Shouldn't have found anything for a FacetRequest "
|
||||
+ "of a facet that doesn't exist in the index.", 0, facetResults.size());
|
||||
|
||||
|
|
|
@ -88,15 +88,15 @@ public class TestTopKResultsHandlerRandom extends BaseTestTopK {
|
|||
int k = 0;
|
||||
for (FacetResult fr : allFacetResults) {
|
||||
FacetResultNode topResNode = fr.getFacetResultNode();
|
||||
maxNumNodes = Math.max(maxNumNodes, topResNode.getNumSubResults());
|
||||
maxNumNodes = Math.max(maxNumNodes, topResNode.subResults.size());
|
||||
int prevCount = Integer.MAX_VALUE;
|
||||
int pos = 0;
|
||||
for (FacetResultNode frn: topResNode.getSubResults()) {
|
||||
assertTrue("wrong counts order: prev="+prevCount+" curr="+frn.getValue(), prevCount>=frn.getValue());
|
||||
prevCount = (int) frn.getValue();
|
||||
String key = k+"--"+frn.getLabel()+"=="+frn.getValue();
|
||||
for (FacetResultNode frn: topResNode.subResults) {
|
||||
assertTrue("wrong counts order: prev="+prevCount+" curr="+frn.value, prevCount>=frn.value);
|
||||
prevCount = (int) frn.value;
|
||||
String key = k+"--"+frn.label+"=="+frn.value;
|
||||
if (VERBOSE) {
|
||||
System.out.println(frn.getLabel() + " - " + frn.getValue() + " "+key+" "+pos);
|
||||
System.out.println(frn.label + " - " + frn.value + " "+key+" "+pos);
|
||||
}
|
||||
all.put(key, pos++); // will use this later to verify order of sub-results
|
||||
}
|
||||
|
@ -113,12 +113,12 @@ public class TestTopKResultsHandlerRandom extends BaseTestTopK {
|
|||
k = 0;
|
||||
for (FacetResult fr : someResults) {
|
||||
FacetResultNode topResNode = fr.getFacetResultNode();
|
||||
assertTrue("too many results: n="+n+" but got "+topResNode.getNumSubResults(), n>=topResNode.getNumSubResults());
|
||||
assertTrue("too many results: n="+n+" but got "+topResNode.subResults.size(), n>=topResNode.subResults.size());
|
||||
int pos = 0;
|
||||
for (FacetResultNode frn: topResNode.getSubResults()) {
|
||||
String key = k+"--"+frn.getLabel()+"=="+frn.getValue();
|
||||
for (FacetResultNode frn: topResNode.subResults) {
|
||||
String key = k+"--"+frn.label+"=="+frn.value;
|
||||
if (VERBOSE) {
|
||||
System.out.println(frn.getLabel() + " - " + frn.getValue() + " "+key+" "+pos);
|
||||
System.out.println(frn.label + " - " + frn.value + " "+key+" "+pos);
|
||||
}
|
||||
Integer origPos = all.get(key);
|
||||
assertNotNull("missing in all results: "+frn,origPos);
|
||||
|
|
|
@ -226,9 +226,9 @@ public class TestTotalFacetCountsCache extends LuceneTestCase {
|
|||
FacetResult result = results.get(i);
|
||||
assertNotNull("Result should not be null", result);
|
||||
FacetResultNode resNode = result.getFacetResultNode();
|
||||
assertEquals("Invalid label", expLabels[i], resNode.getLabel().toString());
|
||||
assertEquals("Invalid value", expValues[i], resNode.getValue(), 0.0);
|
||||
assertEquals("Invalid number of subresults", 0, resNode.getNumSubResults());
|
||||
assertEquals("Invalid label", expLabels[i], resNode.label.toString());
|
||||
assertEquals("Invalid value", expValues[i], resNode.value, 0.0);
|
||||
assertEquals("Invalid number of subresults", 0, resNode.subResults.size());
|
||||
}
|
||||
// we're done, close the index reader and the taxonomy.
|
||||
slowIndexReader.close();
|
||||
|
|
|
@ -118,8 +118,8 @@ public class AssociationsFacetRequestTest extends LuceneTestCase {
|
|||
|
||||
assertNotNull("No results!",res);
|
||||
assertEquals("Wrong number of results!",2, res.size());
|
||||
assertEquals("Wrong count for category 'a'!",200, (int) res.get(0).getFacetResultNode().getValue());
|
||||
assertEquals("Wrong count for category 'b'!",150, (int) res.get(1).getFacetResultNode().getValue());
|
||||
assertEquals("Wrong count for category 'a'!",200, (int) res.get(0).getFacetResultNode().value);
|
||||
assertEquals("Wrong count for category 'b'!",150, (int) res.get(1).getFacetResultNode().value);
|
||||
|
||||
taxo.close();
|
||||
}
|
||||
|
@ -143,8 +143,8 @@ public class AssociationsFacetRequestTest extends LuceneTestCase {
|
|||
|
||||
assertNotNull("No results!",res);
|
||||
assertEquals("Wrong number of results!",2, res.size());
|
||||
assertEquals("Wrong count for category 'a'!",50f, (float) res.get(0).getFacetResultNode().getValue(), 0.00001);
|
||||
assertEquals("Wrong count for category 'b'!",10f, (float) res.get(1).getFacetResultNode().getValue(), 0.00001);
|
||||
assertEquals("Wrong count for category 'a'!",50f, (float) res.get(0).getFacetResultNode().value, 0.00001);
|
||||
assertEquals("Wrong count for category 'b'!",10f, (float) res.get(1).getFacetResultNode().value, 0.00001);
|
||||
|
||||
taxo.close();
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public abstract class BaseSampleTestTopK extends BaseTestTopK {
|
|||
assertSampling(expectedResults, q, sampler, samplingSearchParams, true);
|
||||
|
||||
break; // succeeded
|
||||
} catch (NotSameResultError e) {
|
||||
} catch (AssertionError e) {
|
||||
if (nTrial >= RETRIES - 1) {
|
||||
throw e; // no more retries allowed, must fail
|
||||
}
|
||||
|
|
|
@ -85,10 +85,8 @@ public class OversampleWithDepthTest extends LuceneTestCase {
|
|||
FacetResultNode rootNode = res.getFacetResultNode();
|
||||
|
||||
// Each node below root should also have sub-results as the requested depth was '2'
|
||||
for (FacetResultNode node : rootNode.getSubResults()) {
|
||||
assertTrue("node " + node.getLabel()
|
||||
+ " should have had children as the requested depth was '2'",
|
||||
node.getNumSubResults() > 0);
|
||||
for (FacetResultNode node : rootNode.subResults) {
|
||||
assertTrue("node " + node.label + " should have had children as the requested depth was '2'", node.subResults.size() > 0);
|
||||
}
|
||||
|
||||
IOUtils.close(r, tr, indexDir, taxoDir);
|
||||
|
|
|
@ -28,10 +28,8 @@ import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
|||
public class SamplingAccumulatorTest extends BaseSampleTestTopK {
|
||||
|
||||
@Override
|
||||
protected FacetsAccumulator getSamplingAccumulator(Sampler sampler,
|
||||
TaxonomyReader taxoReader, IndexReader indexReader,
|
||||
FacetSearchParams searchParams) {
|
||||
return new SamplingAccumulator(sampler, searchParams, indexReader,
|
||||
taxoReader);
|
||||
protected FacetsAccumulator getSamplingAccumulator(Sampler sampler, TaxonomyReader taxoReader,
|
||||
IndexReader indexReader, FacetSearchParams searchParams) {
|
||||
return new SamplingAccumulator(sampler, searchParams, indexReader, taxoReader);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue