private void testRightOpenRange(int precisionStep) throws Exception { String field = "field" + precisionStep; int count = 3000; long lower = (count - 1) * distance + (distance / 3) + startOffset; NumericRangeQuery<Long> q = NumericRangeQuery.newLongRange(field, precisionStep, lower, null, true, true); TopDocs topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER); if (VERBOSE) System.out.println( "Found " + q.getTotalNumberOfTerms() + " distinct terms in right open range for field '" + field + "'."); ScoreDoc[] sd = topDocs.scoreDocs; assertNotNull(sd); assertEquals("Score doc count", noDocs - count, sd.length); Document doc = searcher.doc(sd[0].doc); assertEquals("First doc", count * distance + startOffset, Long.parseLong(doc.get(field))); doc = searcher.doc(sd[sd.length - 1].doc); assertEquals("Last doc", (noDocs - 1) * distance + startOffset, Long.parseLong(doc.get(field))); q = NumericRangeQuery.newLongRange(field, precisionStep, lower, null, true, false); topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER); sd = topDocs.scoreDocs; assertNotNull(sd); assertEquals("Score doc count", noDocs - count, sd.length); doc = searcher.doc(sd[0].doc); assertEquals("First doc", count * distance + startOffset, Long.parseLong(doc.get(field))); doc = searcher.doc(sd[sd.length - 1].doc); assertEquals("Last doc", (noDocs - 1) * distance + startOffset, Long.parseLong(doc.get(field))); }
@Test public void testInfiniteValues() throws Exception { Directory dir = newDirectory(); IndexWriter writer = new IndexWriter( dir, newIndexWriterConfig( TEST_VERSION_CURRENT, new WhitespaceAnalyzer(TEST_VERSION_CURRENT))); Document doc = new Document(); doc.add(new NumericField("double").setDoubleValue(Double.NEGATIVE_INFINITY)); doc.add(new NumericField("long").setLongValue(Long.MIN_VALUE)); writer.addDocument(doc); doc = new Document(); doc.add(new NumericField("double").setDoubleValue(Double.POSITIVE_INFINITY)); doc.add(new NumericField("long").setLongValue(Long.MAX_VALUE)); writer.addDocument(doc); doc = new Document(); doc.add(new NumericField("double").setDoubleValue(0.0)); doc.add(new NumericField("long").setLongValue(0L)); writer.addDocument(doc); writer.close(); IndexSearcher s = new IndexSearcher(dir); Query q = NumericRangeQuery.newLongRange("long", null, null, true, true); TopDocs topDocs = s.search(q, 10); assertEquals("Score doc count", 3, topDocs.scoreDocs.length); q = NumericRangeQuery.newLongRange("long", null, null, false, false); topDocs = s.search(q, 10); assertEquals("Score doc count", 3, topDocs.scoreDocs.length); q = NumericRangeQuery.newLongRange("long", Long.MIN_VALUE, Long.MAX_VALUE, true, true); topDocs = s.search(q, 10); assertEquals("Score doc count", 3, topDocs.scoreDocs.length); q = NumericRangeQuery.newLongRange("long", Long.MIN_VALUE, Long.MAX_VALUE, false, false); topDocs = s.search(q, 10); assertEquals("Score doc count", 1, topDocs.scoreDocs.length); q = NumericRangeQuery.newDoubleRange("double", null, null, true, true); topDocs = s.search(q, 10); assertEquals("Score doc count", 3, topDocs.scoreDocs.length); q = NumericRangeQuery.newDoubleRange("double", null, null, false, false); topDocs = s.search(q, 10); assertEquals("Score doc count", 3, topDocs.scoreDocs.length); s.close(); dir.close(); }
private void testSorting(int precisionStep) throws Exception { final Random rnd = newRandom(); String field = "field" + precisionStep; // 10 random tests, the index order is ascending, // so using a reverse sort field should retun descending documents for (int i = 0; i < 10; i++) { long lower = (long) (rnd.nextDouble() * noDocs * distance) + startOffset; long upper = (long) (rnd.nextDouble() * noDocs * distance) + startOffset; if (lower > upper) { long a = lower; lower = upper; upper = a; } Query tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, true); TopDocs topDocs = searcher.search(tq, null, noDocs, new Sort(new SortField(field, SortField.LONG, true))); if (topDocs.totalHits == 0) continue; ScoreDoc[] sd = topDocs.scoreDocs; assertNotNull(sd); long last = Long.parseLong(searcher.doc(sd[0].doc).get(field)); for (int j = 1; j < sd.length; j++) { long act = Long.parseLong(searcher.doc(sd[j].doc).get(field)); assertTrue("Docs should be sorted backwards", last > act); last = act; } } }
protected <N extends Number> NumericRangeQuery<?> numericRange( Class<N> clazz, String field, @Nullable N min, @Nullable N max, boolean minInc, boolean maxInc) { if (clazz.equals(Integer.class)) { return NumericRangeQuery.newIntRange(field, (Integer) min, (Integer) max, minInc, maxInc); } else if (clazz.equals(Double.class)) { return NumericRangeQuery.newDoubleRange(field, (Double) min, (Double) max, minInc, minInc); } else if (clazz.equals(Float.class)) { return NumericRangeQuery.newFloatRange(field, (Float) min, (Float) max, minInc, minInc); } else if (clazz.equals(Long.class)) { return NumericRangeQuery.newLongRange(field, (Long) min, (Long) max, minInc, minInc); } else if (clazz.equals(Byte.class) || clazz.equals(Short.class)) { return NumericRangeQuery.newIntRange( field, min != null ? min.intValue() : null, max != null ? max.intValue() : null, minInc, maxInc); } else { throw new IllegalArgumentException("Unsupported numeric type " + clazz.getName()); } }
/** * Factory that creates a <code>NumericRangeFilter</code>, that queries a <code>long</code> range * using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4). * You can have half-open ranges (which are in fact </≤ or >/≥ queries) by setting the * min or max value to <code>null</code>. By setting inclusive to false, it will match all * documents excluding the bounds, with inclusive on, the boundaries are hits, too. */ public static NumericRangeFilter<Long> newLongRange( final String field, Long min, Long max, final boolean minInclusive, final boolean maxInclusive) { return new NumericRangeFilter<Long>( NumericRangeQuery.newLongRange(field, min, max, minInclusive, maxInclusive)); }
public void testOneMatchQuery() throws Exception { NumericRangeQuery<Long> q = NumericRangeQuery.newLongRange("ascfield8", 8, 1000L, 1000L, true, true); assertSame(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE, q.getRewriteMethod()); TopDocs topDocs = searcher.search(q, noDocs); ScoreDoc[] sd = topDocs.scoreDocs; assertNotNull(sd); assertEquals("Score doc count", 1, sd.length); }
private void testRangeSplit(int precisionStep) throws Exception { final Random rnd = newRandom(); String field = "ascfield" + precisionStep; // 50 random tests for (int i = 0; i < 50; i++) { long lower = (long) (rnd.nextDouble() * noDocs - noDocs / 2); long upper = (long) (rnd.nextDouble() * noDocs - noDocs / 2); if (lower > upper) { long a = lower; lower = upper; upper = a; } // test inclusive range Query tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, true); TopDocs tTopDocs = searcher.search(tq, 1); assertEquals( "Returned count of range query must be equal to inclusive range length", upper - lower + 1, tTopDocs.totalHits); // test exclusive range tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, false, false); tTopDocs = searcher.search(tq, 1); assertEquals( "Returned count of range query must be equal to exclusive range length", Math.max(upper - lower - 1, 0), tTopDocs.totalHits); // test left exclusive range tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, false, true); tTopDocs = searcher.search(tq, 1); assertEquals( "Returned count of range query must be equal to half exclusive range length", upper - lower, tTopDocs.totalHits); // test right exclusive range tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, false); tTopDocs = searcher.search(tq, 1); assertEquals( "Returned count of range query must be equal to half exclusive range length", upper - lower, tTopDocs.totalHits); } }
/** * test for constant score + boolean query + filter, the other tests only use the constant score * mode */ private void testRange(int precisionStep) throws Exception { String field = "field" + precisionStep; int count = 3000; long lower = (distance * 3 / 2) + startOffset, upper = lower + count * distance + (distance / 3); NumericRangeQuery<Long> q = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, true); NumericRangeFilter<Long> f = NumericRangeFilter.newLongRange(field, precisionStep, lower, upper, true, true); int lastTerms = 0; for (byte i = 0; i < 3; i++) { TopDocs topDocs; int terms; String type; q.clearTotalNumberOfTerms(); f.clearTotalNumberOfTerms(); switch (i) { case 0: type = " (constant score filter rewrite)"; q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE); topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER); terms = q.getTotalNumberOfTerms(); break; case 1: type = " (constant score boolean rewrite)"; q.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE); topDocs = searcher.search(q, null, noDocs, Sort.INDEXORDER); terms = q.getTotalNumberOfTerms(); break; case 2: type = " (filter)"; topDocs = searcher.search(new MatchAllDocsQuery(), f, noDocs, Sort.INDEXORDER); terms = f.getTotalNumberOfTerms(); break; default: return; } if (VERBOSE) System.out.println( "Found " + terms + " distinct terms in range for field '" + field + "'" + type + "."); ScoreDoc[] sd = topDocs.scoreDocs; assertNotNull(sd); assertEquals("Score doc count" + type, count, sd.length); Document doc = searcher.doc(sd[0].doc); assertEquals("First doc" + type, 2 * distance + startOffset, Long.parseLong(doc.get(field))); doc = searcher.doc(sd[sd.length - 1].doc); assertEquals( "Last doc" + type, (1 + count) * distance + startOffset, Long.parseLong(doc.get(field))); if (i > 0 && searcher.getIndexReader().getSequentialSubReaders().length == 1) { assertEquals("Distinct term number is equal for all query types", lastTerms, terms); } lastTerms = terms; } }
public void testEqualsAndHash() throws Exception { QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test1", 4, 10L, 20L, true, true)); QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test2", 4, 10L, 20L, false, true)); QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test3", 4, 10L, 20L, true, false)); QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test4", 4, 10L, 20L, false, false)); QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test5", 4, 10L, null, true, true)); QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test6", 4, null, 20L, true, true)); QueryUtils.checkHashEquals(NumericRangeQuery.newLongRange("test7", 4, null, null, true, true)); QueryUtils.checkEqual( NumericRangeQuery.newLongRange("test8", 4, 10L, 20L, true, true), NumericRangeQuery.newLongRange("test8", 4, 10L, 20L, true, true)); QueryUtils.checkUnequal( NumericRangeQuery.newLongRange("test9", 4, 10L, 20L, true, true), NumericRangeQuery.newLongRange("test9", 8, 10L, 20L, true, true)); QueryUtils.checkUnequal( NumericRangeQuery.newLongRange("test10a", 4, 10L, 20L, true, true), NumericRangeQuery.newLongRange("test10b", 4, 10L, 20L, true, true)); QueryUtils.checkUnequal( NumericRangeQuery.newLongRange("test11", 4, 10L, 20L, true, true), NumericRangeQuery.newLongRange("test11", 4, 20L, 10L, true, true)); QueryUtils.checkUnequal( NumericRangeQuery.newLongRange("test12", 4, 10L, 20L, true, true), NumericRangeQuery.newLongRange("test12", 4, 10L, 20L, false, true)); QueryUtils.checkUnequal( NumericRangeQuery.newLongRange("test13", 4, 10L, 20L, true, true), NumericRangeQuery.newFloatRange("test13", 4, 10f, 20f, true, true)); // difference to int range is tested in TestNumericRangeQuery32 }
private void testRandomTrieAndClassicRangeQuery(int precisionStep) throws Exception { final Random rnd = newRandom(); String field = "field" + precisionStep; int termCountT = 0, termCountC = 0; for (int i = 0; i < 50; i++) { long lower = (long) (rnd.nextDouble() * noDocs * distance) + startOffset; long upper = (long) (rnd.nextDouble() * noDocs * distance) + startOffset; if (lower > upper) { long a = lower; lower = upper; upper = a; } // test inclusive range NumericRangeQuery<Long> tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, true); TermRangeQuery cq = new TermRangeQuery( field, NumericUtils.longToPrefixCoded(lower), NumericUtils.longToPrefixCoded(upper), true, true); TopDocs tTopDocs = searcher.search(tq, 1); TopDocs cTopDocs = searcher.search(cq, 1); assertEquals( "Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits); termCountT += tq.getTotalNumberOfTerms(); termCountC += cq.getTotalNumberOfTerms(); // test exclusive range tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, false, false); cq = new TermRangeQuery( field, NumericUtils.longToPrefixCoded(lower), NumericUtils.longToPrefixCoded(upper), false, false); tTopDocs = searcher.search(tq, 1); cTopDocs = searcher.search(cq, 1); assertEquals( "Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits); termCountT += tq.getTotalNumberOfTerms(); termCountC += cq.getTotalNumberOfTerms(); // test left exclusive range tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, false, true); cq = new TermRangeQuery( field, NumericUtils.longToPrefixCoded(lower), NumericUtils.longToPrefixCoded(upper), false, true); tTopDocs = searcher.search(tq, 1); cTopDocs = searcher.search(cq, 1); assertEquals( "Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits); termCountT += tq.getTotalNumberOfTerms(); termCountC += cq.getTotalNumberOfTerms(); // test right exclusive range tq = NumericRangeQuery.newLongRange(field, precisionStep, lower, upper, true, false); cq = new TermRangeQuery( field, NumericUtils.longToPrefixCoded(lower), NumericUtils.longToPrefixCoded(upper), true, false); tTopDocs = searcher.search(tq, 1); cTopDocs = searcher.search(cq, 1); assertEquals( "Returned count for NumericRangeQuery and TermRangeQuery must be equal", cTopDocs.totalHits, tTopDocs.totalHits); termCountT += tq.getTotalNumberOfTerms(); termCountC += cq.getTotalNumberOfTerms(); } if (precisionStep == Integer.MAX_VALUE) { assertEquals( "Total number of terms should be equal for unlimited precStep", termCountT, termCountC); } else { System.out.println("Average number of terms during random search on '" + field + "':"); System.out.println(" Trie query: " + (((double) termCountT) / (50 * 4))); System.out.println(" Classical query: " + (((double) termCountC) / (50 * 4))); } }
/** * 测试各种查询条件 * * @throws IOException * @throws Exception */ @Test public void testAdvancedQuery() throws Exception { Term term = new Term("content", "spring"); // 1、最基本的查询条件 TermQuery query1 = new TermQuery(term); // 2、数字范围查询条件 参数1、搜索域 参数2、范围的最小值 参数3、范围的最大值 参数4:是否包含最小值 参数5:是否包含最大值 NumericRangeQuery<Long> query2 = NumericRangeQuery.newLongRange("size", 100L, 5000L, true, false); // 3、布尔查询——实质是多条件的组合查询 BooleanQuery booleanQuery = new BooleanQuery(); booleanQuery.add(query1, Occur.MUST); booleanQuery.add(query2, Occur.MUST_NOT); // 4、matchall查询 MatchAllDocsQuery query3 = new MatchAllDocsQuery(); /** 以上的各种查询条件其实都是lucene底层查询语法的封装 */ /* System.out.println(query1); System.out.println(query2); System.out.println(booleanQuery); System.out.println(query3);*/ /** * content:spring size:[100 TO 5000} +content:spring -size:[100 TO 5000} :* * * <p>如果我们要直接使用查询语法来搜索,就需要用到queryparser来对语法进行解析得到各种查询条件query */ // -------------------------------------------------------------------------- // 使用查询解析器来解析语法生成查询条件 // lucene支持的常用查询与法 /** content:spring size:[100 TO 5000} +content:spring -size:[100 TO 5000} :* */ // 1、构造一个查询条件解析器 参数1:默认搜索域 参数2:解析查询语句时所用的分词器 QueryParser queryParser = new QueryParser("title", new IKAnalyzer()); // 2、传递一个用lucene查询语法表示的字符串给parser去解析 Query queryYufa1 = queryParser.parse("content:spring.txt"); System.out.println(queryYufa1); // title:spring.txt title:spring title:txt Query queryYufa2 = queryParser.parse("size:[2000 TO 4000}"); System.out.println(queryYufa2); /** 多个域的查询解析器 */ String[] fields = {"title", "content", "author"}; // 参数1: 默认搜索域(多个) 参数2:用来解析查询短语的分词器 MultiFieldQueryParser queryParser2 = new MultiFieldQueryParser(fields, new IKAnalyzer()); // 可以给一个精确的查询语法来解析成查询条件对象query Query query4 = queryParser2.parse("title:spring +content:springmvc"); // 也可以只给一个查询短语,让它自己去对默认搜索域进行解析 Query query5 = queryParser2.parse("小屌丝"); System.out.println("query4---- " + query4); System.out.println("query5---- " + query5); /** * query4---- title:spring +content:springmvc query5---- (title:小 title:屌 title:丝) (content:小 * content:屌 content:丝) (author:小 author:屌 author:丝) */ TopDocs topDocs = indexSearcher.search(queryYufa2, 10); int totalHits = topDocs.totalHits; ScoreDoc[] scoreDocs = topDocs.scoreDocs; System.out.println("总命中数: " + totalHits); for (ScoreDoc scoreDoc : scoreDocs) { Document doc = indexSearcher.doc(scoreDoc.doc); System.out.println(doc.get("title")); System.out.println(doc.get("content")); System.out.println(doc.get("path")); System.out.println(doc.get("size")); } }
@Override public Query getRangeQuery( QParser parser, SchemaField field, String min, String max, boolean minInclusive, boolean maxInclusive) { int ps = precisionStep; Query query = null; switch (type) { case INTEGER: query = NumericRangeQuery.newIntRange( field.getName(), ps, min == null ? null : Integer.parseInt(min), max == null ? null : Integer.parseInt(max), minInclusive, maxInclusive); break; case FLOAT: query = NumericRangeQuery.newFloatRange( field.getName(), ps, min == null ? null : Float.parseFloat(min), max == null ? null : Float.parseFloat(max), minInclusive, maxInclusive); break; case LONG: query = NumericRangeQuery.newLongRange( field.getName(), ps, min == null ? null : Long.parseLong(min), max == null ? null : Long.parseLong(max), minInclusive, maxInclusive); break; case DOUBLE: query = NumericRangeQuery.newDoubleRange( field.getName(), ps, min == null ? null : Double.parseDouble(min), max == null ? null : Double.parseDouble(max), minInclusive, maxInclusive); break; case DATE: query = NumericRangeQuery.newLongRange( field.getName(), ps, min == null ? null : dateField.parseMath(null, min).getTime(), max == null ? null : dateField.parseMath(null, max).getTime(), minInclusive, maxInclusive); break; default: throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field"); } return query; }