354 lines
10 KiB
C++
354 lines
10 KiB
C++
/*------------------------------------------------------------------------------
|
|
* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
|
|
*
|
|
* Distributable under the terms of either the Apache License (Version 2.0) or
|
|
* the GNU Lesser General Public License, as specified in the COPYING file.
|
|
------------------------------------------------------------------------------*/
|
|
#include "test.h"
|
|
|
|
SimpleAnalyzer a;
|
|
StandardAnalyzer aStd;
|
|
WhitespaceAnalyzer aWS;
|
|
IndexSearcher* s=NULL;
|
|
|
|
void _TestSearchesRun( Analyzer* analyzer, Searcher* search, TCHAR* qry){
|
|
Query* q = NULL;
|
|
Hits* h = NULL;
|
|
try{
|
|
q = QueryParser::parse(qry , _T("contents"), analyzer);
|
|
h = search->search( q );
|
|
}_CLFINALLY(
|
|
_CLDELETE(h);
|
|
_CLDELETE(q);
|
|
);
|
|
}
|
|
|
|
void testSrchOpenIndex(CuTest *tc ){
|
|
char loc[1024];
|
|
strcpy(loc, clucene_data_location);
|
|
strcat(loc, "/reuters-21578-index");
|
|
|
|
CuAssert(tc,_T("Index does not exist"), Misc::dir_Exists(loc));
|
|
s=_CLNEW IndexSearcher(loc);
|
|
}
|
|
void testSrchCloseIndex(CuTest *tc ){
|
|
if ( s!=NULL ){
|
|
s->close();
|
|
_CLDELETE(s);
|
|
}
|
|
}
|
|
|
|
void testSrchPunctuation(CuTest *tc ){
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
|
|
//test punctuation
|
|
_TestSearchesRun(&a,s, _T("a&b") );
|
|
_TestSearchesRun(&a,s, _T("a&&b") );
|
|
_TestSearchesRun(&a,s, _T(".NET") );
|
|
}
|
|
|
|
void testSrchSlop(CuTest *tc ){
|
|
#ifdef NO_FUZZY_QUERY
|
|
CuNotImpl(tc,_T("Fuzzy"));
|
|
#else
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
//test slop
|
|
_TestSearchesRun(&a,s, _T("\"term germ\"~2") );
|
|
_TestSearchesRun(&a,s, _T("\"term germ\"~2 flork") );
|
|
_TestSearchesRun(&a,s, _T("\"term\"~2") );
|
|
_TestSearchesRun(&a,s, _T("\" \"~2 germ") );
|
|
_TestSearchesRun(&a,s, _T("\"term germ\"~2^2") );
|
|
#endif
|
|
}
|
|
|
|
void testSrchNumbers(CuTest *tc ){
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
|
|
// The numbers go away because SimpleAnalzyer ignores them
|
|
_TestSearchesRun(&a,s, _T("3") );
|
|
_TestSearchesRun(&a,s, _T("term 1.0 1 2") );
|
|
_TestSearchesRun(&a,s, _T("term term1 term2") );
|
|
|
|
_TestSearchesRun(&aStd,s, _T("3") );
|
|
_TestSearchesRun(&aStd,s, _T("term 1.0 1 2") );
|
|
_TestSearchesRun(&aStd,s, _T("term term1 term2") );
|
|
}
|
|
|
|
void testSrchWildcard(CuTest *tc ){
|
|
#ifdef NO_WILDCARD_QUERY
|
|
CuNotImpl(tc,_T("Wildcard"));
|
|
#else
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
//testWildcard
|
|
_TestSearchesRun(&a,s, _T("term*") );
|
|
_TestSearchesRun(&a,s, _T("term*^2") );
|
|
_TestSearchesRun(&a,s, _T("term~") );
|
|
_TestSearchesRun(&a,s, _T("term^2~") );
|
|
_TestSearchesRun(&a,s, _T("term~^2") );
|
|
_TestSearchesRun(&a,s, _T("term*germ") );
|
|
_TestSearchesRun(&a,s, _T("term*germ^3") );
|
|
|
|
//test problem reported by Gary Mangum
|
|
BooleanQuery* bq = _CLNEW BooleanQuery();
|
|
Term* upper = _CLNEW Term(_T("contents"),_T("0105"));
|
|
Term* lower = _CLNEW Term(_T("contents"),_T("0105"));
|
|
RangeQuery* rq=_CLNEW RangeQuery(lower,upper,true);
|
|
bq->add(rq,true,true,false);
|
|
_CLDECDELETE(upper);
|
|
_CLDECDELETE(lower);
|
|
|
|
Term* prefix = _CLNEW Term(_T("contents"),_T("reuters21578"));
|
|
PrefixQuery* pq = _CLNEW PrefixQuery(prefix);
|
|
_CLDECDELETE(prefix);
|
|
bq->add(pq,true,true,false);
|
|
|
|
Hits* h = NULL;
|
|
try{
|
|
h = s->search( bq );
|
|
}_CLFINALLY(
|
|
_CLDELETE(h);
|
|
_CLDELETE(bq);
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void testSrchEscapes(CuTest *tc ){
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
//testEscaped
|
|
_TestSearchesRun(&aWS,s, _T("\\[brackets") );
|
|
_TestSearchesRun(&a,s, _T("\\[brackets") );
|
|
_TestSearchesRun(&aWS,s, _T("\\\\") );
|
|
_TestSearchesRun(&aWS,s, _T("\\+blah") );
|
|
_TestSearchesRun(&aWS,s, _T("\\(blah") );
|
|
}
|
|
|
|
void testSrchRange(CuTest *tc ){
|
|
#ifdef NO_RANGE_QUERY
|
|
CuNotImpl(tc,_T("Range"));
|
|
#else
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
//testRange
|
|
_TestSearchesRun(&a,s, _T("[ j m]") );
|
|
_TestSearchesRun(&a,s, _T("[ j m ]") );
|
|
_TestSearchesRun(&a,s, _T("{ j m}") );
|
|
_TestSearchesRun(&a,s, _T("{ j m }") );
|
|
_TestSearchesRun(&a,s, _T("{a - b}") );
|
|
_TestSearchesRun(&a,s, _T("{ j m }^2.0") );
|
|
_TestSearchesRun(&a,s, _T("[ j m] OR bar") );
|
|
_TestSearchesRun(&a,s, _T("[ j m] AND bar") );
|
|
_TestSearchesRun(&a,s, _T("( bar blar { j m}) ") );
|
|
_TestSearchesRun(&a,s, _T("gack ( bar blar { j m}) ") );
|
|
#endif
|
|
}
|
|
|
|
void testSrchSimple(CuTest *tc ){
|
|
CuAssert(tc,_T("Searcher was not open"),s!=NULL);
|
|
//simple tests
|
|
_TestSearchesRun(&a,s, _T("a AND b") );
|
|
|
|
_TestSearchesRun(&a,s, _T("term term term") );
|
|
|
|
#ifdef _UCS2
|
|
TCHAR tmp1[100];
|
|
lucene_utf8towcs(tmp1,"t\xc3\xbcrm term term",100);
|
|
_TestSearchesRun(&a,s, tmp1 );
|
|
|
|
lucene_utf8towcs(tmp1,"\xc3\xbcmlaut",100);
|
|
_TestSearchesRun(&a,s, tmp1 );
|
|
#endif
|
|
|
|
_TestSearchesRun(&a,s, _T("(a AND b)") );
|
|
_TestSearchesRun(&a,s, _T("c OR (a AND b)") );
|
|
_TestSearchesRun(&a,s, _T("a AND NOT b") );
|
|
_TestSearchesRun(&a,s, _T("a AND -b") );
|
|
_TestSearchesRun(&a,s, _T("a AND !b") );
|
|
_TestSearchesRun(&a,s, _T("a && b") );
|
|
_TestSearchesRun(&a,s, _T("a && ! b") );
|
|
|
|
_TestSearchesRun(&a,s, _T("a OR b") );
|
|
_TestSearchesRun(&a,s, _T("a || b") );
|
|
_TestSearchesRun(&a,s, _T("a OR !b") );
|
|
_TestSearchesRun(&a,s, _T("a OR ! b") );
|
|
_TestSearchesRun(&a,s, _T("a OR -b") );
|
|
|
|
_TestSearchesRun(&a,s, _T("+term -term term") );
|
|
_TestSearchesRun(&a,s, _T("foo:term AND field:anotherTerm") );
|
|
_TestSearchesRun(&a,s, _T("term AND \"phrase phrase\"") );
|
|
_TestSearchesRun(&a,s, _T("\"hello there\"") );
|
|
|
|
_TestSearchesRun(&a,s, _T("a AND b") );
|
|
_TestSearchesRun(&a,s, _T("hello") );
|
|
_TestSearchesRun(&a,s, _T("\"hello there\"") );
|
|
|
|
_TestSearchesRun(&a,s, _T("germ term^2.0") );
|
|
_TestSearchesRun(&a,s, _T("term^2.0") );
|
|
_TestSearchesRun(&a,s, _T("term^2") );
|
|
_TestSearchesRun(&a,s, _T("term^2.3") );
|
|
_TestSearchesRun(&a,s, _T("\"germ term\"^2.0") );
|
|
_TestSearchesRun(&a,s, _T("\"term germ\"^2") );
|
|
|
|
_TestSearchesRun(&a,s, _T("(foo OR bar) AND (baz OR boo)") );
|
|
_TestSearchesRun(&a,s, _T("((a OR b) AND NOT c) OR d") );
|
|
_TestSearchesRun(&a,s, _T("+(apple \"steve jobs\") -(foo bar baz)") );
|
|
|
|
_TestSearchesRun(&a,s, _T("+title:(dog OR cat) -author:\"bob dole\"") );
|
|
|
|
|
|
_TestSearchesRun(&a,s, _T(".*") );
|
|
_TestSearchesRun(&a,s, _T("<*") );
|
|
_TestSearchesRun(&a,s, _T("/*") );
|
|
_TestSearchesRun(&a,s, _T(";*") );
|
|
}
|
|
|
|
void SearchTest(CuTest *tc) {
|
|
uint64_t start = Misc::currentTimeMillis();
|
|
|
|
SimpleAnalyzer analyzer;
|
|
RAMDirectory ram;
|
|
IndexWriter writer( &ram, &analyzer, true);
|
|
writer.setUseCompoundFile(false);
|
|
|
|
TCHAR* docs[] = { _T("a b c d e"),
|
|
_T("a b c d e a b c d e"),
|
|
_T("a b c d e f g h i j"),
|
|
_T("a c e"),
|
|
_T("e c a"),
|
|
_T("a c e a c e"),
|
|
_T("a c e a b c")
|
|
};
|
|
|
|
for (int j = 0; j < 7; j++) {
|
|
Document* d = _CLNEW Document();
|
|
//no need to delete fields... document takes ownership
|
|
d->add(*Field::Text(_T("contents"),docs[j]));
|
|
|
|
writer.addDocument(d);
|
|
_CLDELETE(d);
|
|
}
|
|
writer.optimize();
|
|
writer.close();
|
|
|
|
IndexReader* reader = IndexReader::open(&ram);
|
|
IndexSearcher searcher(reader);
|
|
TCHAR* queries[] = {
|
|
_T("\"a b\""),
|
|
_T("\"a b c\""),
|
|
_T("a AND b"),
|
|
_T("a c"),
|
|
_T("\"a c\""),
|
|
_T("\"a c e\""),
|
|
};
|
|
int shouldbe[] = {4,4,4,7,3,3};
|
|
Hits* hits = NULL;
|
|
QueryParser parser(_T("contents"), &analyzer);
|
|
|
|
for (int k = 0; k < 6; k++) {
|
|
Query* query = parser.parse(queries[k]);
|
|
const TCHAR* qryInfo = query->toString(_T("contents"));
|
|
|
|
hits = searcher.search(query);
|
|
CLUCENE_ASSERT( hits->length() == shouldbe[k] );
|
|
|
|
_CLDELETE_CARRAY(qryInfo);
|
|
_CLDELETE(hits);
|
|
_CLDELETE(query);
|
|
}
|
|
searcher.close();
|
|
reader->close();
|
|
_CLDELETE( reader );
|
|
|
|
CuMessageA (tc,"took %d milliseconds\n", Misc::currentTimeMillis()-start);
|
|
}
|
|
|
|
void testNormEncoding(CuTest *tc) {
|
|
//just a quick test of the default similarity
|
|
CLUCENE_ASSERT(Similarity::getDefault()->queryNorm(1)==1.0);
|
|
|
|
float_t f = Similarity::getDefault()->queryNorm(9);
|
|
f -= (1.0/3.0);
|
|
if ( f < 0 )
|
|
f *= -1;
|
|
CLUCENE_ASSERT(f < 0.1);
|
|
|
|
//test that div by zero is handled
|
|
float_t tmp = Similarity::getDefault()->lengthNorm(_T("test"),0);
|
|
tmp = Similarity::getDefault()->queryNorm(0);
|
|
|
|
//test that norm encoding is working properly
|
|
CLUCENE_ASSERT( Similarity::encodeNorm(-1)==0 );
|
|
CLUCENE_ASSERT( Similarity::encodeNorm(0)==0 );
|
|
CLUCENE_ASSERT( Similarity::encodeNorm(1)==124 );
|
|
CLUCENE_ASSERT( Similarity::encodeNorm(1)==124 );
|
|
CLUCENE_ASSERT( Similarity::encodeNorm(7516192768.0 )==255);
|
|
|
|
|
|
CLUCENE_ASSERT( Similarity::decodeNorm(124)==1 );
|
|
CLUCENE_ASSERT( Similarity::decodeNorm(255)==7516192768.0 );
|
|
|
|
//well know value:
|
|
CLUCENE_ASSERT( CL_NS(search)::Similarity::encodeNorm(0.5f) == 120 );
|
|
|
|
//can decode self
|
|
CLUCENE_ASSERT( CL_NS(search)::Similarity::encodeNorm(CL_NS(search)::Similarity::decodeNorm(57)) == 57 );
|
|
}
|
|
|
|
void testSrchManyHits(CuTest *tc) {
|
|
SimpleAnalyzer analyzer;
|
|
RAMDirectory ram;
|
|
IndexWriter writer( &ram, &analyzer, true);
|
|
|
|
TCHAR* docs[] = { _T("a b c d e"),
|
|
_T("a b c d e a b c d e"),
|
|
_T("a b c d e f g h i j"),
|
|
_T("a c e"),
|
|
_T("e c a"),
|
|
_T("a c e a c e"),
|
|
_T("a c e a b c")
|
|
};
|
|
|
|
for (int j = 0; j < 140; j++) {
|
|
Document* d = _CLNEW Document();
|
|
//no need to delete fields... document takes ownership
|
|
int x = j%7;
|
|
d->add(*Field::Text(_T("contents"),docs[x]));
|
|
|
|
writer.addDocument(d);
|
|
_CLDELETE(d);
|
|
}
|
|
writer.close();
|
|
|
|
IndexSearcher searcher(&ram);
|
|
|
|
BooleanQuery query;
|
|
Term* t = _CLNEW Term(_T("contents"), _T("a"));
|
|
query.add(_CLNEW TermQuery(t),true,false, false);
|
|
_CLDECDELETE(t);
|
|
Hits* hits = searcher.search(&query);
|
|
for ( int32_t x=0;x<hits->length();x++ ){
|
|
Document& doc = hits->doc(x);
|
|
}
|
|
_CLDELETE(hits);
|
|
searcher.close();
|
|
}
|
|
|
|
CuSuite *testsearch(void)
|
|
{
|
|
CuSuite *suite = CuSuiteNew(_T("CLucene Search Test"));
|
|
SUITE_ADD_TEST(suite, SearchTest);
|
|
|
|
SUITE_ADD_TEST(suite, testNormEncoding);
|
|
SUITE_ADD_TEST(suite, testSrchManyHits);
|
|
SUITE_ADD_TEST(suite, testSrchOpenIndex);
|
|
SUITE_ADD_TEST(suite, testSrchPunctuation);
|
|
SUITE_ADD_TEST(suite, testSrchSlop);
|
|
SUITE_ADD_TEST(suite, testSrchNumbers);
|
|
SUITE_ADD_TEST(suite, testSrchWildcard);
|
|
SUITE_ADD_TEST(suite, testSrchEscapes);
|
|
SUITE_ADD_TEST(suite, testSrchRange);
|
|
SUITE_ADD_TEST(suite, testSrchSimple);
|
|
SUITE_ADD_TEST(suite, testSrchCloseIndex);
|
|
|
|
return suite;
|
|
}
|
|
// EOF
|