20
20
21
21
package org .exist .xquery .modules .lucene ;
22
22
23
+ import org .apache .lucene .facet .DrillDownQuery ;
24
+ import org .apache .lucene .facet .FacetsConfig ;
23
25
import org .apache .lucene .queryparser .classic .QueryParser ;
24
26
import org .apache .lucene .queryparser .classic .QueryParserBase ;
25
27
import org .apache .lucene .queryparser .flexible .standard .CommonQueryParserConfiguration ;
26
28
import org .apache .lucene .search .MultiTermQuery ;
29
+ import org .apache .lucene .search .Query ;
27
30
import org .exist .numbering .NodeId ;
28
31
import org .exist .stax .ExtendedXMLStreamReader ;
29
32
import org .exist .xquery .XPathException ;
30
33
import org .exist .xquery .XQueryContext ;
34
+ import org .exist .xquery .functions .array .ArrayType ;
31
35
import org .exist .xquery .functions .map .AbstractMapType ;
32
36
import org .exist .xquery .value .*;
33
37
@@ -61,7 +65,7 @@ protected enum DefaultOperator {
61
65
62
66
protected boolean filterRewrite = false ;
63
67
protected boolean lowercaseExpandedTerms = false ;
64
- protected Optional <Map <String , List < String > >> facets = Optional .empty ();
68
+ protected Optional <Map <String , FacetQuery >> facets = Optional .empty ();
65
69
protected Set <String > fields = null ;
66
70
67
71
public QueryOptions () {
@@ -101,11 +105,16 @@ public QueryOptions(AbstractMapType map) throws XPathException {
101
105
fields .add (i .nextItem ().getStringValue ());
102
106
}
103
107
} else if (key .equals (OPTION_FACETS ) && entry .getValue ().hasOne () && entry .getValue ().getItemType () == Type .MAP ) {
104
- final Map <String , List <String >> tf = new HashMap <>();
108
+ // map to hold the facet values for each dimension
109
+ final Map <String , FacetQuery > tf = new HashMap <>();
110
+ // iterate over each dimension and collect its values into a FacetQuery
105
111
for (Map .Entry <AtomicValue , Sequence > facet : (AbstractMapType ) entry .getValue ().itemAt (0 )) {
106
- final List <String > values = new ArrayList <>(5 );
107
- for (SequenceIterator si = facet .getValue ().unorderedIterator (); si .hasNext (); ) {
108
- values .add (si .nextItem ().getStringValue ());
112
+ final Sequence value = facet .getValue ();
113
+ FacetQuery values ;
114
+ if (value .hasOne () && value .getItemType () == Type .ARRAY ) {
115
+ values = new FacetQuery ((ArrayType ) facet .getValue ().itemAt (0 ));
116
+ } else {
117
+ values = new FacetQuery (value );
109
118
}
110
119
tf .put (facet .getKey ().getStringValue (), values );
111
120
}
@@ -116,7 +125,76 @@ public QueryOptions(AbstractMapType map) throws XPathException {
116
125
}
117
126
}
118
127
119
- public Optional <Map <String , List <String >>> getFacets () {
128
+ /**
129
+ * Holds the values of a facet for drill down. To support
130
+ * multiple query values for a hierarchical facet, values are
131
+ * kept in a two-dimensional list.
132
+ */
133
+ public static class FacetQuery {
134
+ final List <List <String >> values ;
135
+
136
+ /**
137
+ * Create a single query value from a flat sequence.
138
+ *
139
+ * @param input input sequence
140
+ * @throws XPathException in case of conversion errors
141
+ */
142
+ public FacetQuery (final Sequence input ) throws XPathException {
143
+ values = new ArrayList <>(1 );
144
+ List <String > subValues = new ArrayList <>(input .getItemCount ());
145
+ for (SequenceIterator si = input .unorderedIterator (); si .hasNext (); ) {
146
+ final String value = si .nextItem ().getStringValue ();
147
+ if (value .length () > 0 ) {
148
+ subValues .add (value );
149
+ }
150
+ }
151
+ values .add (subValues );
152
+ }
153
+
154
+ /**
155
+ * Create a multi-valued query from an XQuery array.
156
+ *
157
+ * @param input an XQuery array
158
+ * @throws XPathException in case of conversion errors
159
+ */
160
+ public FacetQuery (final ArrayType input ) throws XPathException {
161
+ final Sequence items [] = input .toArray ();
162
+ values = new ArrayList <>(items .length );
163
+ for (Sequence seq : items ) {
164
+ final List <String > subValues = new ArrayList <>(seq .getItemCount ());
165
+ for (SequenceIterator si = seq .unorderedIterator (); si .hasNext (); ) {
166
+ final String value = si .nextItem ().getStringValue ();
167
+ if (value .length () > 0 ) {
168
+ subValues .add (value );
169
+ }
170
+ }
171
+ values .add (subValues );
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Add the values for the facet dimension to the drill down query.
177
+ *
178
+ * @param dimension the facet dimension
179
+ * @param query the lucene drill down query
180
+ * @param hierarchical true if the facet is hierarchical
181
+ */
182
+ public void toQuery (final String dimension , final DrillDownQuery query , final boolean hierarchical ) {
183
+ for (List <String > subValues : values ) {
184
+ if (hierarchical ) {
185
+ final String [] result = new String [subValues .size ()];
186
+ subValues .toArray (result );
187
+ query .add (dimension , result );
188
+ } else {
189
+ for (String value : subValues ) {
190
+ query .add (dimension , value );
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ public Optional <Map <String , FacetQuery >> getFacets () {
120
198
return facets ;
121
199
}
122
200
0 commit comments