From 8b832b982a0f9c33dca5a9a1b4619cb32982dba3 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Tue, 17 May 2022 22:38:40 -0400 Subject: [PATCH] change stat facets to allow the sum of a facet to be zero (#69) * change stat facets to allow the sum of a facet to be zero or negative --- .../server/search/TaxonomyStatsHandler.java | 22 ++++++------- .../io/zulia/server/test/node/StatTest.java | 32 ++++++++++++++++++- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/zulia-server/src/main/java/io/zulia/server/search/TaxonomyStatsHandler.java b/zulia-server/src/main/java/io/zulia/server/search/TaxonomyStatsHandler.java index 41a68f3f..446919cd 100644 --- a/zulia-server/src/main/java/io/zulia/server/search/TaxonomyStatsHandler.java +++ b/zulia-server/src/main/java/io/zulia/server/search/TaxonomyStatsHandler.java @@ -259,18 +259,14 @@ public List getTopChildren(String field, int topN, String int ord = children[dimOrd]; - double doubleSumValues = 0; - double doubleBottomValue = 0; - - long longSumValues = 0; - long longBottomValue = 0; + double doubleBottomValue = Double.NEGATIVE_INFINITY; + long longBottomValue = Long.MIN_VALUE; while (ord != TaxonomyReader.INVALID_ORDINAL) { Stats stat = stats[ord]; if (stat != null) { stat.ordinal = ord; - if (stat.doubleSum > 0) { - doubleSumValues += stat.doubleSum; + if (stat.isFloatingPoint()) { if (stat.doubleSum > doubleBottomValue) { q.insertWithOverflow(stat); if (q.size() == topN) { @@ -278,8 +274,7 @@ public List getTopChildren(String field, int topN, String } } } - else if (stat.longSum > 0) { - longSumValues += stat.longSum; + else { if (stat.longSum > longBottomValue) { q.insertWithOverflow(stat); if (q.size() == topN) { @@ -292,9 +287,6 @@ else if (stat.longSum > 0) { ord = siblings[ord]; } - if (doubleSumValues == 0 && longSumValues == 0) { - return null; - } ZuliaQuery.FacetStats[] facetStats = new ZuliaQuery.FacetStats[q.size()]; for (int i = facetStats.length - 1; i >= 0; i--) { @@ -339,6 +331,7 @@ else if (a.doubleSum > b.doubleSum || a.longSum > b.longSum) { public static class Stats { + private final boolean floatingPoint; private int ordinal; private long docCount; private long allDocCount; @@ -361,6 +354,7 @@ public Stats(boolean floatingPoint) { doubleMinValue = 0; doubleMaxValue = 0; } + this.floatingPoint = floatingPoint; } public void newDoc(boolean countNonNull) { @@ -391,6 +385,10 @@ public void newValue(long newValue) { } this.valueCount++; } + + public boolean isFloatingPoint() { + return floatingPoint; + } } } diff --git a/zulia-server/src/test/java/io/zulia/server/test/node/StatTest.java b/zulia-server/src/test/java/io/zulia/server/test/node/StatTest.java index 65685f99..7f72ce39 100644 --- a/zulia-server/src/test/java/io/zulia/server/test/node/StatTest.java +++ b/zulia-server/src/test/java/io/zulia/server/test/node/StatTest.java @@ -70,7 +70,7 @@ public void index() throws Exception { indexRecord(i * uniqueDocs + 3, "something special", "top2/middle/bottom3", "bar", 2, List.of(0.5)); indexRecord(i * uniqueDocs + 4, "something really special", "top3/middle/bottom4", "bar", 5, List.of(3.0)); indexRecord(i * uniqueDocs + 5, "something really special", "top3/middle/bottom4", null, 4, List.of()); - indexRecord(i * uniqueDocs + 6, "boring", "top4/middle/bottom5", "other", 1, List.of()); + indexRecord(i * uniqueDocs + 6, "boring", "top4/middle/bottom5", "other", 1, List.of(0.0)); } } @@ -132,6 +132,18 @@ public void statTest() throws Exception { Assertions.assertThrows(Exception.class, () -> zuliaWorkPool.search(finalSearch), "Expecting: Search: Numeric field must be indexed as a SORTABLE numeric field"); + search = new Search(STAT_TEST_INDEX); + search.addStat(new StatFacet("rating", "normalFacet")); + search.addQuery(new FilterQuery("title:boring")); + searchResult = zuliaWorkPool.search(search); + Assertions.assertEquals(repeatCount, searchResult.getTotalHits()); + List ratingByFacet = searchResult.getFacetFieldStat("rating", "normalFacet"); + Assertions.assertEquals(1, ratingByFacet.size()); + Assertions.assertEquals(repeatCount, ratingByFacet.get(0).getDocCount()); + Assertions.assertEquals(0, ratingByFacet.get(0).getMin().getDoubleValue()); + Assertions.assertEquals(0, ratingByFacet.get(0).getMax().getDoubleValue()); + Assertions.assertEquals(0, ratingByFacet.get(0).getSum().getDoubleValue()); + } private void ratingTest(FacetStats ratingStat) { @@ -279,6 +291,24 @@ public void confirm() throws Exception { authorCountPathFacetTest(searchResult); ratingNormalTest(searchResult); ratingPathTest(searchResult); + + + search = new Search(STAT_TEST_INDEX); + search.addStat(new StatFacet("rating", "pathFacet")); + search.addQuery(new FilterQuery("\"something really special\"").addQueryField("title")); + search.addQuery(new FilterQuery("authorCount:[4 TO 4.1]")); + search.addQuery(new FilterQuery("rating:[2 TO 3]").exclude()); + searchResult = zuliaWorkPool.search(search); + Assertions.assertEquals(repeatCount, searchResult.getTotalHits()); + List ratingByFacet = searchResult.getFacetFieldStat("rating", "pathFacet"); + Assertions.assertEquals(1, ratingByFacet.size()); + Assertions.assertEquals(0, ratingByFacet.get(0).getDocCount()); //No docs have values for rating that match even though there are facets for pathFacet + System.err.println(ratingByFacet.get(0).getMin().getDoubleValue()); + System.err.println(ratingByFacet.get(0).getMax().getDoubleValue()); + System.err.println(ratingByFacet.get(0).getSum().getDoubleValue()); + Assertions.assertEquals(Double.POSITIVE_INFINITY, ratingByFacet.get(0).getMin().getDoubleValue(), 0.001); // Positive Infinity for Min when no values found + Assertions.assertEquals(Double.NEGATIVE_INFINITY, ratingByFacet.get(0).getMax().getDoubleValue(), 0.001); // Negative Infinity for Max when no values found + Assertions.assertEquals(0, ratingByFacet.get(0).getSum().getDoubleValue(), 0.001); } private void authorCountPathFacetTest(SearchResult searchResult) {