Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lucene/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ Optimizations

* GITHUB#12453: Faster bulk numeric reads from BufferedIndexInput (Armin Braun)

* GITHUB#12408: Lazy initialization improvements for Facets implementations when there are segments with no hits
to count. (Greg Miller)

Bug Fixes
---------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@
public class LongValueFacetCounts extends Facets {

/** Used for all values that are < 1K. */
private final int[] counts = new int[1024];
private int[] counts;

/** Used for all values that are >= 1K. */
private final LongIntHashMap hashCounts = new LongIntHashMap();
private LongIntHashMap hashCounts;

/** Whether-or-not counters have been initialized. */
private boolean initialized;

/** Field being counted. */
private final String field;
Expand Down Expand Up @@ -125,6 +128,7 @@ public LongValueFacetCounts(String field, IndexReader reader) throws IOException
public LongValueFacetCounts(String field, LongValuesSource valueSource, IndexReader reader)
throws IOException {
this.field = field;
initializeCounters();
if (valueSource != null) {
countAll(reader, valueSource);
} else {
Expand All @@ -141,6 +145,7 @@ public LongValueFacetCounts(String field, LongValuesSource valueSource, IndexRea
public LongValueFacetCounts(String field, MultiLongValuesSource valuesSource, IndexReader reader)
throws IOException {
this.field = field;
initializeCounters();
if (valuesSource != null) {
LongValuesSource singleValued = MultiLongValuesSource.unwrapSingleton(valuesSource);
if (singleValued != null) {
Expand All @@ -153,11 +158,25 @@ public LongValueFacetCounts(String field, MultiLongValuesSource valuesSource, In
}
}

private void initializeCounters() {
if (initialized) {
return;
}
assert counts == null && hashCounts == null;
initialized = true;
counts = new int[1024];
hashCounts = new LongIntHashMap();
}

/** Counts from the provided valueSource. */
private void count(LongValuesSource valueSource, List<MatchingDocs> matchingDocs)
throws IOException {

for (MatchingDocs hits : matchingDocs) {
if (hits.totalHits == 0) {
continue;
}
initializeCounters();

LongValues fv = valueSource.getValues(hits.context, null);

Expand All @@ -183,6 +202,10 @@ private void count(LongValuesSource valueSource, List<MatchingDocs> matchingDocs
private void count(MultiLongValuesSource valuesSource, List<MatchingDocs> matchingDocs)
throws IOException {
for (MatchingDocs hits : matchingDocs) {
if (hits.totalHits == 0) {
continue;
}
initializeCounters();

MultiLongValues multiValues = valuesSource.getValues(hits.context);

Expand Down Expand Up @@ -213,6 +236,10 @@ private void count(MultiLongValuesSource valuesSource, List<MatchingDocs> matchi
/** Counts from the field's indexed doc values. */
private void count(String field, List<MatchingDocs> matchingDocs) throws IOException {
for (MatchingDocs hits : matchingDocs) {
if (hits.totalHits == 0) {
continue;
}
initializeCounters();

SortedNumericDocValues multiValues = DocValues.getSortedNumeric(hits.context.reader(), field);
NumericDocValues singleValues = DocValues.unwrapSingleton(multiValues);
Expand Down Expand Up @@ -350,6 +377,13 @@ private void increment(long value) {
@Override
public FacetResult getAllChildren(String dim, String... path) throws IOException {
validateDimAndPathForGetChildren(dim, path);

if (initialized == false) {
// nothing was counted (either no hits or no values for all hits):
assert totCount == 0;
return new FacetResult(field, new String[0], totCount, new LabelAndValue[0], 0);
}

List<LabelAndValue> labelValues = new ArrayList<>();
for (int i = 0; i < counts.length; i++) {
if (counts[i] != 0) {
Expand Down Expand Up @@ -378,6 +412,12 @@ public FacetResult getTopChildren(int topN, String dim, String... path) {
validateTopN(topN);
validateDimAndPathForGetChildren(dim, path);

if (initialized == false) {
// nothing was counted (either no hits or no values for all hits):
assert totCount == 0;
return new FacetResult(field, new String[0], totCount, new LabelAndValue[0], 0);
}

PriorityQueue<Entry> pq =
new PriorityQueue<>(Math.min(topN, counts.length + hashCounts.size())) {
@Override
Expand Down Expand Up @@ -440,6 +480,12 @@ private static class Entry {
* efficient to use {@link #getAllChildren(String, String...)}.
*/
public FacetResult getAllChildrenSortByValue() {
if (initialized == false) {
// nothing was counted (either no hits or no values for all hits):
assert totCount == 0;
return new FacetResult(field, new String[0], totCount, new LabelAndValue[0], 0);
}

List<LabelAndValue> labelValues = new ArrayList<>();

// compact & sort hash table's arrays by value
Expand Down Expand Up @@ -533,27 +579,29 @@ public String toString() {
StringBuilder b = new StringBuilder();
b.append("LongValueFacetCounts totCount=");
b.append(totCount);
b.append(":\n");
for (int i = 0; i < counts.length; i++) {
if (counts[i] != 0) {
b.append(" ");
b.append(i);
b.append(" -> count=");
b.append(counts[i]);
b.append('\n');
}
}

if (hashCounts.size() != 0) {
for (LongIntCursor c : hashCounts) {
if (c.value != 0) {
if (initialized) {
b.append(":\n");
for (int i = 0; i < counts.length; i++) {
if (counts[i] != 0) {
b.append(" ");
b.append(c.key);
b.append(i);
b.append(" -> count=");
b.append(c.value);
b.append(counts[i]);
b.append('\n');
}
}

if (hashCounts.size() != 0) {
for (LongIntCursor c : hashCounts) {
if (c.value != 0) {
b.append(" ");
b.append(c.key);
b.append(" -> count=");
b.append(c.value);
b.append('\n');
}
}
}
}

return b.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ public class StringValueFacetCounts extends Facets {
private final OrdinalMap ordinalMap;
private final SortedSetDocValues docValues;

private final int[] denseCounts;
private int[] denseCounts;
private final IntIntHashMap sparseCounts;
private boolean initialized;

private final int cardinality;
private int totalDocCount;
Expand Down Expand Up @@ -101,7 +102,9 @@ public StringValueFacetCounts(StringDocValuesReaderState state, FacetsCollector
if (facetsCollector != null) {
if (cardinality < 1024) { // count densely for low cardinality
sparseCounts = null;
denseCounts = new int[cardinality];
denseCounts = null;
initialized = false;
count(facetsCollector);
} else {
int totalHits = 0;
int totalDocs = 0;
Expand All @@ -110,22 +113,31 @@ public StringValueFacetCounts(StringDocValuesReaderState state, FacetsCollector
totalDocs += matchingDocs.context.reader().maxDoc();
}

// If our result set is < 10% of the index, we collect sparsely (use hash map). This
// heuristic is borrowed from IntTaxonomyFacetCounts:
if (totalHits < totalDocs / 10) {
sparseCounts = new IntIntHashMap();
// No counting needed if there are no hits:
if (totalHits == 0) {
sparseCounts = null;
denseCounts = null;
initialized = true;
} else {
sparseCounts = null;
denseCounts = new int[cardinality];
// If our result set is < 10% of the index, we collect sparsely (use hash map). This
// heuristic is borrowed from IntTaxonomyFacetCounts:
if (totalHits < totalDocs / 10) {
sparseCounts = new IntIntHashMap();
denseCounts = null;
initialized = true;
} else {
sparseCounts = null;
denseCounts = new int[cardinality];
initialized = true;
}
count(facetsCollector);
}
}

count(facetsCollector);
} else {
// Since we're counting all ordinals, count densely:
sparseCounts = null;
denseCounts = new int[cardinality];
initialized = true;

countAll();
}
Expand Down Expand Up @@ -294,6 +306,9 @@ private void count(FacetsCollector facetsCollector) throws IOException {
if (matchingDocs.size() == 1) {

FacetsCollector.MatchingDocs hits = matchingDocs.get(0);
if (hits.totalHits == 0) {
return;
}

// Validate state before doing anything else:
validateState(hits.context);
Expand All @@ -314,6 +329,10 @@ private void count(FacetsCollector facetsCollector) throws IOException {
assert ordinalMap != null;
assert docValues instanceof MultiDocValues.MultiSortedSetDocValues;

if (hits.totalHits == 0) {
continue;
}

MultiDocValues.MultiSortedSetDocValues multiValues =
(MultiDocValues.MultiSortedSetDocValues) docValues;

Expand Down Expand Up @@ -368,6 +387,13 @@ private void countOneSegment(
FacetsCollector.MatchingDocs hits,
Bits liveDocs)
throws IOException {
if (initialized == false) {
assert denseCounts == null && sparseCounts == null;
// If the counters weren't initialized, we can assume the cardinality is low enough that
// dense counting will be preferrable:
denseCounts = new int[cardinality];
initialized = true;
}

// It's slightly more efficient to work against SortedDocValues if the field is actually
// single-valued (see: LUCENE-5309)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,20 +157,25 @@ public DoubleRangeFacetCounts(
private void count(DoubleValuesSource valueSource, List<MatchingDocs> matchingDocs)
throws IOException {

LongRange[] longRanges = getLongRanges();

LongRangeCounter counter = LongRangeCounter.create(longRanges, counts);

LongRangeCounter counter = null;
int missingCount = 0;
for (MatchingDocs hits : matchingDocs) {
DoubleValues fv = valueSource.getValues(hits.context, null);
totCount += hits.totalHits;
if (hits.totalHits == 0) {
continue;
}

final DocIdSetIterator it = createIterator(hits);
if (it == null) {
continue;
}

if (counter == null) {
counter = setupCounter();
}

DoubleValues fv = valueSource.getValues(hits.context, null);
totCount += hits.totalHits;

for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
// Skip missing docs:
if (fv.advanceExact(doc)) {
Expand All @@ -183,27 +188,34 @@ private void count(DoubleValuesSource valueSource, List<MatchingDocs> matchingDo
}
}

missingCount += counter.finish();
totCount -= missingCount;
if (counter != null) {
missingCount += counter.finish();
totCount -= missingCount;
}
}

/** Counts from the provided valueSource. */
private void count(MultiDoubleValuesSource valueSource, List<MatchingDocs> matchingDocs)
throws IOException {

LongRange[] longRanges = getLongRanges();

LongRangeCounter counter = LongRangeCounter.create(longRanges, counts);

LongRangeCounter counter = null; // LongRangeCounter.create(longRanges, counts);
int missingCount = 0;
for (MatchingDocs hits : matchingDocs) {
MultiDoubleValues multiValues = valueSource.getValues(hits.context);
if (hits.totalHits == 0) {
continue;
}

final DocIdSetIterator it = createIterator(hits);
if (it == null) {
continue;
}

if (counter == null) {
counter = setupCounter();
}

MultiDoubleValues multiValues = valueSource.getValues(hits.context);

for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
// Skip missing docs:
if (multiValues.advanceExact(doc)) {
Expand Down Expand Up @@ -232,8 +244,10 @@ private void count(MultiDoubleValuesSource valueSource, List<MatchingDocs> match
}
}

missingCount += counter.finish();
totCount -= missingCount;
if (counter != null) {
missingCount += counter.finish();
totCount -= missingCount;
}
}

/** Create long ranges from the double ranges. */
Expand Down
Loading