void searchPhrase(IndexSearcher &is, const string &qStr, bool fuzzy) {

	string queryString = qStr;
	BoolAnalyzer analyzer;
	const Query *pQuery1 = QueryParser::parsePhrase(
			queryString,
			"text", 
			analyzer, fuzzy);
	Query *pQuery2 = QueryParser::parsePhrase(
			queryString,
			"title",
			analyzer, fuzzy);
	pQuery2->setBoost(10);

	const Query *query = new OrQuery(*pQuery1, *pQuery2);
	cout << "Inner Query:  " << query->toString() << endl;
	
	vector<ScoreDoc> scoreDocs = is.search(*query);
	cout << "Hit Numbers:  " << scoreDocs.size() << endl;
	cout << "Hit Documents:" << endl;
	for (size_t i = 0; i < scoreDocs.size(); i ++) {
		fprintf(stdout, "%4ld. #%-4ld ", i + 1, scoreDocs[i].id());
		cout << is.doc(scoreDocs[i].id()).toString() << endl;
	}
	delete query;
}
// BK> all test functions are the same except RAMDirectory constructor, so shared code moved here
void checkDir(CuTest *tc, MockRAMDirectory * ramDir) {

    // Check size
    CuAssertTrue(tc, ramDir->sizeInBytes == ramDir->getRecomputedSizeInBytes(), _T("RAMDir size"));

    // open reader to test document count
    IndexReader * reader = IndexReader::open(ramDir);
    CuAssertEquals(tc, docsToAdd, reader->numDocs(), _T("document count"));

    // open search to check if all doc's are there
    IndexSearcher * searcher = _CLNEW IndexSearcher(reader);

    // search for all documents
    Document doc;
    for (int i = 0; i < docsToAdd; i++) {
        searcher->doc(i, doc);
        CuAssertTrue(tc, doc.getField(_T("content")) != NULL, _T("content is NULL"));
    }

    // cleanup
    reader->close();
    searcher->close();
    _CLLDELETE(reader);
    _CLLDELETE(searcher);
}
    void testEqualScores() 
    {
        // NOTE: uses index build in *this* setUp
        
        IndexReader * pReader = IndexReader::open( m_pSmall );
	    IndexSearcher * pSearch = _CLNEW IndexSearcher( pReader );

	    Hits * pResult;

        // some hits match more terms then others, score should be the same
        Query * q = csrq( _T( "data" ), _T( "1" ), _T( "6" ), true, true );
        pResult = pSearch->search( q );
        size_t numHits = pResult->length();
        assertEqualsMsg( _T( "wrong number of results" ), 6, numHits );
        float_t score = pResult->score( 0 );
        for( size_t i = 1; i < numHits; i++ )
        {
            assertTrueMsg( _T( "score was not the same" ), score == pResult->score( i ));
        }
        _CLDELETE( pResult );
        _CLDELETE( q );

        pSearch->close();
        _CLDELETE( pSearch );

        pReader->close();
        _CLDELETE( pReader );
    }
    void testBoost()
    {
        // NOTE: uses index build in *this* setUp

        IndexReader * pReader = IndexReader::open( m_pSmall );
	    IndexSearcher * pSearch = _CLNEW IndexSearcher( pReader );
	    Hits * pResult;

        // test for correct application of query normalization
        // must use a non score normalizing method for this.
        Query * q = csrq( _T( "data" ), _T( "1" ), _T( "6" ), true, true );
        q->setBoost( 100 );
        pResult = pSearch->search( q );
        for( size_t i = 1; i < pResult->length(); i++ )
        {
            assertTrueMsg( _T( "score was not was not correct" ), 1.0f == pResult->score( i ));
        }
        _CLDELETE( pResult );
        _CLDELETE( q );


        //
        // Ensure that boosting works to score one clause of a query higher
        // than another.
        //
        Query * q1 = csrq( _T( "data" ), _T( "A" ), _T( "A" ), true, true );  // matches document #0
        q1->setBoost( .1f );
        Query * q2 = csrq( _T( "data" ), _T( "Z" ), _T( "Z" ), true, true );  // matches document #1
        BooleanQuery * bq = _CLNEW BooleanQuery( true );
        bq->add( q1, true, BooleanClause::SHOULD );
        bq->add( q2, true, BooleanClause::SHOULD );

        pResult = pSearch->search( bq );
        assertEquals( 1, pResult->id( 0 ));
        assertEquals( 0, pResult->id( 1 ));
        assertTrue( pResult->score( 0 ) > pResult->score( 1 ));
        _CLDELETE( pResult );
        _CLDELETE( bq );

        q1 = csrq( _T( "data" ), _T( "A" ), _T( "A" ), true, true );  // matches document #0
        q1->setBoost( 10.0f );
        q2 = csrq( _T( "data" ), _T( "Z" ), _T( "Z" ), true, true );  // matches document #1
        bq = _CLNEW BooleanQuery( true );
        bq->add( q1, true, BooleanClause::SHOULD );
        bq->add( q2, true, BooleanClause::SHOULD );

        pResult = pSearch->search( bq );
        assertEquals( 0, pResult->id( 0 ));
        assertEquals( 1, pResult->id( 1 ));
        assertTrue( pResult->score( 0 ) > pResult->score( 1 ));
        _CLDELETE( pResult );
        _CLDELETE( bq );

        pSearch->close();
        _CLDELETE( pSearch );

        pReader->close();
        _CLDELETE( pReader );
    }
void testEndThreadException(CuTest *tc) {

    const int MAX_DOCS=1500;
	RAMDirectory ram;
	WhitespaceAnalyzer an;
	IndexWriter* writer = _CLNEW IndexWriter(&ram, &an, true);

    // add some documents
    Document doc;
    for (int i = 0; i < MAX_DOCS; i++) {
        TCHAR * tmp = English::IntToEnglish(i);
        doc.add(* new Field(_T("content"), tmp, Field::STORE_YES | Field::INDEX_UNTOKENIZED));
        writer->addDocument(&doc);
        doc.clear();
        _CLDELETE_ARRAY( tmp );
    }

    CuAssertEquals(tc, MAX_DOCS, writer->docCount());
    
    writer->close();
	_CLLDELETE(writer);
    
    // this sequence is OK: delete searcher after search thread finish
    {
        IndexSearcher * searcher = _CLNEW IndexSearcher(&ram);
        _LUCENE_THREADID_TYPE thread = _LUCENE_THREAD_CREATE(&searchDocs, searcher);
        SCOPED_LOCK_MUTEX(searchMutex);

        CONDITION_WAIT(searchMutex, searchCondition);
//        _LUCENE_SLEEP(9999); //make sure that deleteMutex is being waited on...
        CONDITION_NOTIFYALL(deleteCondition);

        _LUCENE_THREAD_JOIN(thread);

        searcher->close();
        _CLLDELETE(searcher);
    }

    // this produces memory exception: delete searcher after search finish but before thread finish
    {
        IndexSearcher * searcher = _CLNEW IndexSearcher(&ram);
        _LUCENE_THREADID_TYPE thread = _LUCENE_THREAD_CREATE(&searchDocs, searcher);
        SCOPED_LOCK_MUTEX(searchMutex);

        CONDITION_WAIT(searchMutex, searchCondition);
        searcher->close();
        _CLLDELETE(searcher);
        CONDITION_NOTIFYALL(deleteCondition);

        _LUCENE_THREAD_JOIN(thread);
    }


    ram.close();
}
void testIncludeLowerTrue(CuTest* tc)
{
    WhitespaceAnalyzer a;
    RAMDirectory* index = _CLNEW RAMDirectory();
    IndexWriter* writer = _CLNEW IndexWriter(index,
        &a, true);

    Document doc;
    doc.add(*_CLNEW Field(_T("Category"), _T("a 1"), Field::STORE_YES | Field::INDEX_TOKENIZED));
    writer->addDocument(&doc); doc.clear();

    doc.add(*_CLNEW Field(_T("Category"), _T("a 2"), Field::STORE_YES | Field::INDEX_TOKENIZED));
    writer->addDocument(&doc); doc.clear();

    doc.add(*_CLNEW Field(_T("Category"), _T("a 3"), Field::STORE_YES | Field::INDEX_TOKENIZED));
    writer->addDocument(&doc); doc.clear();

    writer->close();
    _CLLDELETE(writer);

    IndexSearcher* s = _CLNEW IndexSearcher(index);
    Filter* f = _CLNEW RangeFilter(_T("Category"), _T("3"), _T("3"), true, true);

    Term* t = _CLNEW Term(_T("Category"), _T("a"));
    Query* q1 = _CLNEW TermQuery(t);
    _CLLDECDELETE(t);

    t = _CLNEW Term(_T("Category"), _T("3"));
    Query* q2 = _CLNEW TermQuery(t);
    _CLLDECDELETE(t);

    Hits* h = s->search(q1);
    assertTrue(h->length() == 3);
    _CLLDELETE(h);

    h = s->search(q2);
    assertTrue(h->length() == 1);
    _CLLDELETE(h);

    h = s->search(q1, f);
    assertTrue(h->length() == 1);
    _CLLDELETE(h);

    s->close();
    _CLLDELETE(s);
    _CLLDELETE(q1);
    _CLLDELETE(q2);
    _CLLDELETE(f);

    index->close();
    _CLLDECDELETE(index);
}
_LUCENE_THREAD_FUNC(searchDocs, _searcher) {

    WhitespaceAnalyzer an;
    IndexSearcher * searcher = (IndexSearcher *)_searcher;
    Query * query = QueryParser::parse(_T("one"), _T("content"), &an);
    Hits * hits = searcher->search(query);
    
//    _LUCENE_SLEEP(9999); //make sure that searchMutex is being waited on...

    CONDITION_NOTIFYALL(searchCondition);
    SCOPED_LOCK_MUTEX(deleteMutex);

    _CLLDELETE(hits);
    _CLLDELETE(query);

    CONDITION_WAIT(deleteMutex, deleteCondition);
//    _LUCENE_THREAD_FUNC_RETURN(0);
}
Beispiel #8
0
/// TestBooleanScorer.java, ported 5/9/2009
void testBooleanScorer(CuTest *tc) {
    const TCHAR* FIELD = _T("category");
    RAMDirectory directory;

    TCHAR* values[] = { _T("1"), _T("2"), _T("3"), _T("4"), NULL};

    try {
        WhitespaceAnalyzer a;
        IndexWriter* writer = _CLNEW IndexWriter(&directory, &a, true);
        for (size_t i = 0; values[i]!=NULL; i++) {
            Document* doc = _CLNEW Document();
            doc->add(*_CLNEW Field(FIELD, values[i], Field::STORE_YES | Field::INDEX_TOKENIZED));
            writer->addDocument(doc);
            _CLLDELETE(doc);
        }
        writer->close();
        _CLLDELETE(writer);

        BooleanQuery* booleanQuery1 = _CLNEW BooleanQuery();
        Term *t = _CLNEW Term(FIELD, _T("1"));
        booleanQuery1->add(_CLNEW TermQuery(t), true, BooleanClause::SHOULD);
        _CLDECDELETE(t);
        t = _CLNEW Term(FIELD, _T("2"));
        booleanQuery1->add(_CLNEW TermQuery(t), true, BooleanClause::SHOULD);
        _CLDECDELETE(t);

        BooleanQuery* query = _CLNEW BooleanQuery();
        query->add(booleanQuery1, true, BooleanClause::MUST);
        t = _CLNEW Term(FIELD, _T("9"));
        query->add(_CLNEW TermQuery(t), true, BooleanClause::MUST_NOT);
        _CLDECDELETE(t);

        IndexSearcher *indexSearcher = _CLNEW IndexSearcher(&directory);
        Hits *hits = indexSearcher->search(query);
        CLUCENE_ASSERT(2 == hits->length()); // Number of matched documents
        _CLLDELETE(hits);
        _CLLDELETE(indexSearcher);

        _CLLDELETE(query);
    }
    catch (CLuceneError& e) {
        CuFail(tc, e.twhat());
    }
}
    void testBooleanOrderUnAffected()
    {
        // NOTE: uses index build in *this* setUp

        IndexReader * pReader = IndexReader::open( m_pSmall );
	    IndexSearcher * pSearch = _CLNEW IndexSearcher( pReader );

        // first do a regular RangeQuery which uses term expansion so
        // docs with more terms in range get higher scores
        Term * pLower = _CLNEW Term( _T( "data" ), _T( "1" ));
        Term * pUpper = _CLNEW Term( _T( "data" ), _T( "4" ));
        Query * rq = _CLNEW RangeQuery( pLower, pUpper, true );
        _CLLDECDELETE( pUpper );
        _CLLDECDELETE( pLower );

        Hits * pExpected = pSearch->search( rq );
        size_t numHits = pExpected->length();
 
        // now do a boolean where which also contains a
        // ConstantScoreRangeQuery and make sure the order is the same
        
        BooleanQuery * q = _CLNEW BooleanQuery();
        q->add( rq, true, BooleanClause::MUST );
        q->add( csrq( _T( "data" ), _T( "1" ), _T( "6" ), true, true ), true, BooleanClause::MUST );
 
        Hits * pActual = pSearch->search( q );
        assertEqualsMsg( _T( "wrong number of hits" ), numHits, pActual->length() );
        for( size_t i = 0; i < numHits; i++ )
        {
            assertEqualsMsg( _T( "mismatch in docid for a hit" ), pExpected->id( i ), pActual->id( i ));
        }
        _CLDELETE( pActual );
        _CLDELETE( pExpected );
        _CLDELETE( q );

        pSearch->close();
        _CLDELETE( pSearch );

        pReader->close();
        _CLDELETE( pReader );
    }
Beispiel #10
0
	void _TestSearchesRun( Analyzer& analyzer, IndexSearcher& search, char_t* qry){
		try{
			Query& q = QueryParser::Parse(qry , _T("contents"), analyzer);
			Hits& h = search.search( q );
			delete &h;
			delete &q;
		}catch(THROW_TYPE e){
			_cout << _T("Failed: ") << qry << " - " << e.what() << endl;
		}catch(...){
			_cout << _T("FAILED: ") << qry << endl;
		}
	}
    /////////////////////////////////////////////////////////////////////////////
    // CLucene specific 
    // Visual Studio 2005 shows memory leaks for this test, but some other 
    // tools do not detect any memory leaks. So what is right?
    // IN VC80 shows memory leaks ONLY if both sub-queries are added as 
    // MUST BooleanClauses. 
    void testBooleanMemLeaks()
    {
        IndexReader * pReader = IndexReader::open( m_pSmall );
	    IndexSearcher * pSearch = _CLNEW IndexSearcher( pReader );
 
        Query * q1 = csrq( _T( "data" ), _T( "A" ), _T( "A" ), true, true );  // matches document #0
        Query * q2 = csrq( _T( "data" ), _T( "Z" ), _T( "Z" ), true, true );  // matches document #1
        BooleanQuery * bq = _CLNEW BooleanQuery( true );
        bq->add( q1, true, BooleanClause::MUST );
        bq->add( q2, true, BooleanClause::MUST );

        Hits * pResult = pSearch->search( bq );

        _CLDELETE( pResult );
        _CLDELETE( bq );

        pSearch->close();
        _CLDELETE( pSearch );

        pReader->close();
        _CLDELETE( pReader );
    }
    void testRangeFilterId() {

        IndexReader* reader = IndexReader::open(index);
        IndexSearcher* search = new IndexSearcher(reader);

        int medId = ((maxId - minId) / 2);

        std::tstring minIPstr = pad(minId);
        const TCHAR* minIP = minIPstr.c_str();

        std::tstring maxIPstr = pad(maxId);
        const TCHAR* maxIP = maxIPstr.c_str();

        std::tstring medIPstr = pad(medId);
        const TCHAR* medIP = medIPstr.c_str();

        size_t numDocs = static_cast<size_t>(reader->numDocs());

        assertEqualsMsg(_T("num of docs"), numDocs, static_cast<size_t>(1+ maxId - minId));

        Hits* result;
        Term* term = _CLNEW Term(_T("body"),_T("body"));
        Query* q = _CLNEW TermQuery(term);
        _CLDECDELETE(term);

        // test id, bounded on both ends

        Filter* f = _CLNEW RangeFilter(_T("id"),minIP,maxIP,T,T);
        result = search->search(q, f);
        assertEqualsMsg(_T("find all"), numDocs, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),minIP,maxIP,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("all but last"), numDocs-1, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f =_CLNEW RangeFilter(_T("id"),minIP,maxIP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("all but first"), numDocs-1, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),minIP,maxIP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("all but ends"), numDocs-2, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),medIP,maxIP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("med and up"), 1+ maxId-medId, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),minIP,medIP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("up to med"), 1+ medId-minId, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        // unbounded id

        f=_CLNEW RangeFilter(_T("id"),minIP,NULL,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("min and up"), numDocs, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),NULL,maxIP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("max and down"), numDocs, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),minIP,NULL,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("not min, but up"), numDocs-1, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),NULL,maxIP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("not max, but down"), numDocs-1, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),medIP,maxIP,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("med and up, not max"), maxId-medId, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),minIP,medIP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("not min, up to med"), medId-minId, result->length());
        _CLLDELETE(result);
        _CLLDELETE(f);

        // very small sets

        f=_CLNEW RangeFilter(_T("id"),minIP,minIP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("min,min,F,F"), 0, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("id"),medIP,medIP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("med,med,F,F"), 0, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("id"),maxIP,maxIP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("max,max,F,F"), 0, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),minIP,minIP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("min,min,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("id"),NULL,minIP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("nul,min,F,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),maxIP,maxIP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("max,max,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("id"),maxIP,NULL,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("max,nul,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("id"),medIP,medIP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("med,med,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        search->close();
        _CLLDELETE(search);

        reader->close();
        _CLLDELETE(reader);

        _CLLDELETE(q);
    }
    void testRangeFilterRand()
    {
        IndexReader* reader = IndexReader::open(index);
        IndexSearcher* search = _CLNEW IndexSearcher(reader);

        std::tstring minRPstr = pad(minR);
        const TCHAR* minRP = minRPstr.c_str();
        
        std::tstring maxRPstr = pad(maxR);
        const TCHAR* maxRP = maxRPstr.c_str();

        size_t numDocs = static_cast<size_t>(reader->numDocs());

        assertEqualsMsg(_T("num of docs"), numDocs, 1+ maxId - minId);

        Hits* result;
        Term* term = _CLNEW Term(_T("body"),_T("body"));
        Query* q = _CLNEW TermQuery(term);
        _CLDECDELETE(term);

        // test extremes, bounded on both ends

        Filter* f = _CLNEW RangeFilter(_T("rand"),minRP,maxRP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("find all"), numDocs, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),minRP,maxRP,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("all but biggest"), numDocs-1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),minRP,maxRP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("all but smallest"), numDocs-1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),minRP,maxRP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("all but extremes"), numDocs-2, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        // unbounded

        f=_CLNEW RangeFilter(_T("rand"),minRP,NULL,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("smallest and up"), numDocs, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),NULL,maxRP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("biggest and down"), numDocs, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),minRP,NULL,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("not smallest, but up"), numDocs-1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),NULL,maxRP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("not biggest, but down"), numDocs-1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        // very small sets

        f=_CLNEW RangeFilter(_T("rand"),minRP,minRP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("min,min,F,F"), 0, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("rand"),maxRP,maxRP,F,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("max,max,F,F"), 0, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),minRP,minRP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("min,min,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("rand"),NULL,minRP,F,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("nul,min,F,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        f=_CLNEW RangeFilter(_T("rand"),maxRP,maxRP,T,T);
        result = search->search(q,f);
        assertEqualsMsg(_T("max,max,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);
        f=_CLNEW RangeFilter(_T("rand"),maxRP,NULL,T,F);
        result = search->search(q,f);
        assertEqualsMsg(_T("max,nul,T,T"), 1, result->length());
        _CLLDELETE(result); _CLLDELETE(f);

        search->close();
        _CLLDELETE(search);

        reader->close();
        _CLLDELETE(reader);

        _CLLDELETE(q);
    }
    void testRangeQueryRand()
    {
        // NOTE: uses index build in *super* setUp

        IndexReader * pReader = IndexReader::open( index );
	    IndexSearcher * pSearch = _CLNEW IndexSearcher( pReader );

        std::tstring sMinRP = pad(minR);
        std::tstring sMaxRP = pad(maxR);
        const TCHAR* minRP = sMinRP.c_str();
        const TCHAR* maxRP = sMaxRP.c_str();
    
        size_t numDocs = static_cast<size_t>( pReader->numDocs() );
        assertEqualsMsg( _T("num of docs"), numDocs, static_cast<size_t>(1+ maxId - minId));
        
    	Hits * pResult;
        Query * q;

        // test extremes, bounded on both ends
        
        q = csrq( _T( "rand" ), minRP, maxRP, true, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "find all" ), numDocs, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), minRP, maxRP, true, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "all but biggest" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), minRP, maxRP, false, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "all but smallest" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), minRP, maxRP, false, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "all but extremes" ), numDocs-2, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
    
        // unbounded

        q = csrq( _T( "rand" ), minRP, NULL, true, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "smallest and up" ), numDocs, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), NULL, maxRP, false, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "biggest and down" ), numDocs, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), minRP, NULL, false, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "not smallest, but up" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
            
        q = csrq( _T( "rand" ), NULL, maxRP, false, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "not biggest, but down" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
        
        // very small sets

        q = csrq( _T( "rand" ), minRP, minRP, false, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "min,min,F,F" ), 0, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), maxRP, maxRP, false, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "max,max,F,F" ), 0, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
                         
        q = csrq( _T( "rand" ), minRP, minRP, true, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "min,min,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), NULL, minRP, false, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "nul,min,F,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), maxRP, maxRP, true, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "max,max,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "rand" ), maxRP, NULL, true, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "max,nul,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        pSearch->close();
        _CLDELETE( pSearch );

        pReader->close();
        _CLDELETE( pReader );
    }
    void testRangeQueryId()
    {
        // NOTE: uses index build in *super* setUp

        IndexReader * pReader = IndexReader::open( index );
	    IndexSearcher * pSearch = _CLNEW IndexSearcher( pReader );

        int32_t medId = ((maxId - minId) / 2);
        
        std::tstring sMinIP = pad(minId);
        std::tstring sMaxIP = pad(maxId);
        std::tstring sMedIP = pad(medId);
        const TCHAR* minIP = sMinIP.c_str();
        const TCHAR* maxIP = sMaxIP.c_str();
        const TCHAR* medIP = sMedIP.c_str();
    
        size_t numDocs = static_cast<size_t>( pReader->numDocs() );
        assertEqualsMsg( _T("num of docs"), numDocs, static_cast<size_t>(1+ maxId - minId));
        
	    Hits * pResult;
        Query * q;
        // test id, bounded on both ends
        
        q = csrq( _T( "id" ), minIP, maxIP, true, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "find all" ), numDocs, pResult->length() );
        _CLDELETE( pResult ); _CLDELETE( q );

	    q = csrq( _T( "id" ), minIP, maxIP, true, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "all but last" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

	    q = csrq( _T( "id" ), minIP, maxIP, false, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "all but first" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
            
	    q = csrq( _T( "id" ), minIP, maxIP, false,false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "all but ends" ), numDocs-2, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
    
        q = csrq( _T( "id" ), medIP, maxIP, true, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "med and up" ), 1+maxId-medId, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
        
        q = csrq( _T( "id" ), minIP, medIP, true, true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "up to med" ), 1+medId-minId, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        // unbounded id

	    q = csrq( _T( "id" ), minIP, NULL, true, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "min and up" ), numDocs, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

	    q = csrq( _T( "id" ), NULL, maxIP, false, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "max and down" ), numDocs, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

	    q = csrq( _T( "id" ), minIP, NULL, false, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "not min, but up" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
            
	    q = csrq( _T( "id" ), NULL, maxIP, false, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "not max, but down" ), numDocs-1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
            
        q = csrq( _T( "id" ), medIP, maxIP, true, false );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "med and up, not max" ), maxId-medId, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
        
        q = csrq( _T( "id" ), minIP, medIP, false,true );
	    pResult = pSearch->search( q );
        assertEqualsMsg( _T( "not min, up to med" ), medId-minId, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        // very small sets

	    q = csrq( _T( "id" ), minIP, minIP, false, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "min,min,F,F" ), 0, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "id" ), medIP, medIP, false, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "med,med,F,F" ), 0, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "id") , maxIP, maxIP, false, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "max,max,F,F" ), 0, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
                         
	    q = csrq( _T( "id" ), minIP, minIP, true, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "min,min,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "id" ), NULL, minIP, false, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "nul,min,F,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

	    q = csrq( _T( "id" ), maxIP, maxIP, true, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "max,max,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

        q = csrq( _T( "id" ), maxIP, NULL, true, false );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "max,nul,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );

	    q = csrq( _T( "id" ), medIP, medIP, true, true );
	    pResult = pSearch->search( q );
	    assertEqualsMsg( _T( "med,med,T,T" ), 1, pResult->length());
        _CLDELETE( pResult ); _CLDELETE( q );
            
        pSearch->close();
        _CLDELETE( pSearch );

        pReader->close();
        _CLDELETE( pReader );
    }