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.
17
package org.apache.solr;
19
import org.apache.solr.request.SolrQueryRequest;
20
import org.apache.solr.schema.DateField;
21
import org.apache.solr.schema.FieldType;
22
import org.apache.solr.schema.TrieField;
23
import org.apache.solr.util.DateMathParser;
24
import org.junit.After;
25
import org.junit.BeforeClass;
26
import org.junit.Test;
28
import java.text.SimpleDateFormat;
29
import java.util.Locale;
30
import java.util.TimeZone;
33
* Tests for TrieField functionality
35
* @version $Id: TestTrie.java 1065312 2011-01-30 16:08:25Z rmuir $
38
public class TestTrie extends SolrTestCaseJ4 {
40
public static void beforeClass() throws Exception {
41
initCore("solrconfig.xml","schema-trie.xml");
46
public void tearDown() throws Exception {
52
public void testTrieIntRangeSearch() throws Exception {
53
for (int i = 0; i < 10; i++) {
54
assertU(adoc("id", String.valueOf(i), "tint", String.valueOf(i)));
57
assertQ("Range filter must match only 5 documents", req("q", "*:*", "fq", "tint:[2 TO 6]"), "//*[@numFound='5']");
58
for (int i = 1; i < 11; i++) {
59
assertU(adoc("id", String.valueOf(-i), "tint", String.valueOf(-i)));
62
assertQ("Range filter must match only 5 documents", req("q", "*:*", "fq", "tint:[-6 TO -2]"), "//*[@numFound='5']");
64
// Test open ended range searches
65
assertQ("Range filter tint:[-9 to *] must match 20 documents", req("q", "*:*", "fq", "tint:[-10 TO *]"), "//*[@numFound='20']");
66
assertQ("Range filter tint:[* to 9] must match 20 documents", req("q", "*:*", "fq", "tint:[* TO 10]"), "//*[@numFound='20']");
67
assertQ("Range filter tint:[* to *] must match 20 documents", req("q", "*:*", "fq", "tint:[* TO *]"), "//*[@numFound='20']");
70
assertQ("Sort descending does not work correctly on tint fields", req("q", "*:*", "sort", "tint desc"), "//*[@numFound='20']", "//int[@name='tint'][.='9']");
71
assertQ("Sort ascending does not work correctly on tint fields", req("q", "*:*", "sort", "tint asc"), "//*[@numFound='20']", "//int[@name='tint'][.='-10']");
74
assertQ("Function queries does not work correctly on tint fields", req("q", "_val_:\"sum(tint,1)\""), "//*[@numFound='20']", "//int[@name='tint'][.='9']");
78
public void testTrieTermQuery() throws Exception {
79
for (int i = 0; i < 10; i++) {
80
assertU(adoc("id", String.valueOf(i),
81
"tint", String.valueOf(i),
82
"tfloat", String.valueOf(i * i * 31.11f),
83
"tlong", String.valueOf((long) Integer.MAX_VALUE + (long) i),
84
"tdouble", String.valueOf(i * 2.33d)));
89
assertQ("Term query on trie int field must match 1 document", req("q", "tint:2"), "//*[@numFound='1']");
90
assertQ("Term query on trie float field must match 1 document", req("q", "tfloat:124.44"), "//*[@numFound='1']");
91
assertQ("Term query on trie long field must match 1 document", req("q", "tlong:2147483648"), "//*[@numFound='1']");
92
assertQ("Term query on trie double field must match 1 document", req("q", "tdouble:4.66"), "//*[@numFound='1']");
95
assertQ("Term query on trie int field must match 1 document", req("q", "*:*", "fq", "tint:2"), "//*[@numFound='1']");
96
assertQ("Term query on trie float field must match 1 document", req("q", "*:*", "fq", "tfloat:124.44"), "//*[@numFound='1']");
97
assertQ("Term query on trie long field must match 1 document", req("q", "*:*", "fq", "tlong:2147483648"), "//*[@numFound='1']");
98
assertQ("Term query on trie double field must match 1 document", req("q", "*:*", "fq", "tdouble:4.66"), "//*[@numFound='1']");
102
public void testTrieFloatRangeSearch() throws Exception {
103
for (int i = 0; i < 10; i++) {
104
assertU(adoc("id", String.valueOf(i), "tfloat", String.valueOf(i * i * 31.11f)));
107
SolrQueryRequest req = req("q", "*:*", "fq", "tfloat:[0 TO 2518.0]");
108
assertQ("Range filter must match only 5 documents", req, "//*[@numFound='9']");
109
req = req("q", "*:*", "fq", "tfloat:[0 TO *]");
110
assertQ("Range filter must match 10 documents", req, "//*[@numFound='10']");
113
assertQ("Sort descending does not work correctly on tfloat fields", req("q", "*:*", "sort", "tfloat desc"), "//*[@numFound='10']", "//float[@name='tfloat'][.='2519.9102']");
114
assertQ("Sort ascending does not work correctly on tfloat fields", req("q", "*:*", "sort", "tfloat asc"), "//*[@numFound='10']", "//float[@name='tfloat'][.='0.0']");
117
assertQ("Function queries does not work correctly on tfloat fields", req("q", "_val_:\"sum(tfloat,1.0)\""), "//*[@numFound='10']", "//float[@name='tfloat'][.='2519.9102']");
121
public void testTrieLongRangeSearch() throws Exception {
122
for (long i = Integer.MAX_VALUE, c = 0; i < (long) Integer.MAX_VALUE + 10l; i++) {
123
assertU(adoc("id", String.valueOf(c++), "tlong", String.valueOf(i)));
126
String fq = "tlong:[" + Integer.MAX_VALUE + " TO " + (5l + Integer.MAX_VALUE) + "]";
127
SolrQueryRequest req = req("q", "*:*", "fq", fq);
128
assertQ("Range filter must match only 5 documents", req, "//*[@numFound='6']");
129
assertQ("Range filter tlong:[* to *] must match 10 documents", req("q", "*:*", "fq", "tlong:[* TO *]"), "//*[@numFound='10']");
132
assertQ("Sort descending does not work correctly on tlong fields", req("q", "*:*", "sort", "tlong desc"), "//*[@numFound='10']", "//long[@name='tlong'][.='2147483656']");
133
assertQ("Sort ascending does not work correctly on tlong fields", req("q", "*:*", "sort", "tlong asc"), "//*[@numFound='10']", "//long[@name='tlong'][.='2147483647']");
136
assertQ("Function queries does not work correctly on tlong fields", req("q", "_val_:\"sum(tlong,1.0)\""), "//*[@numFound='10']", "//long[@name='tlong'][.='2147483656']");
140
public void testTrieDoubleRangeSearch() throws Exception {
141
for (long i = Integer.MAX_VALUE, c = 0; i < (long) Integer.MAX_VALUE + 10l; i++) {
142
assertU(adoc("id", String.valueOf(c++), "tdouble", String.valueOf(i * 2.33d)));
145
String fq = "tdouble:[" + Integer.MAX_VALUE * 2.33d + " TO " + (5l + Integer.MAX_VALUE) * 2.33d + "]";
146
assertQ("Range filter must match only 5 documents", req("q", "*:*", "fq", fq), "//*[@numFound='6']");
147
assertQ("Range filter tdouble:[* to *] must match 10 documents", req("q", "*:*", "fq", "tdouble:[* TO *]"), "//*[@numFound='10']");
150
assertQ("Sort descending does not work correctly on tdouble fields", req("q", "*:*", "sort", "tdouble desc"), "//*[@numFound='10']", "//double[@name='tdouble'][.='5.0036369184800005E9']");
151
assertQ("Sort ascending does not work correctly on tdouble fields", req("q", "*:*", "sort", "tdouble asc"), "//*[@numFound='10']", "//double[@name='tdouble'][.='5.00363689751E9']");
154
assertQ("Function queries does not work correctly on tdouble fields", req("q", "_val_:\"sum(tdouble,1.0)\""), "//*[@numFound='10']", "//double[@name='tdouble'][.='5.0036369184800005E9']");
158
public void testTrieDateRangeSearch() throws Exception {
159
for (int i = 0; i < 10; i++) {
160
assertU(adoc("id", String.valueOf(i), "tdate", "1995-12-31T23:" + (i < 10 ? "0" + i : i) + ":59.999Z"));
163
SolrQueryRequest req = req("q", "*:*", "fq", "tdate:[1995-12-31T23:00:59.999Z TO 1995-12-31T23:04:59.999Z]");
164
assertQ("Range filter must match only 5 documents", req, "//*[@numFound='5']");
166
// Test open ended range searches
167
assertQ("Range filter tint:[1995-12-31T23:00:59.999Z to *] must match 10 documents", req("q", "*:*", "fq", "tdate:[1995-12-31T23:00:59.999Z TO *]"), "//*[@numFound='10']");
168
assertQ("Range filter tint:[* to 1995-12-31T23:09:59.999Z] must match 10 documents", req("q", "*:*", "fq", "tdate:[* TO 1995-12-31T23:09:59.999Z]"), "//*[@numFound='10']");
169
assertQ("Range filter tint:[* to *] must match 10 documents", req("q", "*:*", "fq", "tdate:[* TO *]"), "//*[@numFound='10']");
171
// Test date math syntax
172
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
173
format.setTimeZone(TimeZone.getTimeZone("UTC"));
175
assertU(delQ("*:*"));
176
DateMathParser dmp = new DateMathParser(DateField.UTC, Locale.US);
177
String largestDate = "";
178
for (int i = 0; i < 10; i++) {
179
// index 10 days starting with today
180
String d = format.format(i == 0 ? dmp.parseMath("/DAY") : dmp.parseMath("/DAY+" + i + "DAYS"));
181
assertU(adoc("id", String.valueOf(i), "tdate", d));
182
if (i == 9) largestDate = d;
185
assertQ("Range filter must match only 10 documents", req("q", "*:*", "fq", "tdate:[* TO *]"), "//*[@numFound='10']");
186
req = req("q", "*:*", "fq", "tdate:[NOW/DAY TO NOW/DAY+5DAYS]");
187
assertQ("Range filter must match only 6 documents", req, "//*[@numFound='6']");
190
assertU(adoc("id", "11", "tdate", "1995-12-31T23:59:59.999Z"));
192
assertQ("Term query must match only 1 document", req("q", "tdate:1995-12-31T23\\:59\\:59.999Z"), "//*[@numFound='1']");
193
assertQ("Term query must match only 1 document", req("q", "*:*", "fq", "tdate:1995-12-31T23\\:59\\:59.999Z"), "//*[@numFound='1']");
196
assertQ("Sort descending does not work correctly on tdate fields", req("q", "*:*", "sort", "tdate desc"), "//*[@numFound='11']", "//date[@name='tdate'][.='" + largestDate + "']");
197
assertQ("Sort ascending does not work correctly on tdate fields", req("q", "*:*", "sort", "tdate asc"), "//*[@numFound='11']", "//date[@name='tdate'][.='1995-12-31T23:59:59.999Z']");
200
assertQ("Function queries does not work correctly on tdate fields", req("q", "_val_:\"sum(tdate,1.0)\""), "//*[@numFound='11']", "//date[@name='tdate'][.='" + largestDate + "']");
204
public void testTrieDoubleRangeSearch_CustomPrecisionStep() throws Exception {
205
for (long i = Integer.MAX_VALUE, c = 0; i < (long) Integer.MAX_VALUE + 10l; i++) {
206
assertU(adoc("id", String.valueOf(c++), "tdouble4", String.valueOf(i * 2.33d)));
209
String fq = "tdouble4:[" + Integer.MAX_VALUE * 2.33d + " TO " + (5l + Integer.MAX_VALUE) * 2.33d + "]";
210
assertQ("Range filter must match only 5 documents", req("q", "*:*", "fq", fq), "//*[@numFound='6']");
214
public void testTrieFacet_PrecisionStep() throws Exception {
215
// Future protect - assert 0<precisionStep<64
216
checkPrecisionSteps("tint");
217
checkPrecisionSteps("tfloat");
218
checkPrecisionSteps("tdouble");
219
checkPrecisionSteps("tlong");
220
checkPrecisionSteps("tdate");
223
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
224
format.setTimeZone(TimeZone.getTimeZone("UTC"));
225
DateMathParser dmp = new DateMathParser(DateField.UTC, Locale.US);
227
for (int i = 0; i < 10; i++) {
228
long l = Integer.MAX_VALUE + i*1L;
229
// index 10 days starting with today
230
String d = format.format(i == 0 ? dmp.parseMath("/DAY") : dmp.parseMath("/DAY+" + i + "DAYS"));
231
assertU(adoc("id", String.valueOf(i), "tint", String.valueOf(i),
232
"tlong", String.valueOf(l),
233
"tfloat", String.valueOf(i * i * 31.11f),
234
"tdouble", String.valueOf(i * 2.33d),
237
for (int i = 0; i < 5; i++) {
238
long l = Integer.MAX_VALUE + i*1L;
239
String d = format.format(i == 0 ? dmp.parseMath("/DAY") : dmp.parseMath("/DAY+" + i + "DAYS"));
240
assertU(adoc("id", String.valueOf((i+1)*10), "tint", String.valueOf(i),
241
"tlong", String.valueOf(l),
242
"tfloat", String.valueOf(i * i * 31.11f),
243
"tdouble", String.valueOf(i * 2.33d),
248
SolrQueryRequest req = req("q", "*:*", "facet", "true", "rows", "15",
249
"facet.field", "tint",
250
"facet.field", "tlong",
251
"facet.field", "tfloat",
252
"facet.field", "tdouble",
253
"facet.date", "tdate",
254
"facet.date.start", "NOW/DAY",
255
"facet.date.end", "NOW/DAY+6DAYS",
256
"facet.date.gap", "+1DAY");
257
testFacetField(req, "tint", "0", "2");
258
testFacetField(req, "tint", "5", "1");
259
testFacetField(req, "tlong", String.valueOf(Integer.MAX_VALUE), "2");
260
testFacetField(req, "tlong", String.valueOf(Integer.MAX_VALUE+5L), "1");
261
testFacetField(req, "tfloat", String.valueOf(31.11f), "2");
262
testFacetField(req, "tfloat", String.valueOf(5*5*31.11f), "1");
263
testFacetField(req, "tdouble", String.valueOf(2.33d), "2");
264
testFacetField(req, "tdouble", String.valueOf(5*2.33d), "1");
266
testFacetDate(req, "tdate", format.format(dmp.parseMath("/DAY")), "4");
267
testFacetDate(req, "tdate", format.format(dmp.parseMath("/DAY+5DAYS")), "2");
270
private void checkPrecisionSteps(String fieldType) {
271
FieldType type = h.getCore().getSchema().getFieldType(fieldType);
272
if (type instanceof TrieField) {
273
TrieField field = (TrieField) type;
274
assertTrue(field.getPrecisionStep() > 0 && field.getPrecisionStep() < 64);
278
private void testFacetField(SolrQueryRequest req, String field, String value, String count) {
279
String xpath = "//lst[@name='facet_fields']/lst[@name='" + field + "']/int[@name='" + value + "'][.='" + count + "']";
283
private void testFacetDate(SolrQueryRequest req, String field, String value, String count) {
284
String xpath = "//lst[@name='facet_dates']/lst[@name='" + field + "']/int[@name='" + value + "'][.='" + count + "']";