Index: lucene/CHANGES.txt =================================================================== --- lucene/CHANGES.txt (revision 1508180) +++ lucene/CHANGES.txt (working copy) @@ -95,6 +95,9 @@ * LUCENE-5132: Spatial RecursivePrefixTree Contains predicate will throw an NPE when there's no indexed data and maybe in other circumstances too. (David Smiley) +* LUCENE-5151: Associations FacetsAggregators could enter an infinite loop when + some result documents were missing category associations. (Shai Erera) + API Changes * LUCENE-5094: Add ramBytesUsed() to MultiDocValues.OrdinalMap. Index: lucene/facet/src/java/org/apache/lucene/facet/associations/SumFloatAssociationFacetsAggregator.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/associations/SumFloatAssociationFacetsAggregator.java (revision 1508180) +++ lucene/facet/src/java/org/apache/lucene/facet/associations/SumFloatAssociationFacetsAggregator.java (working copy) @@ -54,23 +54,20 @@ int doc = 0; while (doc < length && (doc = matchingDocs.bits.nextSetBit(doc)) != -1) { dv.get(doc, bytes); - if (bytes.length == 0) { - continue; // no associations for this document + if (bytes.length > 0) { + // aggreate float association values for ordinals + int bytesUpto = bytes.offset + bytes.length; + int pos = bytes.offset; + while (pos < bytesUpto) { + int ordinal = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) + | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); + + int value = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) + | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); + + values[ordinal] += Float.intBitsToFloat(value); + } } - - // aggreate float association values for ordinals - int bytesUpto = bytes.offset + bytes.length; - int pos = bytes.offset; - while (pos < bytesUpto) { - int ordinal = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) - | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); - - int value = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) - | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); - - values[ordinal] += Float.intBitsToFloat(value); - } - ++doc; } } Index: lucene/facet/src/java/org/apache/lucene/facet/associations/SumIntAssociationFacetsAggregator.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/associations/SumIntAssociationFacetsAggregator.java (revision 1508180) +++ lucene/facet/src/java/org/apache/lucene/facet/associations/SumIntAssociationFacetsAggregator.java (working copy) @@ -53,23 +53,20 @@ int doc = 0; while (doc < length && (doc = matchingDocs.bits.nextSetBit(doc)) != -1) { dv.get(doc, bytes); - if (bytes.length == 0) { - continue; // no associations for this document + if (bytes.length > 0) { + // aggreate association values for ordinals + int bytesUpto = bytes.offset + bytes.length; + int pos = bytes.offset; + while (pos < bytesUpto) { + int ordinal = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) + | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); + + int value = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) + | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); + + values[ordinal] += value; + } } - - // aggreate association values for ordinals - int bytesUpto = bytes.offset + bytes.length; - int pos = bytes.offset; - while (pos < bytesUpto) { - int ordinal = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) - | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); - - int value = ((bytes.bytes[pos++] & 0xFF) << 24) | ((bytes.bytes[pos++] & 0xFF) << 16) - | ((bytes.bytes[pos++] & 0xFF) << 8) | (bytes.bytes[pos++] & 0xFF); - - values[ordinal] += value; - } - ++doc; } } Index: lucene/facet/src/test/org/apache/lucene/facet/associations/AssociationsFacetRequestTest.java =================================================================== --- lucene/facet/src/test/org/apache/lucene/facet/associations/AssociationsFacetRequestTest.java (revision 1508180) +++ lucene/facet/src/test/org/apache/lucene/facet/associations/AssociationsFacetRequestTest.java (working copy) @@ -67,14 +67,18 @@ AssociationsFacetFields assocFacetFields = new AssociationsFacetFields(taxoWriter); // index documents, 50% have only 'b' and all have 'a' - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 110; i++) { Document doc = new Document(); CategoryAssociationsContainer associations = new CategoryAssociationsContainer(); - associations.setAssociation(aint, new CategoryIntAssociation(2)); - associations.setAssociation(afloat, new CategoryFloatAssociation(0.5f)); - if (i % 2 == 0) { // 50 - associations.setAssociation(bint, new CategoryIntAssociation(3)); - associations.setAssociation(bfloat, new CategoryFloatAssociation(0.2f)); + // every 11th document is added empty, this used to cause the association + // aggregators to go into an infinite loop + if (i % 11 != 0) { + associations.setAssociation(aint, new CategoryIntAssociation(2)); + associations.setAssociation(afloat, new CategoryFloatAssociation(0.5f)); + if (i % 2 == 0) { // 50 + associations.setAssociation(bint, new CategoryIntAssociation(3)); + associations.setAssociation(bfloat, new CategoryFloatAssociation(0.2f)); + } } assocFacetFields.addFields(doc, associations); writer.addDocument(doc); @@ -185,6 +189,6 @@ assertEquals("Wrong count for category 'b'!",10f, (float) res.get(3).getFacetResultNode().value, 0.00001); taxo.close(); - } + } }