2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.solr.util;
20
import org.apache.solr.SolrTestCaseJ4;
21
import org.apache.solr.util.SolrPluginUtils;
22
import org.apache.solr.util.SolrPluginUtils.DisjunctionMaxQueryParser;
23
import org.apache.solr.search.SolrIndexSearcher;
24
import org.apache.solr.search.DocList;
25
import org.apache.solr.common.SolrDocument;
26
import org.apache.solr.common.SolrDocumentList;
28
import org.apache.lucene.index.Term;
29
import org.apache.lucene.search.Query;
30
import org.apache.lucene.search.TermQuery;
31
import org.apache.lucene.search.PhraseQuery;
32
import org.apache.lucene.search.DisjunctionMaxQuery;
33
import org.apache.lucene.search.BooleanQuery;
34
import org.apache.lucene.search.BooleanClause;
35
import org.apache.lucene.search.MatchAllDocsQuery;
36
import org.apache.lucene.search.BooleanClause.Occur;
37
import org.junit.BeforeClass;
38
import org.junit.Test;
40
import java.util.List;
42
import java.util.HashMap;
43
import java.util.Iterator;
45
import java.util.HashSet;
48
* Tests that the functions in SolrPluginUtils work as advertised.
50
public class SolrPluginUtilsTest extends SolrTestCaseJ4 {
53
public static void beforeClass() throws Exception {
54
initCore("solrconfig.xml","schema.xml");
58
public void testDocListConversion() throws Exception {
59
assertU("", adoc("id", "3234", "val_t", "quick red fox"));
60
assertU("", adoc("id", "3235", "val_t", "quick green fox"));
61
assertU("", adoc("id", "3236", "val_t", "quick brown fox"));
63
RefCounted<SolrIndexSearcher> holder = h.getCore().getSearcher();
64
SolrIndexSearcher srchr = holder.get();
65
SolrIndexSearcher.QueryResult qr = new SolrIndexSearcher.QueryResult();
66
SolrIndexSearcher.QueryCommand cmd = new SolrIndexSearcher.QueryCommand();
67
cmd.setQuery(new MatchAllDocsQuery());
68
qr = srchr.search(qr, cmd);
70
DocList docs = qr.getDocList();
71
Set<String> fields = new HashSet<String>();
75
SolrDocumentList list = SolrPluginUtils.docListToSolrDocumentList(docs, srchr, fields, null);
76
assertTrue("list Size: " + list.size() + " is not: " + docs.size(), list.size() == docs.size());
77
for (SolrDocument document : list) {
78
assertNotNull(document.get("val_t"));
84
public void testPartialEscape() {
86
assertEquals("",pe(""));
87
assertEquals("foo",pe("foo"));
88
assertEquals("foo\\:bar",pe("foo:bar"));
89
assertEquals("+foo\\:bar",pe("+foo:bar"));
90
assertEquals("foo \\! bar",pe("foo ! bar"));
91
assertEquals("foo\\?",pe("foo?"));
92
assertEquals("foo \"bar\"",pe("foo \"bar\""));
93
assertEquals("foo\\! \"bar\"",pe("foo! \"bar\""));
98
public void testStripUnbalancedQuotes() {
100
assertEquals("",strip(""));
101
assertEquals("foo",strip("foo"));
102
assertEquals("foo \"bar\"",strip("foo \"bar\""));
103
assertEquals("42",strip("42\""));
104
assertEquals("\"how now brown cow?\"",strip("\"how now brown cow?\""));
105
assertEquals("\"you go\" \"now!\"",strip("\"you go\" \"now!\""));
110
public void testStripIllegalOperators() {
112
assertEquals("",stripOp(""));
113
assertEquals("foo",stripOp("foo"));
114
assertEquals("foo -bar",stripOp("foo -bar"));
115
assertEquals("foo +bar",stripOp("foo +bar"));
116
assertEquals("foo + bar",stripOp("foo + bar"));
117
assertEquals("foo+ bar",stripOp("foo+ bar"));
118
assertEquals("foo+ bar",stripOp("foo+ bar"));
119
assertEquals("foo+",stripOp("foo+"));
120
assertEquals("foo bar",stripOp("foo bar -"));
121
assertEquals("foo bar ",stripOp("foo bar - + ++"));
122
assertEquals("foo bar",stripOp("foo --bar"));
123
assertEquals("foo bar ",stripOp("foo -------------------------------------------------------------------------------------------------------------------------bar --"));
124
assertEquals("foo bar ",stripOp("foo --bar -----------------------------------------------------------------------------------------------------------------------"));
129
public void testParseFieldBoosts() throws Exception {
131
Map<String,Float> e1 = new HashMap<String,Float>();
132
e1.put("fieldOne",2.3f);
133
e1.put("fieldTwo",null);
134
e1.put("fieldThree",-0.4f);
136
assertEquals("basic e1", e1, SolrPluginUtils.parseFieldBoosts
137
("fieldOne^2.3 fieldTwo fieldThree^-0.4"));
138
assertEquals("spacey e1", e1, SolrPluginUtils.parseFieldBoosts
139
(" fieldOne^2.3 fieldTwo fieldThree^-0.4 "));
140
assertEquals("really spacey e1", e1, SolrPluginUtils.parseFieldBoosts
141
(" \t fieldOne^2.3 \n fieldTwo fieldThree^-0.4 "));
142
assertEquals("really spacey e1", e1, SolrPluginUtils.parseFieldBoosts
143
(new String[]{" \t fieldOne^2.3 \n",
144
" fieldTwo fieldThree^-0.4 ",
147
Map<String,Float> e2 = new HashMap<String,Float>();
148
assertEquals("empty e2", e2, SolrPluginUtils.parseFieldBoosts
150
assertEquals("spacey e2", e2, SolrPluginUtils.parseFieldBoosts
155
public void testDisjunctionMaxQueryParser() throws Exception {
160
DisjunctionMaxQueryParser qp =
161
new SolrPluginUtils.DisjunctionMaxQueryParser(h.getCore().getSchema());
163
qp.addAlias("hoss", 0.01f, SolrPluginUtils.parseFieldBoosts
164
("title^2.0 title_stemmed name^1.2 subject^0.5"));
165
qp.addAlias("test", 0.01f, SolrPluginUtils.parseFieldBoosts("text^2.0"));
166
qp.addAlias("unused", 1.0f, SolrPluginUtils.parseFieldBoosts
167
("subject^0.5 sind^1.5"));
170
/* first some sanity tests that don't use aliasing at all */
174
assertNotNull(t+" sanity test gave back null", out);
175
assertTrue(t+" sanity test isn't TermQuery: " + out.getClass(),
176
out instanceof TermQuery);
177
assertEquals(t+" sanity test is wrong field",
178
h.getCore().getSchema().getDefaultSearchFieldName(),
179
((TermQuery)out).getTerm().field());
181
t = "subject:XXXXXXXX";
183
assertNotNull(t+" sanity test gave back null", out);
184
assertTrue(t+" sanity test isn't TermQuery: " + out.getClass(),
185
out instanceof TermQuery);
186
assertEquals(t+" sanity test is wrong field", "subject",
187
((TermQuery)out).getTerm().field());
189
/* field has untokenzied type, so this should be a term anyway */
190
t = "sind:\"simple phrase\"";
192
assertNotNull(t+" sanity test gave back null", out);
193
assertTrue(t+" sanity test isn't TermQuery: " + out.getClass(),
194
out instanceof TermQuery);
195
assertEquals(t+" sanity test is wrong field", "sind",
196
((TermQuery)out).getTerm().field());
198
t = "subject:\"simple phrase\"";
200
assertNotNull(t+" sanity test gave back null", out);
201
assertTrue(t+" sanity test isn't PhraseQuery: " + out.getClass(),
202
out instanceof PhraseQuery);
203
assertEquals(t+" sanity test is wrong field", "subject",
204
((PhraseQuery)out).getTerms()[0].field());
207
/* now some tests that use aliasing */
209
/* basic usage of single "term" */
212
assertNotNull(t+" was null", out);
213
assertTrue(t+" wasn't a DMQ:" + out.getClass(),
214
out instanceof DisjunctionMaxQuery);
215
assertEquals(t+" wrong number of clauses", 4,
216
countItems(((DisjunctionMaxQuery)out).iterator()));
219
/* odd case, but should still work, DMQ of one clause */
222
assertNotNull(t+" was null", out);
223
assertTrue(t+" wasn't a DMQ:" + out.getClass(),
224
out instanceof DisjunctionMaxQuery);
225
assertEquals(t+" wrong number of clauses", 1,
226
countItems(((DisjunctionMaxQuery)out).iterator()));
228
/* basic usage of multiple "terms" */
229
t = "hoss:XXXXXXXX test:YYYYY";
231
assertNotNull(t+" was null", out);
232
assertTrue(t+" wasn't a boolean:" + out.getClass(),
233
out instanceof BooleanQuery);
235
BooleanQuery bq = (BooleanQuery)out;
236
List<BooleanClause> clauses = bq.clauses();
237
assertEquals(t+" wrong number of clauses", 2,
239
Query sub = clauses.get(0).getQuery();
240
assertTrue(t+" first wasn't a DMQ:" + sub.getClass(),
241
sub instanceof DisjunctionMaxQuery);
242
assertEquals(t+" first had wrong number of clauses", 4,
243
countItems(((DisjunctionMaxQuery)sub).iterator()));
244
sub = clauses.get(1).getQuery();
245
assertTrue(t+" second wasn't a DMQ:" + sub.getClass(),
246
sub instanceof DisjunctionMaxQuery);
247
assertEquals(t+" second had wrong number of clauses", 1,
248
countItems(((DisjunctionMaxQuery)sub).iterator()));
251
/* a phrase, and a term that is a stop word for some fields */
252
t = "hoss:\"XXXXXX YYYYY\" hoss:the";
254
assertNotNull(t+" was null", out);
255
assertTrue(t+" wasn't a boolean:" + out.getClass(),
256
out instanceof BooleanQuery);
258
BooleanQuery bq = (BooleanQuery)out;
259
List<BooleanClause> clauses = bq.clauses();
260
assertEquals(t+" wrong number of clauses", 2,
262
Query sub = clauses.get(0).getQuery();
263
assertTrue(t+" first wasn't a DMQ:" + sub.getClass(),
264
sub instanceof DisjunctionMaxQuery);
265
assertEquals(t+" first had wrong number of clauses", 4,
266
countItems(((DisjunctionMaxQuery)sub).iterator()));
267
sub = clauses.get(1).getQuery();
268
assertTrue(t+" second wasn't a DMQ:" + sub.getClass(),
269
sub instanceof DisjunctionMaxQuery);
270
assertEquals(t+" second had wrong number of clauses (stop words)", 2,
271
countItems(((DisjunctionMaxQuery)sub).iterator()));
278
private static int countItems(Iterator i) {
280
while (i.hasNext()) {
288
public void testMinShouldMatchCalculator() {
290
/* zero is zero is zero */
291
assertEquals(0, calcMSM(5, "0"));
292
assertEquals(0, calcMSM(5, "0%"));
293
assertEquals(0, calcMSM(5, "-5"));
294
assertEquals(0, calcMSM(5, "-100%"));
297
assertEquals(3, calcMSM(5, "3"));
298
assertEquals(2, calcMSM(5, "-3"));
299
assertEquals(3, calcMSM(3, "3"));
300
assertEquals(0, calcMSM(3, "-3"));
301
assertEquals(3, calcMSM(3, "5"));
302
assertEquals(0, calcMSM(3, "-5"));
304
/* positive percentages with rounding */
305
assertEquals(0, calcMSM(3, "25%"));
306
assertEquals(1, calcMSM(4, "25%"));
307
assertEquals(1, calcMSM(5, "25%"));
308
assertEquals(2, calcMSM(10, "25%"));
310
/* negative percentages with rounding */
311
assertEquals(3, calcMSM(3, "-25%"));
312
assertEquals(3, calcMSM(4, "-25%"));
313
assertEquals(4, calcMSM(5, "-25%"));
314
assertEquals(8, calcMSM(10, "-25%"));
317
assertEquals(1, calcMSM(1, "3<0"));
318
assertEquals(2, calcMSM(2, "3<0"));
319
assertEquals(3, calcMSM(3, "3<0"));
320
assertEquals(0, calcMSM(4, "3<0"));
321
assertEquals(0, calcMSM(5, "3<0"));
322
assertEquals(1, calcMSM(1, "3<25%"));
323
assertEquals(2, calcMSM(2, "3<25%"));
324
assertEquals(3, calcMSM(3, "3<25%"));
325
assertEquals(1, calcMSM(4, "3<25%"));
326
assertEquals(1, calcMSM(5, "3<25%"));
328
/* multiple conditionals */
329
assertEquals(1, calcMSM(1, "3<-25% 10<-3"));
330
assertEquals(2, calcMSM(2, "3<-25% 10<-3"));
331
assertEquals(3, calcMSM(3, "3<-25% 10<-3"));
332
assertEquals(3, calcMSM(4, "3<-25% 10<-3"));
333
assertEquals(4, calcMSM(5, "3<-25% 10<-3"));
334
assertEquals(5, calcMSM(6, "3<-25% 10<-3"));
335
assertEquals(6, calcMSM(7, "3<-25% 10<-3"));
336
assertEquals(6, calcMSM(8, "3<-25% 10<-3"));
337
assertEquals(7, calcMSM(9, "3<-25% 10<-3"));
338
assertEquals(8, calcMSM(10, "3<-25% 10<-3"));
339
assertEquals(8, calcMSM(11, "3<-25% 10<-3"));
340
assertEquals(9, calcMSM(12, "3<-25% 10<-3"));
341
assertEquals(97, calcMSM(100, "3<-25% 10<-3"));
343
BooleanQuery q = new BooleanQuery();
344
q.add(new TermQuery(new Term("a","b")), Occur.SHOULD);
345
q.add(new TermQuery(new Term("a","c")), Occur.SHOULD);
346
q.add(new TermQuery(new Term("a","d")), Occur.SHOULD);
347
q.add(new TermQuery(new Term("a","d")), Occur.SHOULD);
349
SolrPluginUtils.setMinShouldMatch(q, "0");
350
assertEquals(0, q.getMinimumNumberShouldMatch());
352
SolrPluginUtils.setMinShouldMatch(q, "1");
353
assertEquals(1, q.getMinimumNumberShouldMatch());
355
SolrPluginUtils.setMinShouldMatch(q, "50%");
356
assertEquals(2, q.getMinimumNumberShouldMatch());
358
SolrPluginUtils.setMinShouldMatch(q, "99");
359
assertEquals(4, q.getMinimumNumberShouldMatch());
361
q.add(new TermQuery(new Term("a","e")), Occur.MUST);
362
q.add(new TermQuery(new Term("a","f")), Occur.MUST);
364
SolrPluginUtils.setMinShouldMatch(q, "50%");
365
assertEquals(2, q.getMinimumNumberShouldMatch());
370
public String pe(CharSequence s) {
371
return SolrPluginUtils.partialEscape(s).toString();
375
public String strip(CharSequence s) {
376
return SolrPluginUtils.stripUnbalancedQuotes(s).toString();
380
public String stripOp(CharSequence s) {
381
return SolrPluginUtils.stripIllegalOperators(s).toString();
385
public int calcMSM(int clauses, String spec) {
386
return SolrPluginUtils.calculateMinShouldMatch(clauses, spec);