Author: catholicon
Date: Fri Nov 23 09:27:31 2018
New Revision: 1847231
URL: http://svn.apache.org/viewvc?rev=1847231&view=rev
Log:
OAK-7898: Facet queries with UNION should do trivial merge of facets from
sub-queries (backport r1846617 from trunk)
Added:
jackrabbit/oak/branches/1.8/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ResultRowImplTest.java
- copied unchanged from r1846617,
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ResultRowImplTest.java
Modified:
jackrabbit/oak/branches/1.8/ (props changed)
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
jackrabbit/oak/branches/1.8/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/FacetResult.java
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/package-info.java
jackrabbit/oak/branches/1.8/oak-query-spi/src/test/java/org/apache/jackrabbit/oak/query/facet/FacetResultTest.java
Propchange: jackrabbit/oak/branches/1.8/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Nov 23 09:27:31 2018
@@ -1,3 +1,3 @@
/jackrabbit/oak/branches/1.0:1665962
-/jackrabbit/oak/trunk:1820660-1820661,1820729,1820734,1820859,1820861,1820878,1820888,1820947,1821027,1821130,1821140-1821141,1821178,1821237,1821240,1821249,1821258,1821325,1821358,1821361-1821362,1821370,1821375,1821393,1821477,1821487,1821516,1821617,1821663,1821665,1821668,1821681,1821847,1821975-1821983,1822121,1822201,1822207,1822527,1822642,1822723,1822808,1822850,1822934,1823135,1823163,1823169,1823172,1823655,1823669,1824196,1824198,1824253,1824255,1824896,1824962,1825065,1825362,1825381,1825442,1825448,1825466,1825470-1825471,1825475,1825523,1825525,1825561,1825619-1825621,1825651,1825654,1825992,1826079,1826090,1826096,1826216,1826237,1826338,1826516,1826532,1826551,1826560,1826638,1826640,1826730,1826833,1826932,1826957,1827423,1827472,1827486,1827816,1827977,1828349,1828439,1828502,1828529,1828948,1829527,1829534,1829546,1829569,1829587,1829665,1829854,1829864,1829978,1829985,1829987,1829998,1830019,1830048,1830160,1830171,1830197,1830209,1830239,1830347,1830748,1830911
,1830923,1831157-1831158,1831163,1831190,1831374,1831560,1831689,1832258,1832376,1832379,1832535,1833308,1833347,1833833,1834112,1834117,1834287,1834291,1834302,1834326,1834328,1834336,1834428,1834468,1834483,1834610,1834648-1834649,1834681,1834823,1834857-1834858,1835060,1835518,1835521,1835635,1835642,1835780,1835819,1836082,1836121,1836167-1836168,1836170-1836187,1836189-1836196,1836206,1836487,1836493,1837057,1837274,1837296,1837326,1837475,1837503,1837547,1837569,1837600,1837657,1837718,1837998,1838076,1838637,1839549,1839570,1839637,1839746,1840019,1840024,1840031,1840226,1840455,1840462,1840574,1841314,1841352,1842089,1842677,1843175,1843222,1843231,1843398,1843618,1843652,1843911,1844325,1844549,1844625,1844627,1844642,1844728,1844775,1844932,1845135,1845336,1845405,1845415,1845730-1845731,1845863,1845865,1846057
+/jackrabbit/oak/trunk:1820660-1820661,1820729,1820734,1820859,1820861,1820878,1820888,1820947,1821027,1821130,1821140-1821141,1821178,1821237,1821240,1821249,1821258,1821325,1821358,1821361-1821362,1821370,1821375,1821393,1821477,1821487,1821516,1821617,1821663,1821665,1821668,1821681,1821847,1821975-1821983,1822121,1822201,1822207,1822527,1822642,1822723,1822808,1822850,1822934,1823135,1823163,1823169,1823172,1823655,1823669,1824196,1824198,1824253,1824255,1824896,1824962,1825065,1825362,1825381,1825442,1825448,1825466,1825470-1825471,1825475,1825523,1825525,1825561,1825619-1825621,1825651,1825654,1825992,1826079,1826090,1826096,1826216,1826237,1826338,1826516,1826532,1826551,1826560,1826638,1826640,1826730,1826833,1826932,1826957,1827423,1827472,1827486,1827816,1827977,1828349,1828439,1828502,1828529,1828948,1829527,1829534,1829546,1829569,1829587,1829665,1829854,1829864,1829978,1829985,1829987,1829998,1830019,1830048,1830160,1830171,1830197,1830209,1830239,1830347,1830748,1830911
,1830923,1831157-1831158,1831163,1831190,1831374,1831560,1831689,1832258,1832376,1832379,1832535,1833308,1833347,1833833,1834112,1834117,1834287,1834291,1834302,1834326,1834328,1834336,1834428,1834468,1834483,1834610,1834648-1834649,1834681,1834823,1834857-1834858,1835060,1835518,1835521,1835635,1835642,1835780,1835819,1836082,1836121,1836167-1836168,1836170-1836187,1836189-1836196,1836206,1836487,1836493,1837057,1837274,1837296,1837326,1837475,1837503,1837547,1837569,1837600,1837657,1837718,1837998,1838076,1838637,1839549,1839570,1839637,1839746,1840019,1840024,1840031,1840226,1840455,1840462,1840574,1841314,1841352,1842089,1842677,1843175,1843222,1843231,1843398,1843618,1843652,1843911,1844325,1844549,1844625,1844627,1844642,1844728,1844775,1844932,1845135,1845336,1845405,1845415,1845730-1845731,1845863,1845865,1846057,1846617
/jackrabbit/trunk:1345480
Modified:
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java?rev=1847231&r1=1847230&r2=1847231&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java
(original)
+++
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java
Fri Nov 23 09:27:31 2018
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.query;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Map;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.PropertyValue;
@@ -264,4 +265,16 @@ public class ResultRowImpl implements Re
}
+ static ResultRowImpl getMappingResultRow(ResultRowImpl delegate, final
Map<String, String> columnToFacetMap) {
+ if (columnToFacetMap.size() == 0) {
+ return delegate;
+ }
+
+ PropertyValue[] mappedVals = delegate.getValues();
+ for (Map.Entry<String, String> entry : columnToFacetMap.entrySet()) {
+ mappedVals[delegate.query.getColumnIndex(entry.getKey())] =
PropertyValues.newString(entry.getValue());
+ }
+ return new ResultRowImpl(delegate.query, delegate.trees, mappedVals,
+ delegate.distinctValues, delegate.orderValues);
+ }
}
\ No newline at end of file
Modified:
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java?rev=1847231&r1=1847230&r2=1847231&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
(original)
+++
jackrabbit/oak/branches/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
Fri Nov 23 09:27:31 2018
@@ -21,22 +21,27 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Maps;
+import com.google.common.collect.PeekingIterator;
import org.apache.jackrabbit.oak.api.PropertyValue;
import org.apache.jackrabbit.oak.api.Result;
import org.apache.jackrabbit.oak.api.Result.SizePrecision;
+import org.apache.jackrabbit.oak.api.ResultRow;
import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.memory.PropertyValues;
import org.apache.jackrabbit.oak.query.QueryImpl.MeasuringIterator;
import org.apache.jackrabbit.oak.query.ast.ColumnImpl;
import org.apache.jackrabbit.oak.query.ast.OrderingImpl;
+import org.apache.jackrabbit.oak.query.facet.FacetResult;
import
org.apache.jackrabbit.oak.query.stats.QueryStatsData.QueryExecutionStats;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Maps;
-
/**
* Represents a union query.
*/
@@ -295,9 +300,11 @@ public class UnionQueryImpl implements Q
boolean distinct = !unionAll;
Comparator<ResultRowImpl> orderBy =
ResultRowImpl.getComparator(orderings);
+ FacetMerger facetMerger = new FacetMerger(left, right);
+
Iterator<ResultRowImpl> it;
- final Iterator<ResultRowImpl> leftRows = left.getRows();
- final Iterator<ResultRowImpl> rightRows = right.getRows();
+ final Iterator<ResultRowImpl> leftRows =
facetMerger.getLeftIterator();;
+ final Iterator<ResultRowImpl> rightRows =
facetMerger.getRightIterator();
Iterator<ResultRowImpl> leftIter = leftRows;
Iterator<ResultRowImpl> rightIter = rightRows;
@@ -412,4 +419,88 @@ public class UnionQueryImpl implements Q
return left.getQueryExecutionStats();
}
+ static class FacetMerger {
+
+ private final Iterator<ResultRowImpl> leftIterator;
+ private final Iterator<ResultRowImpl> rightIterator;
+
+ FacetMerger(Query left, Query right) {
+ ColumnImpl[] columns = left.getColumns();
+ String[] columnNames = new String[columns.length];
+ Arrays.setAll(columnNames, i -> columns[i].getColumnName());
+
+ Iterator<ResultRowImpl> lIter = left.getRows();
+ Iterator<ResultRowImpl> rIter = right.getRows();
+
+ if (!hasFacets(columnNames) || !bothHaveRows(lIter, rIter)) {
+ this.leftIterator = lIter;
+ this.rightIterator = rIter;
+
+ return;
+ }
+
+ PeekingIterator<ResultRowImpl> lPeekIter =
Iterators.peekingIterator(lIter);
+ PeekingIterator<ResultRowImpl> rPeekIter =
Iterators.peekingIterator(rIter);
+
+ ResultRow lRow = lPeekIter.peek();
+ ResultRow rRow = rPeekIter.peek();
+
+ FacetResult facetResult = new FacetResult(columnNames,
+ columnName -> {
+ PropertyValue value = lRow.getValue(columnName);
+ return value == null ? null :
value.getValue(Type.STRING);
+ },
+ columnName -> {
+ PropertyValue value = rRow.getValue(columnName);
+ return value == null ? null :
value.getValue(Type.STRING);
+ });
+
+ Map<String, String> columnToFacetMap =
facetResult.asColumnToFacetJsonMap();
+
+ this.leftIterator = new MappingRowIterator(columnToFacetMap,
lPeekIter);
+ this.rightIterator = new MappingRowIterator(columnToFacetMap,
rPeekIter);
+ }
+
+ Iterator<ResultRowImpl> getLeftIterator() {
+ return leftIterator;
+ }
+
+ Iterator<ResultRowImpl> getRightIterator() {
+ return rightIterator;
+ }
+
+ private boolean hasFacets(String[] columnNames) {
+ for (String c : columnNames) {
+ if (c.startsWith(QueryConstants.REP_FACET + "(")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean bothHaveRows(Iterator<ResultRowImpl> lIter,
Iterator<ResultRowImpl> rIter) {
+ return lIter.hasNext() && rIter.hasNext();
+ }
+ }
+
+ static class MappingRowIterator extends AbstractIterator<ResultRowImpl> {
+
+ private final Map<String, String> columnToFacetMap;
+ private final Iterator<ResultRowImpl> delegate;
+
+ MappingRowIterator(Map<String, String> columnToFacetMap,
Iterator<ResultRowImpl> delegate) {
+ super();
+ this.columnToFacetMap = columnToFacetMap;
+ this.delegate = delegate;
+ }
+
+ @Override
+ protected ResultRowImpl computeNext() {
+ if (delegate.hasNext()) {
+ return ResultRowImpl.getMappingResultRow(delegate.next(),
columnToFacetMap);
+ } else {
+ return endOfData();
+ }
+ }
+ }
}
Modified:
jackrabbit/oak/branches/1.8/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java?rev=1847231&r1=1847230&r2=1847231&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.8/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
(original)
+++
jackrabbit/oak/branches/1.8/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
Fri Nov 23 09:27:31 2018
@@ -29,6 +29,7 @@ import javax.jcr.query.RowIterator;
import javax.jcr.security.Privilege;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
@@ -38,6 +39,7 @@ import org.apache.jackrabbit.oak.query.f
import org.junit.After;
import org.junit.Before;
+import static com.google.common.collect.Sets.newHashSet;
import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
/**
@@ -776,6 +778,95 @@ public class FacetTest extends AbstractQ
assertEquals(2, rows.getSize());
}
+ public void testMergedFacetsOverUnionUniqueLabels() throws Exception {
+ Node n1 = testRootNode.addNode("node1");
+ n1.setProperty("text", "t1");
+ n1.setProperty("x", "x1");
+ n1.setProperty("name","Node1");
+
+ Node n2 = testRootNode.addNode("node2");
+ n2.setProperty("text", "t2");
+ n2.setProperty("x", "x2");
+ n2.setProperty("name","Node2");
+
+ Node n3 = testRootNode.addNode("node3");
+ n3.setProperty("text", "t3");
+ n3.setProperty("x", "x3");
+ n3.setProperty("name","Node3");
+ superuser.save();
+
+ String xpath = "//*[@name = 'Node1' or @text = 't2' or @x =
'x3']/(rep:facet(text))";
+
+ Query q = qm.createQuery(xpath, Query.XPATH);
+
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertEquals("Unexpected dimensions", newHashSet("text"),
facetResult.getDimensions());
+
+ List<FacetResult.Facet> facets = facetResult.getFacets("text");
+
+ Set<String> facetLabels = newHashSet();
+ for (FacetResult.Facet facet : facets) {
+ assertEquals("Unexpected facet count for " + facet.getLabel(), 1,
facet.getCount());
+ facetLabels.add(facet.getLabel());
+ }
+
+ assertEquals("Unexpected facet labels", newHashSet("t1", "t2", "t3"),
facetLabels);
+ }
+
+ public void testMergedFacetsOverUnionSummingCount() throws Exception {
+ // the distribution of nodes with t1 and t2 are intentionally across
first and second set (below)
+ // put such that second condition turns facet count around
+
+ // first set of nodes matching first condition (x1 = v1)
+ Node n11 = testRootNode.addNode("node11");
+ n11.setProperty("text", "t1");
+ n11.setProperty("x1","v1");
+ Node n12 = testRootNode.addNode("node12");
+ n12.setProperty("text", "t1");
+ n12.setProperty("x1","v1");
+ Node n13 = testRootNode.addNode("node13");
+ n13.setProperty("text", "t2");
+ n13.setProperty("x1","v1");
+
+ // second set of nodes matching second condition (x2 = v2)
+ Node n21 = testRootNode.addNode("node21");
+ n21.setProperty("text", "t2");
+ n21.setProperty("x2","v2");
+ Node n22 = testRootNode.addNode("node22");
+ n22.setProperty("text", "t1");
+ n22.setProperty("x2","v2");
+ Node n23 = testRootNode.addNode("node23");
+ n23.setProperty("text", "t1");
+ n23.setProperty("x2","v2");
+ Node n24 = testRootNode.addNode("node24");
+ n24.setProperty("text", "t1");
+ n24.setProperty("x2","v2");
+
+ superuser.save();
+
+ String xpath = "//*[@x1 = 'v1' or @x2 = 'v2']/(rep:facet(text))";
+
+ Query q = qm.createQuery(xpath, Query.XPATH);
+
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertEquals("Unexpected dimensions", newHashSet("text"),
facetResult.getDimensions());
+
+ List<FacetResult.Facet> facets = facetResult.getFacets("text");
+ assertEquals("Incorrect facet label list size", 2, facets.size());
+
+ FacetResult.Facet facet = facets.get(0);
+ assertEquals("t1", facet.getLabel());
+ assertEquals(5, facet.getCount());
+
+ facet = facets.get(1);
+ assertEquals("t2", facet.getLabel());
+ assertEquals(2, facet.getCount());
+ }
+
public Node deny(Node node) throws RepositoryException {
AccessControlUtils.deny(node, "anonymous", Privilege.JCR_ALL);
return node;
Modified:
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/FacetResult.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/FacetResult.java?rev=1847231&r1=1847230&r2=1847231&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/FacetResult.java
(original)
+++
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/FacetResult.java
Fri Nov 23 09:27:31 2018
@@ -19,21 +19,27 @@
package org.apache.jackrabbit.oak.query.facet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
+import org.apache.jackrabbit.oak.commons.json.JsopReader;
+import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
import javax.jcr.Value;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
+import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.apache.jackrabbit.oak.commons.json.JsopReader;
-import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
-import org.apache.jackrabbit.oak.spi.query.QueryConstants;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import static java.util.Collections.reverseOrder;
+import static java.util.Comparator.comparingInt;
/**
* A facet result is a wrapper for {@link javax.jcr.query.QueryResult} capable
of returning information about facets
@@ -48,25 +54,69 @@ public class FacetResult {
RowIterator rows = queryResult.getRows();
if (rows.hasNext()) {
Row row = rows.nextRow();
- for (String column : queryResult.getColumnNames()) {
- if (column.startsWith(QueryConstants.REP_FACET)) {
- String dimension =
column.substring(QueryConstants.REP_FACET.length() + 1, column.length() - 1);
- Value value = row.getValue(column);
- if (value != null) {
- String jsonFacetString = value.getString();
- parseJson(dimension, jsonFacetString);
- }
- }
- }
+ parseJson(queryResult.getColumnNames(), columnName -> {
+ Value value = row.getValue(columnName);
+ return value == null ? null : value.getString();
+ });
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public FacetResult(String[] columnNames, FacetResultRow...rows) {
+ try {
+ for (FacetResultRow row : rows) {
+ parseJson(columnNames, row);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
+ public Map<String, String> asColumnToFacetJsonMap() {
+ Map<String, String> json = Maps.newHashMap();
+ for (Map.Entry<String, List<Facet>> entry : perDimFacets.entrySet()) {
+ JsopBuilder builder = new JsopBuilder();
+ builder.object();
+
+ for (Facet f : entry.getValue()) {
+ builder.key(f.getLabel());
+ builder.value(f.getCount());
+ }
+
+ builder.endObject();
+
+ json.put(QueryConstants.REP_FACET + "(" + entry.getKey() + ")",
builder.toString());
+ }
+
+ return json;
+ }
+
+ private void parseJson(String[] columnNames, FacetResultRow row) throws
Exception {
+ for (String column : columnNames) {
+ if (column.startsWith(QueryConstants.REP_FACET)) {
+ String dimension =
column.substring(QueryConstants.REP_FACET.length() + 1, column.length() - 1);
+ String value = row.getValue(column);
+ if (value != null) {
+ String jsonFacetString = value;
+ parseJson(dimension, jsonFacetString);
+ }
+ }
+ }
+ }
+
private void parseJson(String dimension, String jsonFacetString) {
JsopTokenizer jsopTokenizer = new JsopTokenizer(jsonFacetString);
- List<Facet> facets = new LinkedList<Facet>();
+ List<Facet> facets = perDimFacets.get(dimension);
+ Map<String, Facet> facetsMap = Maps.newLinkedHashMap();
+ if (facets != null) {
+ for (Facet facet : facets) {
+ if (!facetsMap.containsKey(facet.getLabel())) {
+ facetsMap.put(facet.getLabel(), facet);
+ }
+ }
+ }
int c;
String label = null;
int count;
@@ -76,11 +126,16 @@ public class FacetResult {
} else if (JsopReader.NUMBER == c) {
count = Integer.parseInt(jsopTokenizer.getEscapedToken());
if (label != null) {
- facets.add(new Facet(label, count));
+ if (facetsMap.containsKey(label)) {
+ count += facetsMap.get(label).getCount();
+ }
+ facetsMap.put(label, new Facet(label, count));
}
label = null;
}
}
+ facets = Lists.newArrayList(facetsMap.values());
+ Collections.sort(facets, reverseOrder(comparingInt(Facet::getCount)));
perDimFacets.put(dimension, facets);
}
@@ -102,7 +157,7 @@ public class FacetResult {
private final String label;
private final int count;
- private Facet(String label, int count) {
+ Facet(String label, int count) {
this.label = label;
this.count = count;
}
@@ -124,5 +179,9 @@ public class FacetResult {
return count;
}
}
+
+ public interface FacetResultRow {
+ String getValue(String columnName) throws Exception;
+ }
}
Modified:
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/package-info.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/package-info.java?rev=1847231&r1=1847230&r2=1847231&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/package-info.java
(original)
+++
jackrabbit/oak/branches/1.8/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/query/facet/package-info.java
Fri Nov 23 09:27:31 2018
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.0.1")
+@Version("1.1.0")
package org.apache.jackrabbit.oak.query.facet;
import org.osgi.annotation.versioning.Version;
Modified:
jackrabbit/oak/branches/1.8/oak-query-spi/src/test/java/org/apache/jackrabbit/oak/query/facet/FacetResultTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.8/oak-query-spi/src/test/java/org/apache/jackrabbit/oak/query/facet/FacetResultTest.java?rev=1847231&r1=1847230&r2=1847231&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.8/oak-query-spi/src/test/java/org/apache/jackrabbit/oak/query/facet/FacetResultTest.java
(original)
+++
jackrabbit/oak/branches/1.8/oak-query-spi/src/test/java/org/apache/jackrabbit/oak/query/facet/FacetResultTest.java
Fri Nov 23 09:27:31 2018
@@ -16,16 +16,21 @@
*/
package org.apache.jackrabbit.oak.query.facet;
+import com.google.common.collect.Maps;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
+import org.apache.jackrabbit.oak.query.facet.FacetResult.Facet;
+import org.apache.jackrabbit.oak.query.facet.FacetResult.FacetResultRow;
+import org.junit.Test;
+
import javax.jcr.Value;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
+import java.util.List;
+import java.util.Map;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.apache.jackrabbit.oak.spi.query.QueryConstants.REP_FACET;
+import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -65,4 +70,142 @@ public class FacetResultTest {
assertEquals(1, facetResult.getFacets("jcr:title").get(1).getCount(),
0);
}
+ @Test
+ public void simpleMergeFacets() {
+ String r1c1Facet = json(f("l1", 2), f("l2", 1));
+ String r2c1Facet = json(f("l2", 4), f("l1", 1));
+
+ FacetResult merged = facet(new FacetColumn("x", r1c1Facet, r2c1Facet));
+
+ FacetResult expected = facet(new FacetColumn("x", json(f("l2", 5),
f("l1", 3))));
+
+ verify(expected, merged);
+ }
+
+ @Test
+ public void uniqueLabelsMergeFacets() {
+ String r1c1Facet = json(f("l1", 1));
+ String r2c1Facet = json(f("l2", 2));
+
+ FacetResult merged = facet(new FacetColumn("x", r1c1Facet, r2c1Facet));
+
+ FacetResult expected = facet(new FacetColumn("x", json(f("l2", 2),
f("l1", 1))));
+
+ verify(expected, merged);
+ }
+
+ @Test
+ public void multipleColumns() {
+ String r1c1Facet = json(f("l1", 1));
+ String r2c1Facet = json(f("l2", 2));
+
+ String r1c2Facet = json(f("m1", 2));
+ String r2c2Facet = json(f("m2", 1));
+
+ FacetResult merged = facet(
+ new FacetColumn("x", r1c1Facet, r2c1Facet),
+ new FacetColumn("y", r1c2Facet, r2c2Facet)
+ );
+
+ FacetResult expected = facet(
+ new FacetColumn("x", json(f("l2", 2), f("l1", 1))),
+ new FacetColumn("y", json(f("m1", 2), f("m2", 1)))
+ );
+
+ verify(expected, merged);
+ }
+
+ @Test
+ public void multipleColumnsWithNullColumns() {
+ String r2c1Facet = json(f("l1", 1));
+ String r1c2Facet = json(f("m1", 1));
+
+ FacetResult merged = facet(
+ new FacetColumn("x", null, r2c1Facet),
+ new FacetColumn("y", r1c2Facet, null)
+ );
+
+ FacetResult expected = facet(
+ new FacetColumn("x", json(f("l1", 1))),
+ new FacetColumn("y", json(f("m1", 1)))
+ );
+
+ verify(expected, merged);
+ }
+
+ private FacetResult facet(FacetColumn ... facetColumns) {
+ String[] colNames = new String[facetColumns.length];
+ colNames[0] = facetColumns[0].colName;
+
+ int numRows = facetColumns[0].facets.length;
+
+ for (int i = 1; i < facetColumns.length; i++) {
+ assertEquals("numRows for col num " + i + " wasn't same as first",
numRows, facetColumns[i].facets.length);
+
+ colNames[i] = facetColumns[i].colName;
+ }
+
+ FacetResultRow[] facetResultRows = new FacetResultRow[numRows];
+
+ for (int i = 0; i < numRows; i++) {
+ Map<String, String> columns = Maps.newHashMap();
+
+ for (FacetColumn col : facetColumns) {
+ columns.put(col.colName, col.facets[i]);
+ }
+
+ facetResultRows[i] = new FacetResultRow() {
+ final Map<String, String> cols = columns;
+ @Override
+ public String getValue(String columnName) {
+ return cols.get(columnName);
+ }
+ };
+ }
+
+ return new FacetResult(colNames, facetResultRows);
+ }
+
+ private static String json(Facet ... facets) {
+ JsopBuilder builder = new JsopBuilder();
+ builder.object();
+ for (Facet facet : facets) {
+ builder.key(facet.getLabel());
+ builder.value(facet.getCount());
+ }
+ builder.endObject();
+
+ return builder.toString();
+ }
+
+ private static class FacetColumn {
+ final String colName;
+ final String[] facets;
+
+ FacetColumn(String colName, String ... facets) {
+ this.colName = REP_FACET + "(" + colName + ")";
+ this.facets = facets;
+ }
+ }
+
+ private static Facet f(String label, int count) {
+ return new Facet(label, count);
+ }
+
+ private static void verify(FacetResult expected, FacetResult result) {
+ assertEquals("Dimension mismatch", expected.getDimensions(),
result.getDimensions());
+
+ for (String dim : expected.getDimensions()) {
+ List<Facet> expectedFacets = expected.getFacets(dim);
+ List<Facet> resultFacets = result.getFacets(dim);
+
+ for (int i = 0; i < expectedFacets.size(); i++) {
+ Facet expectedFacet = expectedFacets.get(i);
+ Facet resultFacet = resultFacets.get(i);
+
+ assertEquals("label mismatch for dim " + dim,
expectedFacet.getLabel(), resultFacet.getLabel());
+ assertEquals("count mismatch for dim " + dim,
expectedFacet.getCount(), resultFacet.getCount());
+ }
+ }
+ }
}
\ No newline at end of file