summaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests/queryeval/multibitvectoriterator
diff options
context:
space:
mode:
Diffstat (limited to 'searchlib/src/tests/queryeval/multibitvectoriterator')
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/.gitignore2
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/CMakeLists.txt15
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/DESC1
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/FILES2
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp138
-rw-r--r--searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_test.cpp531
6 files changed, 689 insertions, 0 deletions
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/.gitignore b/searchlib/src/tests/queryeval/multibitvectoriterator/.gitignore
new file mode 100644
index 00000000000..415cfe14f11
--- /dev/null
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/.gitignore
@@ -0,0 +1,2 @@
+searchlib_multibitvectoriterator_test_app
+searchlib_multibitvectoriterator_bench_app
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/CMakeLists.txt b/searchlib/src/tests/queryeval/multibitvectoriterator/CMakeLists.txt
new file mode 100644
index 00000000000..1bac095225f
--- /dev/null
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchlib_multibitvectoriterator_test_app
+ SOURCES
+ multibitvectoriterator_test.cpp
+ DEPENDS
+ searchlib
+)
+vespa_add_test(NAME searchlib_multibitvectoriterator_test_app COMMAND searchlib_multibitvectoriterator_test_app)
+vespa_add_executable(searchlib_multibitvectoriterator_bench_app
+ SOURCES
+ multibitvectoriterator_bench.cpp
+ DEPENDS
+ searchlib
+)
+vespa_add_test(NAME searchlib_multibitvectoriterator_bench_app COMMAND searchlib_multibitvectoriterator_bench_app and no no 10 100000000 50 50 50 BENCHMARK)
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/DESC b/searchlib/src/tests/queryeval/multibitvectoriterator/DESC
new file mode 100644
index 00000000000..96fc26f5950
--- /dev/null
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/DESC
@@ -0,0 +1 @@
+multibitvectoriterator test. Take a look at multibitvectoriterator_test.cpp for details.
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/FILES b/searchlib/src/tests/queryeval/multibitvectoriterator/FILES
new file mode 100644
index 00000000000..7ae4331d090
--- /dev/null
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/FILES
@@ -0,0 +1,2 @@
+multibitvectoriterator_test.cpp
+multibitvectoriterator_bench.cpp
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp b/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp
new file mode 100644
index 00000000000..8912be56351
--- /dev/null
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_bench.cpp
@@ -0,0 +1,138 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/log/log.h>
+LOG_SETUP("multibitvectoriterator_test");
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/searchlib/queryeval/multibitvectoriterator.h>
+#include <vespa/searchlib/queryeval/emptysearch.h>
+#include <vespa/searchlib/common/bitvectoriterator.h>
+#include <vespa/searchlib/queryeval/andsearch.h>
+#include <vespa/searchlib/queryeval/orsearch.h>
+#include <vespa/searchlib/fef/termfieldmatchdata.h>
+#include <vespa/searchlib/fef/termfieldmatchdataarray.h>
+
+using namespace search::queryeval;
+using namespace search::fef;
+using namespace search;
+
+//-----------------------------------------------------------------------------
+
+class Test : public vespalib::TestApp
+{
+public:
+ void benchmark();
+ int Main();
+ template <typename T>
+ void testSearch(bool strict);
+private:
+ void searchAndCompare(SearchIterator::UP s, uint32_t docIdLimit);
+ void setup();
+ std::vector< BitVector::UP > _bvs;
+ uint32_t _numSearch;
+ uint32_t _numDocs;
+ bool _strict;
+ bool _optimize;
+ vespalib::string _type;
+ std::vector<int> _fillLimits;
+};
+
+void Test::setup()
+{
+ for(size_t i(0); i < _fillLimits.size(); i++) {
+ _bvs.push_back(BitVector::create(_numDocs));
+ BitVector & bv(*_bvs.back());
+ for (size_t j(0); j < bv.size(); j++) {
+ int r = rand();
+ if (r < _fillLimits[i]) {
+ bv.setBit(j);
+ }
+ }
+ bv.invalidateCachedCount();
+ LOG(info, "Filled bitvector %ld with %d bits", i, bv.countTrueBits());
+ }
+}
+
+typedef std::vector<uint32_t> H;
+
+H
+seek(SearchIterator & s, uint32_t docIdLimit)
+{
+ H h;
+ for (uint32_t docId(0); docId < docIdLimit; ) {
+ if (s.seek(docId)) {
+ h.push_back(docId);
+ docId++;
+ } else {
+ if (s.getDocId() > docId) {
+ docId = s.getDocId();
+ } else {
+ docId++;
+ }
+ }
+ //printf("docId = %u\n", docId);
+ }
+ return h;
+}
+
+void
+Test::benchmark()
+{
+ if (_type == "and") {
+ LOG(info, "Testing 'and'");
+ for (size_t i(0); i < _numSearch; i++) {
+ testSearch<AndSearch>(_strict);
+ }
+ } else {
+ LOG(info, "Testing 'or'");
+ for (size_t i(0); i < _numSearch; i++) {
+ testSearch<OrSearch>(_strict);
+ }
+ }
+}
+
+template <typename T>
+void
+Test::testSearch(bool strict)
+{
+ TermFieldMatchData tfmd;
+ TermFieldMatchDataArray tfmda;
+ tfmda.add(&tfmd);
+ MultiSearch::Children andd;
+ for (size_t i(0); i < _bvs.size(); i++) {
+ andd.push_back(BitVectorIterator::create(_bvs[i].get(), tfmda, strict).release());
+ }
+ SearchIterator::UP s(T::create(andd, strict));
+ if (_optimize) {
+ LOG(info, "Optimizing iterator");
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ }
+ H h = seek(*s, _numDocs);
+ LOG(info, "Found %ld hits", h.size());
+}
+
+int
+Test::Main()
+{
+ TEST_INIT("multibitvectoriterator_benchmark");
+ if (_argc < 6) {
+ LOG(info, "%s <'and/or'> <'strict/no-strict'> <'optimize/no-optimize> <numsearch> <numdocs> <fill 1> [<fill N>]", _argv[0]);
+ return -1;
+ }
+ _type = _argv[1];
+ _strict = _argv[2] == vespalib::string("strict");
+ _optimize = _argv[3] == vespalib::string("optimize");
+ _numSearch = strtoul(_argv[4], NULL, 0);
+ _numDocs = strtoul(_argv[5], NULL, 0);
+ for (int i(6); i < _argc; i++) {
+ _fillLimits.push_back((RAND_MAX/100) * strtoul(_argv[i], NULL, 0));
+ }
+ LOG(info, "Start setup of '%s' isearch with %ld vectors with %d documents", _type.c_str(), _fillLimits.size(), _numDocs);
+ setup();
+ LOG(info, "Start benchmark");
+ benchmark();
+ LOG(info, "Done benchmark");
+ TEST_FLUSH();
+ TEST_DONE();
+}
+
+TEST_APPHOOK(Test);
diff --git a/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_test.cpp b/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_test.cpp
new file mode 100644
index 00000000000..f3a25d675b2
--- /dev/null
+++ b/searchlib/src/tests/queryeval/multibitvectoriterator/multibitvectoriterator_test.cpp
@@ -0,0 +1,531 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+#include <vespa/log/log.h>
+LOG_SETUP("multibitvectoriterator_test");
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/searchlib/queryeval/multibitvectoriterator.h>
+#include <vespa/searchlib/queryeval/emptysearch.h>
+#include <vespa/searchlib/queryeval/truesearch.h>
+#include <vespa/searchlib/common/bitvectoriterator.h>
+#include <vespa/searchlib/queryeval/andsearch.h>
+#include <vespa/searchlib/queryeval/andnotsearch.h>
+#include <vespa/searchlib/queryeval/orsearch.h>
+#include <vespa/searchlib/fef/termfieldmatchdata.h>
+#include <vespa/searchlib/fef/termfieldmatchdataarray.h>
+
+using namespace search::queryeval;
+using namespace search::fef;
+using namespace search;
+
+//-----------------------------------------------------------------------------
+
+class Test : public vespalib::TestApp
+{
+public:
+ void testAndNot();
+ void testAnd();
+ void testBug7163266();
+ void testOr();
+ void testAndWith();
+ void testEndGuard();
+ template<typename T>
+ void testThatOptimizePreservesUnpack();
+ template <typename T>
+ void testOptimizeCommon(bool isAnd);
+ template <typename T>
+ void testOptimizeAndOr();
+ template <typename T>
+ void testSearch(bool strict);
+ int Main();
+private:
+ void verifySelectiveUnpack(SearchIterator & s, const TermFieldMatchData * tfmd);
+ void searchAndCompare(SearchIterator::UP s, uint32_t docIdLimit);
+ void setup();
+ std::vector< BitVector::UP > _bvs;
+};
+
+void Test::setup()
+{
+ srand(7);
+ for(size_t i(0); i < 3; i++) {
+ _bvs.push_back(BitVector::create(10000));
+ BitVector & bv(*_bvs.back());
+ for (size_t j(0); j < bv.size(); j++) {
+ int r = rand();
+ if (r & 0x1) {
+ bv.setBit(j);
+ }
+ }
+ }
+}
+
+typedef std::vector<uint32_t> H;
+
+H
+seekNoReset(SearchIterator & s, uint32_t start, uint32_t docIdLimit)
+{
+ H h;
+ for (uint32_t docId(start); docId < docIdLimit; ) {
+ if (s.seek(docId)) {
+ h.push_back(docId);
+ docId++;
+ } else {
+ if (s.getDocId() > docId) {
+ docId = s.getDocId();
+ } else {
+ docId++;
+ }
+ }
+ //printf("docId = %u\n", docId);
+ }
+ return h;
+}
+
+H
+seek(SearchIterator & s, uint32_t docIdLimit)
+{
+ s.resetRange();
+ s.initFullRange();
+ return seekNoReset(s, 1, docIdLimit);
+}
+
+void
+Test::testAndWith()
+{
+ TermFieldMatchData tfmd;
+ TermFieldMatchDataArray tfmda;
+ tfmda.add(&tfmd);
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(AndSearch::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+
+ s->initFullRange();
+ H firstHits2 = seekNoReset(*s, 1, 130);
+ SearchIterator::UP filter(s->andWith(BitVectorIterator::create(_bvs[2].get(), tfmda, false), 9));
+ H lastHits2F = seekNoReset(*s, 130, _bvs[0]->size());
+
+ children.clear();
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[2].get(), tfmda, false).release());
+ s.reset(AndSearch::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ s->initFullRange();
+ H firstHits3 = seekNoReset(*s, 1, 130);
+ H lastHits3 = seekNoReset(*s, 130, _bvs[0]->size());
+ //These constants will change if srand(7) is changed.
+ EXPECT_EQUAL(30u, firstHits2.size());
+ EXPECT_EQUAL(19u, firstHits3.size());
+ EXPECT_EQUAL(1234u, lastHits2F.size());
+ ASSERT_EQUAL(lastHits3.size(), lastHits2F.size());
+ for (size_t i(0); i < lastHits3.size(); i++) {
+ EXPECT_EQUAL(lastHits3[i], lastHits2F[i]);
+ }
+ }
+}
+
+void
+Test::testAndNot()
+{
+ testOptimizeCommon<AndNotSearch>(false);
+ testSearch<AndNotSearch>(false);
+ testSearch<AndNotSearch>(true);
+}
+
+void
+Test::testAnd()
+{
+ testOptimizeCommon<AndSearch>(true);
+ testOptimizeAndOr<AndSearch>();
+ testSearch<AndSearch>(false);
+ testSearch<AndSearch>(true);
+}
+
+void
+Test::testOr()
+{
+ testOptimizeCommon< OrSearch >(false);
+ testOptimizeAndOr< OrSearch >();
+ testSearch<OrSearch>(false);
+ testSearch<OrSearch>(true);
+}
+
+void
+Test::testBug7163266()
+{
+ TermFieldMatchData tfmd[30];
+ TermFieldMatchDataArray tfmda[30];
+ for (size_t i(0); i < 30; i++) {
+ tfmda[i].add(&tfmd[i]);
+ }
+ _bvs[0]->setBit(1);
+ _bvs[1]->setBit(1);
+ MultiSearch::Children children;
+ UnpackInfo unpackInfo;
+ for (size_t i(0); i < 28; i++) {
+ children.push_back(new TrueSearch(tfmd[2]));
+ unpackInfo.add(i);
+ }
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda[0], false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda[1], false).release());
+ SearchIterator::UP s(AndSearch::create(children, false, unpackInfo));
+ const MultiSearch * ms = dynamic_cast<const MultiSearch *>(s.get());
+ EXPECT_TRUE(ms != NULL);
+ EXPECT_EQUAL(30u, ms->getChildren().size());
+ EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::(anonymous namespace)::SelectiveUnpack>", s->getClassName());
+ for (size_t i(0); i < 28; i++) {
+ EXPECT_TRUE(ms->needUnpack(i));
+ }
+ EXPECT_FALSE(ms->needUnpack(28));
+ EXPECT_FALSE(ms->needUnpack(29));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ ms = dynamic_cast<const MultiSearch *>(s.get());
+ EXPECT_TRUE(ms != NULL);
+ EXPECT_EQUAL(29u, ms->getChildren().size());
+ EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::(anonymous namespace)::SelectiveUnpack>", s->getClassName());
+ for (size_t i(0); i < 28; i++) {
+ EXPECT_TRUE(ms->needUnpack(i));
+ }
+ EXPECT_TRUE(ms->needUnpack(28)); // NB: force unpack all
+}
+
+template<typename T>
+void
+Test::testThatOptimizePreservesUnpack()
+{
+ TermFieldMatchData tfmd[4];
+ TermFieldMatchDataArray tfmda[4];
+ for (size_t i(0); i < 4; i++) {
+ tfmda[i].add(&tfmd[i]);
+ }
+ _bvs[0]->setBit(1);
+ _bvs[1]->setBit(1);
+ _bvs[2]->setBit(1);
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda[0], false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda[1], false).release());
+ children.push_back(new TrueSearch(tfmd[2]));
+ children.push_back(BitVectorIterator::create(_bvs[2].get(), tfmda[3], false).release());
+ UnpackInfo unpackInfo;
+ unpackInfo.add(1);
+ unpackInfo.add(2);
+ SearchIterator::UP s(T::create(children, false, unpackInfo));
+ s->initFullRange();
+ const MultiSearch * ms = dynamic_cast<const MultiSearch *>(s.get());
+ EXPECT_TRUE(ms != NULL);
+ EXPECT_EQUAL(4u, ms->getChildren().size());
+ verifySelectiveUnpack(*s, tfmd);
+ tfmd[1].resetOnlyDocId(0);
+ tfmd[2].resetOnlyDocId(0);
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ s->resetRange();
+ s->initFullRange();
+ ms = dynamic_cast<const MultiSearch *>(s.get());
+ EXPECT_TRUE(ms != NULL);
+ EXPECT_EQUAL(2u, ms->getChildren().size());
+ verifySelectiveUnpack(*s, tfmd);
+}
+
+void
+Test::verifySelectiveUnpack(SearchIterator & s, const TermFieldMatchData * tfmd)
+{
+ s.seek(1);
+ EXPECT_EQUAL(0u, tfmd[0].getDocId());
+ EXPECT_EQUAL(0u, tfmd[1].getDocId());
+ EXPECT_EQUAL(0u, tfmd[2].getDocId());
+ EXPECT_EQUAL(0u, tfmd[3].getDocId());
+ s.unpack(1);
+ EXPECT_EQUAL(0u, tfmd[0].getDocId());
+ EXPECT_EQUAL(1u, tfmd[1].getDocId());
+ EXPECT_EQUAL(1u, tfmd[2].getDocId());
+ EXPECT_EQUAL(0u, tfmd[3].getDocId());
+}
+
+void
+Test::searchAndCompare(SearchIterator::UP s, uint32_t docIdLimit)
+{
+ H a = seek(*s, docIdLimit);
+ SearchIterator * p = s.get();
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ if (s.get() != p) {
+ H b = seek(*s, docIdLimit);
+ EXPECT_FALSE(a.empty());
+ EXPECT_EQUAL(a.size(), b.size());
+ for (size_t i(0); i < a.size(); i++) {
+ EXPECT_EQUAL(a[i], b[i]);
+ }
+ }
+}
+
+template <typename T>
+void
+Test::testSearch(bool strict)
+{
+ TermFieldMatchData tfmd;
+ TermFieldMatchDataArray tfmda;
+ tfmda.add(&tfmd);
+ uint32_t docIdLimit(_bvs[0]->size());
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, strict).release());
+ SearchIterator::UP s(T::create(children, strict));
+ searchAndCompare(std::move(s), docIdLimit);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, strict).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, strict).release());
+ SearchIterator::UP s(T::create(children, strict));
+ searchAndCompare(std::move(s), docIdLimit);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, strict).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, strict).release());
+ children.push_back(BitVectorIterator::create(_bvs[2].get(), tfmda, strict).release());
+ SearchIterator::UP s(T::create(children, strict));
+ searchAndCompare(std::move(s), docIdLimit);
+ }
+}
+
+template <typename T>
+void
+Test::testOptimizeCommon(bool isAnd)
+{
+ TermFieldMatchData tfmd;
+ TermFieldMatchDataArray tfmda;
+ tfmda.add(&tfmd);
+
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(1u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const BitVectorIterator *>(m.getChildren()[0]) != NULL);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(new EmptySearch());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const BitVectorIterator *>(m.getChildren()[0]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[1]) != NULL);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(new EmptySearch());
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[0]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const BitVectorIterator *>(m.getChildren()[1]) != NULL);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(new EmptySearch());
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[0]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[1]) != NULL);
+ EXPECT_FALSE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[1])->isStrict());
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(new EmptySearch());
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, true).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[0]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[1]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[1])->isStrict());
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ SearchIterator::UP filter(s->andWith(BitVectorIterator::create(_bvs[2].get(), tfmda, false), 9));
+
+ if (isAnd) {
+ EXPECT_TRUE(nullptr == filter.get());
+ } else {
+ EXPECT_FALSE(nullptr == filter.get());
+ }
+
+ children.clear();
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+ s.reset(T::create(children, true));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ filter = s->andWith(BitVectorIterator::create(_bvs[2].get(), tfmda, false), 9);
+
+ if (isAnd) {
+ EXPECT_TRUE(nullptr == filter.get());
+ } else {
+ EXPECT_FALSE(nullptr == filter.get());
+ }
+ }
+}
+
+template <typename T>
+void
+Test::testOptimizeAndOr()
+{
+ TermFieldMatchData tfmd;
+ TermFieldMatchDataArray tfmda;
+ tfmda.add(&tfmd);
+
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(s.get()) != NULL);
+ EXPECT_FALSE(dynamic_cast<const MultiBitVectorIteratorBase *>(s.get())->isStrict());
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(new EmptySearch());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0]) != NULL);
+ EXPECT_FALSE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0])->isStrict());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[1]) != NULL);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, false).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+ children.push_back(new EmptySearch());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0]) != NULL);
+ EXPECT_FALSE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0])->isStrict());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[1]) != NULL);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, true).release());
+ children.push_back(new EmptySearch());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0])->isStrict());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[1]) != NULL);
+ }
+ {
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, true).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, false).release());
+ children.push_back(new EmptySearch());
+
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const T *>(s.get()) != NULL);
+ const MultiSearch & m(dynamic_cast<const MultiSearch &>(*s));
+ EXPECT_EQUAL(2u, m.getChildren().size());
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0]) != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(m.getChildren()[0])->isStrict());
+ EXPECT_TRUE(dynamic_cast<const EmptySearch *>(m.getChildren()[1]) != NULL);
+ }
+}
+
+void
+Test::testEndGuard()
+{
+ typedef AndSearch T;
+ TermFieldMatchData tfmd;
+ TermFieldMatchDataArray tfmda;
+ tfmda.add(&tfmd);
+
+ MultiSearch::Children children;
+ children.push_back(BitVectorIterator::create(_bvs[0].get(), tfmda, true).release());
+ children.push_back(BitVectorIterator::create(_bvs[1].get(), tfmda, true).release());
+ SearchIterator::UP s(T::create(children, false));
+ s = MultiBitVectorIteratorBase::optimize(std::move(s));
+ s->initFullRange();
+ EXPECT_TRUE(s.get() != NULL);
+ EXPECT_TRUE(dynamic_cast<const MultiBitVectorIteratorBase *>(s.get()) != NULL);
+ MultiSearch & m(dynamic_cast<MultiSearch &>(*s));
+ EXPECT_TRUE(m.seek(0) || !m.seek(0));
+ EXPECT_TRUE(m.seek(3) || !m.seek(3));
+ EXPECT_FALSE(m.seek(_bvs[0]->size()+987));
+}
+
+int
+Test::Main()
+{
+ TEST_INIT("multibitvectoriterator_test");
+ setup();
+ testBug7163266();
+ testThatOptimizePreservesUnpack<OrSearch>();
+ testThatOptimizePreservesUnpack<AndSearch>();
+ TEST_FLUSH();
+ testEndGuard();
+ TEST_FLUSH();
+ testAndNot();
+ TEST_FLUSH();
+ testAnd();
+ TEST_FLUSH();
+ testOr();
+ TEST_FLUSH();
+ testAndWith();
+ TEST_FLUSH();
+ TEST_DONE();
+}
+
+TEST_APPHOOK(Test);