Skip to content

Commit 8189035

Browse files
committed
[feature] Extend hierarchical facets to accept multiple values passed in via an array.
1 parent da8e6bf commit 8189035

File tree

3 files changed

+88
-9
lines changed

3 files changed

+88
-9
lines changed

extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/LuceneFacetConfig.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@
2929
import org.exist.storage.DBBroker;
3030
import org.exist.util.DatabaseConfigurationException;
3131
import org.exist.xquery.XPathException;
32+
import org.exist.xquery.functions.array.ArrayType;
3233
import org.exist.xquery.value.Sequence;
3334
import org.exist.xquery.value.SequenceIterator;
35+
import org.exist.xquery.value.Type;
3436
import org.w3c.dom.Element;
3537

3638
import javax.annotation.Nonnull;
39+
import java.util.ArrayList;
40+
import java.util.List;
3741
import java.util.Map;
3842

3943
/**
@@ -62,7 +66,7 @@ public LuceneFacetConfig(LuceneConfig config, Element configElement, Map<String,
6266
(hierarchicalOpt.equalsIgnoreCase("true") || hierarchicalOpt.equalsIgnoreCase("yes"));
6367

6468
config.facetsConfig.setHierarchical(dimension, isHierarchical);
65-
config.facetsConfig.setMultiValued(dimension, !isHierarchical);
69+
config.facetsConfig.setMultiValued(dimension, true);
6670
}
6771

6872
@Nonnull
@@ -71,17 +75,19 @@ public String getDimension() {
7175
}
7276

7377
@Override
74-
protected void processResult(Sequence result, Document luceneDoc) throws XPathException {
78+
protected void processResult(final Sequence result, final Document luceneDoc) throws XPathException {
7579
if (isHierarchical) {
76-
String paths[] = new String[result.getItemCount()];
77-
int j = 0;
78-
for (SequenceIterator i = result.unorderedIterator(); i.hasNext(); j++) {
79-
final String value = i.nextItem().getStringValue();
80-
if (value.length() > 0) {
81-
paths[j] = value;
80+
// hierarchical facets may be multi-valued, so if we receive an array,
81+
// create one hierarchical facet for each member
82+
if (result.hasOne() && result.getItemType() == Type.ARRAY) {
83+
final ArrayType array = (ArrayType) result.itemAt(0);
84+
for (Sequence seq : array.toArray()) {
85+
createHierarchicalFacet(luceneDoc, seq);
8286
}
87+
} else {
88+
// otherwise create a single hierarchical facet
89+
createHierarchicalFacet(luceneDoc, result);
8390
}
84-
luceneDoc.add(new FacetField(dimension, paths));
8591
} else {
8692
for (SequenceIterator i = result.unorderedIterator(); i.hasNext(); ) {
8793
final String value = i.nextItem().getStringValue();
@@ -92,6 +98,19 @@ protected void processResult(Sequence result, Document luceneDoc) throws XPathEx
9298
}
9399
}
94100

101+
private void createHierarchicalFacet(Document luceneDoc, Sequence seq) throws XPathException {
102+
final List<String> paths = new ArrayList<>(seq.getItemCount());
103+
for (SequenceIterator i = seq.unorderedIterator(); i.hasNext(); ) {
104+
final String value = i.nextItem().getStringValue();
105+
if (value.length() > 0) {
106+
paths.add(value);
107+
}
108+
}
109+
if (!paths.isEmpty()) {
110+
luceneDoc.add(new FacetField(dimension, paths.toArray(new String[0])));
111+
}
112+
}
113+
95114
@Override
96115
protected void processText(CharSequence text, Document luceneDoc) {
97116
if (text.length() > 0) {

extensions/indexes/lucene/src/test/resources-filtered/conf.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@
740740

741741
<!-- Needed for XQSuite! -->
742742
<module uri="http://www.w3.org/2005/xpath-functions/map" class="org.exist.xquery.functions.map.MapModule" />
743+
<module uri="http://www.w3.org/2005/xpath-functions/array" class="org.exist.xquery.functions.array.ArrayModule" />
743744
<module uri="http://exist-db.org/xquery/inspection" class="org.exist.xquery.functions.inspect.InspectionModule"/>
744745
<module uri="http://exist-db.org/xquery/response" class="org.exist.xquery.functions.response.ResponseModule" />
745746
<module uri="http://exist-db.org/xquery/system" class="org.exist.xquery.functions.system.SystemModule" />

extensions/indexes/lucene/src/test/xquery/lucene/facets.xql

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ declare variable $facet:XML :=
1414
<time>14:22:19.329+01:00</time>
1515
<likes>9</likes>
1616
<score>6.0</score>
17+
<subject>art</subject>
1718
</letter>
1819
<letter>
1920
<from>Rudi</from>
@@ -23,6 +24,7 @@ declare variable $facet:XML :=
2324
<time>15:22:19.329+01:00</time>
2425
<likes>19</likes>
2526
<score>8.25</score>
27+
<subject>history</subject>
2628
</letter>
2729
<letter>
2830
<from>Susi</from>
@@ -31,6 +33,8 @@ declare variable $facet:XML :=
3133
<date>2019-04-01</date>
3234
<likes>29</likes>
3335
<score>16.5</score>
36+
<subject>engineering</subject>
37+
<subject>history</subject>
3438
</letter>
3539
<letter>
3640
<from>Heinz</from>
@@ -39,6 +43,7 @@ declare variable $facet:XML :=
3943
<date>2017-03-11</date>
4044
<likes>1</likes>
4145
<score>14.25</score>
46+
<subject>history</subject>
4247
</letter>
4348
<letter>
4449
<from>Heinz</from>
@@ -47,13 +52,15 @@ declare variable $facet:XML :=
4752
<date>2015-06-22</date>
4853
<likes>5</likes>
4954
<score>29.50</score>
55+
<subject>history</subject>
5056
</letter>
5157
<letter>
5258
<from>Heinz</from>
5359
<to>Basia Kowalska</to>
5460
<place>Wrocław</place>
5561
<date>2013-06-22</date>
5662
<likes>3</likes>
63+
<subject>history</subject>
5764
<score>16.0</score>
5865
</letter>
5966
</letters>;
@@ -70,6 +77,19 @@ declare variable $facet:TAXONOMY :=
7077
</place>
7178
</places>;
7279

80+
declare variable $facet:SUBJECT :=
81+
<subject>
82+
<subject name="science">
83+
<subject name="math"/>
84+
<subject name="engineering"/>
85+
</subject>
86+
<subject name="humanities">
87+
<subject name="art"/>
88+
<subject name="sociology"/>
89+
<subject name="history"/>
90+
</subject>
91+
</subject>;
92+
7393
declare variable $facet:DOCUMENTS :=
7494
<documents>
7595
<document id="D-37/2">
@@ -110,6 +130,15 @@ declare variable $facet:MODULE :=
110130
else
111131
()
112132
};
133+
134+
declare function idx:subject-hierarchy($key as xs:string*) {
135+
if (exists($key)) then
136+
array:for-each(array {$key}, function($k) {
137+
doc('/db/lucenetest/subjects.xml')//subject[@name=$k]/ancestor-or-self::subject/@name
138+
})
139+
else
140+
()
141+
};
113142
]``;
114143

115144
declare variable $facet:XCONF1 :=
@@ -124,6 +153,7 @@ declare variable $facet:XCONF1 :=
124153
<text qname="letter" analyzer="nodiacritics">
125154
<facet dimension="place" expression="place"/>
126155
<facet dimension="location" expression="idx:place-hierarchy(place)" hierarchical="yes"/>
156+
<facet dimension="subject" expression="idx:subject-hierarchy(subject)" hierarchical="yes"/>
127157
<facet dimension="from" expression="from"/>
128158
<facet dimension="to" expression="to"/>
129159
<facet dimension="date" expression="tokenize(date, '-')" hierarchical="yes"/>
@@ -164,6 +194,7 @@ function facet:setup() {
164194
xmldb:store($testCol, "module.xql", $facet:MODULE, "application/xquery"),
165195
xmldb:store($confCol, "collection.xconf", $facet:XCONF1),
166196
xmldb:store($testCol, "places.xml", $facet:TAXONOMY),
197+
xmldb:store($testCol, "subjects.xml", $facet:SUBJECT),
167198
xmldb:store($testCol, "test.xml", $facet:XML),
168199
xmldb:store($testCol, "documents.xml", $facet:DOCUMENTS),
169200
xmldb:store($testCol, "multi-lang.xml", $facet:MULTI_LANGUAGE)
@@ -294,6 +325,34 @@ function facet:hierarchical-place() {
294325
)
295326
};
296327

328+
declare
329+
%test:assertEquals('{"art":1,"history":5}','{"engineering":1}')
330+
function facet:hierarchical-subject() {
331+
let $result := collection("/db/lucenetest")//letter[ft:query(., ())]
332+
let $facets := ft:facets($result, "subject", 10) (: Returns facet counts for "science" and "humanities" :)
333+
for $topic in map:keys($facets)
334+
order by $topic
335+
return
336+
serialize(
337+
ft:facets($result, "subject", 10, $topic), (: Get facet counts for sub-categories :)
338+
map { "method": "json" }
339+
)
340+
};
341+
342+
declare
343+
%test:assertEquals('{"history":1}','{"engineering":1}')
344+
function facet:hierarchical-multivalue-subject() {
345+
let $result := collection("/db/lucenetest")//letter[ft:query(., 'from:susi')]
346+
let $facets := ft:facets($result, "subject", 10) (: Returns facet counts for "science" and "humanities" :)
347+
for $topic in map:keys($facets)
348+
order by $topic
349+
return
350+
serialize(
351+
ft:facets($result, "subject", 10, $topic), (: Get facet counts for sub-categories :)
352+
map { "method": "json" }
353+
)
354+
};
355+
297356
declare
298357
%test:args("place:hamburg")
299358
%test:assertEquals(1)

0 commit comments

Comments
 (0)