/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.lucene.search; import java.io.IOException; import java.util.Arrays; import org.apache.lucene.document.Document; import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.NumericDocValuesField; import org.apache.lucene.document.SortedDocValuesField; import org.apache.lucene.document.SortedNumericDocValuesField; import org.apache.lucene.document.SortedSetDocValuesField; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.NumericUtils; import org.apache.lucene.util.TestUtil; public class TestDocValuesQueries extends LuceneTestCase { public void testDuelPointRangeSortedNumericRangeQuery() throws IOException { doTestDuelPointRangeNumericRangeQuery(true, 1); } public void testDuelPointRangeMultivaluedSortedNumericRangeQuery() throws IOException { doTestDuelPointRangeNumericRangeQuery(true, 3); } public void testDuelPointRangeNumericRangeQuery() throws IOException { doTestDuelPointRangeNumericRangeQuery(false, 1); } private void doTestDuelPointRangeNumericRangeQuery(boolean sortedNumeric, int maxValuesPerDoc) throws IOException { final int iters = atLeast(10); for (int iter = 0; iter < iters; ++iter) { Directory dir = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), dir); final int numDocs = atLeast(100); for (int i = 0; i < numDocs; ++i) { Document doc = new Document(); final int numValues = TestUtil.nextInt(random(), 0, maxValuesPerDoc); for (int j = 0; j < numValues; ++j) { final long value = TestUtil.nextLong(random(), -100, 10000); if (sortedNumeric) { doc.add(new SortedNumericDocValuesField("dv", value)); } else { doc.add(new NumericDocValuesField("dv", value)); } doc.add(new LongPoint("idx", value)); } iw.addDocument(doc); } if (random().nextBoolean()) { iw.deleteDocuments(LongPoint.newRangeQuery("idx", 0L, 10L)); } final IndexReader reader = iw.getReader(); final IndexSearcher searcher = newSearcher(reader, false); iw.close(); for (int i = 0; i < 100; ++i) { final long min = random().nextBoolean() ? Long.MIN_VALUE : TestUtil.nextLong(random(), -100, 10000); final long max = random().nextBoolean() ? Long.MAX_VALUE : TestUtil.nextLong(random(), -100, 10000); final Query q1 = LongPoint.newRangeQuery("idx", min, max); final Query q2; if (sortedNumeric) { q2 = SortedNumericDocValuesField.newRangeQuery("dv", min, max); } else { q2 = NumericDocValuesField.newRangeQuery("dv", min, max); } assertSameMatches(searcher, q1, q2, false); } reader.close(); dir.close(); } } private void doTestDuelPointRangeSortedRangeQuery(boolean sortedSet, int maxValuesPerDoc) throws IOException { final int iters = atLeast(10); for (int iter = 0; iter < iters; ++iter) { Directory dir = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), dir); final int numDocs = atLeast(100); for (int i = 0; i < numDocs; ++i) { Document doc = new Document(); final int numValues = TestUtil.nextInt(random(), 0, maxValuesPerDoc); for (int j = 0; j < numValues; ++j) { final long value = TestUtil.nextLong(random(), -100, 10000); byte[] encoded = new byte[Long.BYTES]; LongPoint.encodeDimension(value, encoded, 0); if (sortedSet) { doc.add(new SortedSetDocValuesField("dv", new BytesRef(encoded))); } else { doc.add(new SortedDocValuesField("dv", new BytesRef(encoded))); } doc.add(new LongPoint("idx", value)); } iw.addDocument(doc); } if (random().nextBoolean()) { iw.deleteDocuments(LongPoint.newRangeQuery("idx", 0L, 10L)); } final IndexReader reader = iw.getReader(); final IndexSearcher searcher = newSearcher(reader, false); iw.close(); for (int i = 0; i < 100; ++i) { long min = random().nextBoolean() ? Long.MIN_VALUE : TestUtil.nextLong(random(), -100, 10000); long max = random().nextBoolean() ? Long.MAX_VALUE : TestUtil.nextLong(random(), -100, 10000); byte[] encodedMin = new byte[Long.BYTES]; byte[] encodedMax = new byte[Long.BYTES]; LongPoint.encodeDimension(min, encodedMin, 0); LongPoint.encodeDimension(max, encodedMax, 0); boolean includeMin = true; boolean includeMax = true; if (random().nextBoolean()) { includeMin = false; min++; } if (random().nextBoolean()) { includeMax = false; max--; } final Query q1 = LongPoint.newRangeQuery("idx", min, max); final Query q2; if (sortedSet) { q2 = SortedSetDocValuesField.newRangeQuery("dv", min == Long.MIN_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMin), max == Long.MAX_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMax), includeMin, includeMax); } else { q2 = SortedDocValuesField.newRangeQuery("dv", min == Long.MIN_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMin), max == Long.MAX_VALUE && random().nextBoolean() ? null : new BytesRef(encodedMax), includeMin, includeMax); } assertSameMatches(searcher, q1, q2, false); } reader.close(); dir.close(); } } public void testDuelPointRangeSortedSetRangeQuery() throws IOException { doTestDuelPointRangeSortedRangeQuery(true, 1); } public void testDuelPointRangeMultivaluedSortedSetRangeQuery() throws IOException { doTestDuelPointRangeSortedRangeQuery(true, 3); } public void testDuelPointRangeSortedRangeQuery() throws IOException { doTestDuelPointRangeSortedRangeQuery(false, 1); } private void assertSameMatches(IndexSearcher searcher, Query q1, Query q2, boolean scores) throws IOException { final int maxDoc = searcher.getIndexReader().maxDoc(); final TopDocs td1 = searcher.search(q1, maxDoc, scores ? Sort.RELEVANCE : Sort.INDEXORDER); final TopDocs td2 = searcher.search(q2, maxDoc, scores ? Sort.RELEVANCE : Sort.INDEXORDER); assertEquals(td1.totalHits, td2.totalHits); for (int i = 0; i < td1.scoreDocs.length; ++i) { assertEquals(td1.scoreDocs[i].doc, td2.scoreDocs[i].doc); if (scores) { assertEquals(td1.scoreDocs[i].score, td2.scoreDocs[i].score, 10e-7); } } } public void testEquals() { Query q1 = SortedNumericDocValuesField.newRangeQuery("foo", 3, 5); QueryUtils.checkEqual(q1, SortedNumericDocValuesField.newRangeQuery("foo", 3, 5)); QueryUtils.checkUnequal(q1, SortedNumericDocValuesField.newRangeQuery("foo", 3, 6)); QueryUtils.checkUnequal(q1, SortedNumericDocValuesField.newRangeQuery("foo", 4, 5)); QueryUtils.checkUnequal(q1, SortedNumericDocValuesField.newRangeQuery("bar", 3, 5)); Query q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), true, true); QueryUtils.checkEqual(q2, SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), true, true)); QueryUtils.checkUnequal(q2, SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("baz"), new BytesRef("baz"), true, true)); QueryUtils.checkUnequal(q2, SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("bar"), true, true)); QueryUtils.checkUnequal(q2, SortedSetDocValuesField.newRangeQuery("quux", new BytesRef("bar"), new BytesRef("baz"), true, true)); } public void testToString() { Query q1 = SortedNumericDocValuesField.newRangeQuery("foo", 3, 5); assertEquals("foo:[3 TO 5]", q1.toString()); assertEquals("[3 TO 5]", q1.toString("foo")); assertEquals("foo:[3 TO 5]", q1.toString("bar")); Query q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), true, true); assertEquals("foo:[[62 61 72] TO [62 61 7a]]", q2.toString()); q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), false, true); assertEquals("foo:{[62 61 72] TO [62 61 7a]]", q2.toString()); q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), new BytesRef("baz"), false, false); assertEquals("foo:{[62 61 72] TO [62 61 7a]}", q2.toString()); q2 = SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("bar"), null, true, true); assertEquals("foo:[[62 61 72] TO *}", q2.toString()); q2 = SortedSetDocValuesField.newRangeQuery("foo", null, new BytesRef("baz"), true, true); assertEquals("foo:{* TO [62 61 7a]]", q2.toString()); assertEquals("{* TO [62 61 7a]]", q2.toString("foo")); assertEquals("foo:{* TO [62 61 7a]]", q2.toString("bar")); } public void testMissingField() throws IOException { Directory dir = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), dir); iw.addDocument(new Document()); IndexReader reader = iw.getReader(); iw.close(); IndexSearcher searcher = newSearcher(reader); for (Query query : Arrays.asList( NumericDocValuesField.newRangeQuery("foo", 2, 4), SortedNumericDocValuesField.newRangeQuery("foo", 2, 4), SortedDocValuesField.newRangeQuery("foo", new BytesRef("abc"), new BytesRef("bcd"), random().nextBoolean(), random().nextBoolean()), SortedSetDocValuesField.newRangeQuery("foo", new BytesRef("abc"), new BytesRef("bcd"), random().nextBoolean(), random().nextBoolean()))) { Weight w = searcher.createNormalizedWeight(query, random().nextBoolean()); assertNull(w.scorer(searcher.getIndexReader().leaves().get(0))); } reader.close(); dir.close(); } public void testSortedNumericNPE() throws IOException { Directory dir = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), dir); double[] nums = {-1.7147449030215377E-208, -1.6887024655302576E-11, 1.534911516604164E113, 0.0, 2.6947996404505155E-166, -2.649722021970773E306, 6.138239235731689E-198, 2.3967090122610808E111}; for (int i = 0; i < nums.length; ++i) { Document doc = new Document(); doc.add(new SortedNumericDocValuesField("dv", NumericUtils.doubleToSortableLong(nums[i]))); iw.addDocument(doc); } iw.commit(); final IndexReader reader = iw.getReader(); final IndexSearcher searcher = newSearcher(reader); iw.close(); final long lo = NumericUtils.doubleToSortableLong(8.701032080293731E-226); final long hi = NumericUtils.doubleToSortableLong(2.0801416404385346E-41); Query query = SortedNumericDocValuesField.newRangeQuery("dv", lo, hi); // TODO: assert expected matches searcher.search(query, searcher.reader.maxDoc(), Sort.INDEXORDER); // swap order, should still work query = SortedNumericDocValuesField.newRangeQuery("dv", hi, lo); // TODO: assert expected matches searcher.search(query, searcher.reader.maxDoc(), Sort.INDEXORDER); reader.close(); dir.close(); } }