/*------------------------------------------------------------------------------ * 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 "CLucene/StdHeader.h" #include "FieldSortedHitQueue.h" #include "FieldDocSortedHitQueue.h" #include "Compare.h" CL_NS_USE(util) CL_NS_USE(index) CL_NS_DEF(search) FieldSortedHitQueue::hitqueueCacheType FieldSortedHitQueue::Comparators(false,true); FieldSortedHitQueue::FieldSortedHitQueue (IndexReader* reader, SortField** _fields, int32_t size): fieldsLen(0), maxscore(1.0f) { while ( _fields[fieldsLen] != 0 ) fieldsLen++; comparators = _CL_NEWARRAY(ScoreDocComparator*,fieldsLen+1); SortField** tmp = _CL_NEWARRAY(SortField*,fieldsLen+1); for (int32_t i=0; igetField(); //todo: fields[i].getLocale(), not implemented comparators[i] = getCachedComparator (reader, fieldname, _fields[i]->getType(), _fields[i]->getFactory()); tmp[i] = _CLNEW SortField (fieldname, comparators[i]->sortType(), _fields[i]->getReverse()); } comparatorsLen = fieldsLen; comparators[fieldsLen]=NULL; tmp[fieldsLen] = NULL; this->fields = tmp; initialize(size,true); } bool FieldSortedHitQueue::lessThan (FieldDoc* docA, FieldDoc* docB) { // keep track of maximum score if (docA->scoreDoc.score > maxscore) maxscore = docA->scoreDoc.score; if (docB->scoreDoc.score > maxscore) maxscore = docB->scoreDoc.score; // run comparators int32_t c = 0; for ( int32_t i=0; c==0 && igetReverse()) ? comparators[i]->compare (&docB->scoreDoc, &docA->scoreDoc) : comparators[i]->compare (&docA->scoreDoc, &docB->scoreDoc); } // avoid random sort order that could lead to duplicates (bug #31241): if (c == 0) return docA->scoreDoc.doc > docB->scoreDoc.doc; return c > 0; } //static ScoreDocComparator* FieldSortedHitQueue::comparatorString (IndexReader* reader, const TCHAR* field) { //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); FieldCacheAuto* fa = FieldCache::DEFAULT->getStringIndex (reader, field); //CLStringIntern::unintern(field); CND_PRECONDITION(fa->contentType==FieldCacheAuto::STRING_INDEX,"Content type is incorrect"); fa->ownContents = false; return _CLNEW ScoreDocComparators::String(fa->stringIndex, fa->contentLen); } //static ScoreDocComparator* FieldSortedHitQueue::comparatorInt (IndexReader* reader, const TCHAR* field){ //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); FieldCacheAuto* fa = FieldCache::DEFAULT->getInts (reader, field); //CLStringIntern::unintern(field); CND_PRECONDITION(fa->contentType==FieldCacheAuto::INT_ARRAY,"Content type is incorrect"); return _CLNEW ScoreDocComparators::Int32(fa->intArray, fa->contentLen); } //static ScoreDocComparator* FieldSortedHitQueue::comparatorFloat (IndexReader* reader, const TCHAR* field) { //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); FieldCacheAuto* fa = FieldCache::DEFAULT->getFloats (reader, field); //CLStringIntern::unintern(field); CND_PRECONDITION(fa->contentType==FieldCacheAuto::FLOAT_ARRAY,"Content type is incorrect"); return _CLNEW ScoreDocComparators::Float (fa->floatArray, fa->contentLen); } //static ScoreDocComparator* FieldSortedHitQueue::comparatorAuto (IndexReader* reader, const TCHAR* field){ //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); FieldCacheAuto* fa = FieldCache::DEFAULT->getAuto (reader, field); //CLStringIntern::unintern(field); if (fa->contentType == FieldCacheAuto::STRING_INDEX ) { return comparatorString (reader, field); } else if (fa->contentType == FieldCacheAuto::INT_ARRAY) { return comparatorInt (reader, field); } else if (fa->contentType == FieldCacheAuto::FLOAT_ARRAY) { return comparatorFloat (reader, field); } else if (fa->contentType == FieldCacheAuto::STRING_ARRAY) { return comparatorString (reader, field); } else { _CLTHROWA(CL_ERR_Runtime, "unknown data type in field"); //todo: rich error information: '"+field+"'"); } } //todo: Locale locale, not implemented yet ScoreDocComparator* FieldSortedHitQueue::getCachedComparator (IndexReader* reader, const TCHAR* fieldname, int32_t type, SortComparatorSource* factory){ if (type == SortField::DOC) return ScoreDocComparator::INDEXORDER; if (type == SortField::DOCSCORE) return ScoreDocComparator::RELEVANCE; ScoreDocComparator* comparator = lookup (reader, fieldname, type, factory); if (comparator == NULL) { switch (type) { case SortField::AUTO: comparator = comparatorAuto (reader, fieldname); break; case SortField::INT: comparator = comparatorInt (reader, fieldname); break; case SortField::FLOAT: comparator = comparatorFloat (reader, fieldname); break; case SortField::STRING: //if (locale != NULL) // comparator = comparatorStringLocale (reader, fieldname, locale); //else comparator = comparatorString (reader, fieldname); break; case SortField::CUSTOM: comparator = factory->newComparator (reader, fieldname); break; default: _CLTHROWA(CL_ERR_Runtime,"unknown field type"); //todo: extend error //throw _CLNEW RuntimeException ("unknown field type: "+type); } store (reader, fieldname, type, factory, comparator); } return comparator; } FieldDoc* FieldSortedHitQueue::fillFields (FieldDoc* doc) const{ int32_t n = comparatorsLen; Comparable** fields = _CL_NEWARRAY(Comparable*,n+1); for (int32_t i=0; isortValue(&doc->scoreDoc); fields[n]=NULL; doc->fields = fields; if (maxscore > 1.0f) doc->scoreDoc.score /= maxscore; // normalize scores return doc; } ScoreDocComparator* FieldSortedHitQueue::lookup (IndexReader* reader, const TCHAR* field, int32_t type, SortComparatorSource* factory) { ScoreDocComparator* sdc = NULL; FieldCacheImpl::FileEntry* entry = (factory != NULL) ? _CLNEW FieldCacheImpl::FileEntry (field, factory) : _CLNEW FieldCacheImpl::FileEntry (field, type); { SCOPED_LOCK_MUTEX(Comparators.THIS_LOCK) hitqueueCacheReaderType* readerCache = Comparators.get(reader); if (readerCache == NULL){ _CLDELETE(entry); return NULL; } sdc = readerCache->get (entry); _CLDELETE(entry); } return sdc; } void FieldSortedHitQueue::closeCallback(CL_NS(index)::IndexReader* reader, void*){ SCOPED_LOCK_MUTEX(Comparators.THIS_LOCK) Comparators.remove(reader); } //static void FieldSortedHitQueue::store (IndexReader* reader, const TCHAR* field, int32_t type, SortComparatorSource* factory, ScoreDocComparator* value) { FieldCacheImpl::FileEntry* entry = (factory != NULL) ? _CLNEW FieldCacheImpl::FileEntry (field, factory) : _CLNEW FieldCacheImpl::FileEntry (field, type); { SCOPED_LOCK_MUTEX(Comparators.THIS_LOCK) hitqueueCacheReaderType* readerCache = Comparators.get(reader); if (readerCache == NULL) { readerCache = _CLNEW hitqueueCacheReaderType(true); Comparators.put(reader,readerCache); reader->addCloseCallback(FieldSortedHitQueue::closeCallback,NULL); } readerCache->put (entry, value); //return NULL; //supposed to return previous value... } } FieldSortedHitQueue::~FieldSortedHitQueue(){ _CLDELETE_ARRAY(comparators); if ( fields != NULL ){ for ( int i=0;fields[i]!=NULL;i++ ) _CLDELETE(fields[i]); _CLDELETE_ARRAY(fields); } } CL_NS_END