// use FTSearch.nui // cFTS_Searcher class. Use Strings.nui // String manipulation for VDF (No User Interface) Use FTSIndex.nui // cFTS_System and cFTS_Indexer classes Use FTSData.nui // cFTS_TableAccess class. Use Dates.nui // Date routines (No User Interface) Use DocAttach.nui // Class for putting files 'attached' to records into one directory. class cFTS_ResultSet is a cArray procedure construct_object forward send construct_object property string priv.psSearchValue public "" property integer pbIsPopulated public -1 // Not popuplated property integer pbNegative public DFFALSE property integer piArticleCount public 0 end_procedure function bDoLogicalAnd integer lhResultSet returns integer integer liMax liArticle lbOK liDecrement move 0 to liDecrement get item_count to liMax decrement liMax for liArticle from 0 to liMax if (integer(value(self,liArticle))) begin get bEvalArticle of lhResultSet liArticle to lbOK ifnot lbOK begin set value item liArticle to 0 increment liDecrement end end if (mod(liArticle,50)=0 and ft_searcher@stop_time<>0) begin if (TS_SysTime()>ft_searcher@stop_time) function_return FTIS_SEARCH_TIMEOUT end loop set piArticleCount to (piArticleCount(self)-liDecrement) end_function end_class // cFTS_ResultSet // This is a help class to the cFTSearch class. // Public interface: // // property string psSearchValue // // function iEstimatedHits returns integer // // function iBuildTheSet returns integer // // class cFTS_ResultSetWord is a cFTS_ResultSet procedure construct_object forward send construct_object property integer priv.piWordId end_procedure function bEvalArticle integer liArticle returns integer integer lbRval liMax liItm liFile if (pbIsPopulated(self)) move (integer(value(self,liArticle))) to lbRval else begin // not populated get filenumber_ftartwrd to liFile clear liFile // clear ftartwrd set_field_value liFile 1 to liArticle // move liArticle to ftartwrd.article_id set_field_value liFile 2 to (priv.piWordId(self)) // get priv.piWordId to ftartwrd.word_id vfind liFile 1 EQ // find eq ftartwrd by index.1 move (found) to lbRval // move (found) to lbRval end if (pbNegative(self)) function_return (not(lbRval)) function_return lbRval end_function procedure set psSearchValue string lsValue set priv.psSearchValue to lsValue end_procedure function psSearchValue returns string function_return (priv.psSearchValue(self)) end_function function iEstimatedHits returns integer integer liFile liValue get filenumber_ftword to liFile clear liFile // clear FTWord set_field_value liFile 2 to (psSearchValue(self)) // get psSearchValue to FTWord.Word vfind liFile 2 eq // find eq FTWord by index.2 get_field_value liFile 1 to liValue // .Word_Id // set priv.piWordId to liValue // set priv.piWordId to FTWord.Word_Id get_field_value liFile 3 to liValue // .Frequency // function_return liValue // function_return FTWord.Frequency end_function function iBuildTheSet returns integer integer liWordId liArticleCount liFile liArticleId lbFound liValue get filenumber_ftartwrd to liFile send delete_data get priv.piWordId to liWordId move 0 to liArticleCount clear liFile set_field_Value liFile 2 to liWordId repeat vfind liFile 2 GT move (found) to lbFound if lbFound begin get_field_value liFile 2 to liValue move (liValue=liWordId) to lbFound if lbFound begin get_field_value liFile 1 to liArticleId set value item liArticleId to DFTRUE increment liArticleCount if (mod(liArticleCount,50)=0 and ft_searcher@stop_time<>0) begin if (TS_SysTime()>ft_searcher@stop_time) function_return FTIS_SEARCH_TIMEOUT end end end until not lbFound set piArticleCount to liArticleCount set pbIsPopulated to DFTRUE function_return FTIS_NO_ERROR end_function end_class // cFTS_ResultSetWord class cFTS_ResultSetPhrase is a cFTS_ResultSet procedure construct_object forward send construct_object object oPrivateWordSplitter is a cFTS_WordSplitter set pbDoNotRegisterWithParent to true end_object property string priv.psSearchValue public "" property integer pbNegative public DFFALSE end_procedure function bEvalArticle integer liArticle returns integer integer lhWordSplitter liMax liRow liItm liFile liPhraseLength liValue lbFound if (pbIsPopulated(self)) move (integer(value(self,liArticle))) to lbFound else begin // not populated move (oPrivateWordSplitter(self)) to lhWordSplitter get row_count of lhWordSplitter to liMax decrement liMax get filenumber_ftartphr to liFile get piPhraseLength to liPhraseLength clear liFile // clear FTArtPhr set_field_value liFile 1 to liArticle // move liArticle to FTArtPhr.Article_Id if liMax ge 0 set_field_value liFile 2 to (piWordId.i(lhWordSplitter, 0)) if liMax ge 1 set_field_value liFile 3 to (piWordId.i(lhWordSplitter, 1)) if liMax ge 2 set_field_value liFile 4 to (piWordId.i(lhWordSplitter, 2)) if liMax ge 3 set_field_value liFile 5 to (piWordId.i(lhWordSplitter, 3)) if liMax ge 4 set_field_value liFile 6 to (piWordId.i(lhWordSplitter, 4)) if liMax ge 5 set_field_value liFile 7 to (piWordId.i(lhWordSplitter, 5)) if liPhraseLength ge 7 if liMax ge 6 set_field_value liFile 8 to (piWordId.i(lhWordSplitter, 6)) if liPhraseLength ge 8 if liMax ge 7 set_field_value liFile 9 to (piWordId.i(lhWordSplitter, 7)) if liPhraseLength ge 9 if liMax ge 8 set_field_value liFile 10 to (piWordId.i(lhWordSplitter, 8)) if liPhraseLength ge 10 if liMax ge 9 set_field_value liFile 11 to (piWordId.i(lhWordSplitter, 9)) if liPhraseLength ge 11 if liMax ge 10 set_field_value liFile 12 to (piWordId.i(lhWordSplitter,10)) if liPhraseLength ge 12 if liMax ge 11 set_field_value liFile 13 to (piWordId.i(lhWordSplitter,11)) if liPhraseLength ge 13 if liMax ge 12 set_field_value liFile 14 to (piWordId.i(lhWordSplitter,12)) if liPhraseLength ge 14 if liMax ge 13 set_field_value liFile 15 to (piWordId.i(lhWordSplitter,13)) vfind liFile 1 EQ move (found) to lbFound if lbFound begin get_field_value liFile 1 to liValue move (liArticle=liValue) to lbFound end if lbFound if liMax ge 0 begin get_field_value liFile 2 to liValue move (liValue=piWordId.i(lhWordSplitter, 0)) to lbFound end if lbFound if liMax ge 1 begin get_field_value liFile 3 to liValue move (liValue=piWordId.i(lhWordSplitter, 1)) to lbFound end if lbFound if liMax ge 2 begin get_field_value liFile 4 to liValue move (liValue=piWordId.i(lhWordSplitter, 2)) to lbFound end if lbFound if liMax ge 3 begin get_field_value liFile 5 to liValue move (liValue=piWordId.i(lhWordSplitter, 3)) to lbFound end if lbFound if liMax ge 4 begin get_field_value liFile 6 to liValue move (liValue=piWordId.i(lhWordSplitter, 4)) to lbFound end if lbFound if liMax ge 5 begin get_field_value liFile 7 to liValue move (liValue=piWordId.i(lhWordSplitter, 5)) to lbFound end if liPhraseLength ge 7 if lbFound if liMax ge 6 begin get_field_value liFile 8 to liValue move (liValue=piWordId.i(lhWordSplitter, 6)) to lbFound end if liPhraseLength ge 8 if lbFound if liMax ge 7 begin get_field_value liFile 9 to liValue move (liValue=piWordId.i(lhWordSplitter, 7)) to lbFound end if liPhraseLength ge 9 if lbFound if liMax ge 8 begin get_field_value liFile 10 to liValue move (liValue=piWordId.i(lhWordSplitter, 8)) to lbFound end if liPhraseLength ge 10 if lbFound if liMax ge 9 begin get_field_value liFile 11 to liValue move (liValue=piWordId.i(lhWordSplitter, 9)) to lbFound end if liPhraseLength ge 11 if lbFound if liMax ge 10 begin get_field_value liFile 12 to liValue move (liValue=piWordId.i(lhWordSplitter,10)) to lbFound end if liPhraseLength ge 12 if lbFound if liMax ge 11 begin get_field_value liFile 13 to liValue move (liValue=piWordId.i(lhWordSplitter,11)) to lbFound end if liPhraseLength ge 13 if lbFound if liMax ge 12 begin get_field_value liFile 14 to liValue move (liValue=piWordId.i(lhWordSplitter,12)) to lbFound end if liPhraseLength ge 14 if lbFound if liMax ge 13 begin get_field_value liFile 15 to liValue move (liValue=piWordId.i(lhWordSplitter,13)) to lbFound end end function_return lbFound end_function procedure set psSearchValue string lsValue integer lhWordSplitter lhPrivateWordSplitter move (oPrivateWordSplitter(self)) to lhPrivateWordSplitter get phWordsplitterObject to lhWordSplitter send delete_data // reset the result set send DoReset to lhPrivateWordSplitter set cFTS_WordSplitter.phRedirectObj of lhWordSplitter to lhPrivateWordSplitter send DoAddText to lhWordSplitter lsValue set priv.psSearchValue to lsValue end_procedure function psSearchValue returns string function_return (priv.psSearchValue(self)) end_function function iEstimatedHits returns integer integer lhWordSplitter liMax liRow liType liRval liFile liValue string lsWord get filenumber_ftword to liFile move -1 to liRval move (oPrivateWordSplitter(self)) to lhWordSplitter get row_count of lhWordSplitter to liMax decrement liMax for liRow from 0 to liMax get psWord.i of lhWordSplitter liRow to lsWord clear liFile //clear FTWord set_field_value liFile 2 to lsWord //move lsWord to FTWord.Word vfind liFile 2 EQ //find eq FTWord by index.2 if (found) begin get_field_value liFile 1 to liValue // FTWORD.WORD_ID set piWordId.i of lhWordSplitter liRow to liValue get_field_value liFile 3 to liValue // FTWord.Frequency set piFrequency.i of lhWordSplitter liRow to liValue if (liRval=-1 or liValue<liRval) move liValue to liRval // if (liRval=-1 or FTWord.Frequency<liRval) move FTWord.Frequency to liRval end else move 0 to liRval loop function_return (liRval/(liMax+1)) end_function function iBuildTheSet returns integer integer lhWordSplitter liMax liRow liArticleCount lbFound liMaxArticles integer liWordID liFile liPhraseLength liValue send delete_data if liMaxArticles eq 0 move 999999 to liMaxArticles move (oPrivateWordSplitter(self)) to lhWordSplitter get row_count of lhWordSplitter to liMax ifnot liMax function_return 0 decrement liMax move 0 to liArticleCount get filenumber_ftartphr to liFile get piPhraseLength to liPhraseLength clear liFile //clear FTArtPhr if liMax ge 0 set_field_value liFile 2 to (piWordId.i(lhWordSplitter, 0)) if liMax ge 1 set_field_value liFile 3 to (piWordId.i(lhWordSplitter, 1)) if liMax ge 2 set_field_value liFile 4 to (piWordId.i(lhWordSplitter, 2)) if liMax ge 3 set_field_value liFile 5 to (piWordId.i(lhWordSplitter, 3)) if liMax ge 4 set_field_value liFile 6 to (piWordId.i(lhWordSplitter, 4)) if liMax ge 5 set_field_value liFile 7 to (piWordId.i(lhWordSplitter, 5)) if liPhraseLength ge 7 if liMax ge 6 set_field_value liFile 8 to (piWordId.i(lhWordSplitter, 6)) if liPhraseLength ge 8 if liMax ge 7 set_field_value liFile 9 to (piWordId.i(lhWordSplitter, 7)) if liPhraseLength ge 9 if liMax ge 8 set_field_value liFile 10 to (piWordId.i(lhWordSplitter, 8)) if liPhraseLength ge 10 if liMax ge 9 set_field_value liFile 11 to (piWordId.i(lhWordSplitter, 9)) if liPhraseLength ge 11 if liMax ge 10 set_field_value liFile 12 to (piWordId.i(lhWordSplitter,10)) if liPhraseLength ge 12 if liMax ge 11 set_field_value liFile 13 to (piWordId.i(lhWordSplitter,11)) if liPhraseLength ge 13 if liMax ge 12 set_field_value liFile 14 to (piWordId.i(lhWordSplitter,12)) if liPhraseLength ge 14 if liMax ge 13 set_field_value liFile 15 to (piWordId.i(lhWordSplitter,13)) repeat vfind liFile 2 GT // find gt FTArtPhr by index.2 move (found) to lbFound if lbFound if liMax ge 0 begin get_field_value liFile 2 to liValue move (liValue=piWordId.i(lhWordSplitter, 0)) to lbFound end if lbFound if liMax ge 1 begin get_field_value liFile 3 to liValue move (liValue=piWordId.i(lhWordSplitter, 1)) to lbFound end if lbFound if liMax ge 2 begin get_field_value liFile 4 to liValue move (liValue=piWordId.i(lhWordSplitter, 2)) to lbFound end if lbFound if liMax ge 3 begin get_field_value liFile 5 to liValue move (liValue=piWordId.i(lhWordSplitter, 3)) to lbFound end if lbFound if liMax ge 4 begin get_field_value liFile 6 to liValue move (liValue=piWordId.i(lhWordSplitter, 4)) to lbFound end if lbFound if liMax ge 5 begin get_field_value liFile 7 to liValue move (liValue=piWordId.i(lhWordSplitter, 5)) to lbFound end if liPhraseLength ge 7 if lbFound if liMax ge 6 begin get_field_value liFile 8 to liValue move (liValue=piWordId.i(lhWordSplitter, 6)) to lbFound end if liPhraseLength ge 8 if lbFound if liMax ge 7 begin get_field_value liFile 9 to liValue move (liValue=piWordId.i(lhWordSplitter, 7)) to lbFound end if liPhraseLength ge 9 if lbFound if liMax ge 8 begin get_field_value liFile 10 to liValue move (liValue=piWordId.i(lhWordSplitter, 8)) to lbFound end if liPhraseLength ge 10 if lbFound if liMax ge 9 begin get_field_value liFile 11 to liValue move (liValue=piWordId.i(lhWordSplitter, 9)) to lbFound end if liPhraseLength ge 11 if lbFound if liMax ge 10 begin get_field_value liFile 12 to liValue move (liValue=piWordId.i(lhWordSplitter,10)) to lbFound end if liPhraseLength ge 12 if lbFound if liMax ge 11 begin get_field_value liFile 13 to liValue move (liValue=piWordId.i(lhWordSplitter,11)) to lbFound end if liPhraseLength ge 13 if lbFound if liMax ge 12 begin get_field_value liFile 14 to liValue move (liValue=piWordId.i(lhWordSplitter,12)) to lbFound end if liPhraseLength ge 14 if lbFound if liMax ge 13 begin get_field_value liFile 15 to liValue move (liValue=piWordId.i(lhWordSplitter,13)) to lbFound end if lbFound begin increment liArticleCount get_field_value liFile 1 to liValue // FTArtPhr.ARTICLE_ID set value item liValue to 1 if (mod(liArticleCount,50)=0 and ft_searcher@stop_time<>0) begin if (TS_SysTime()>ft_searcher@stop_time) function_return FTIS_SEARCH_TIMEOUT end end until (not(lbFound) or liArticleCount=liMaxArticles) set piArticleCount to liArticleCount set pbIsPopulated to DFTRUE function_return FTIS_NO_ERROR end_function end_class // cFTS_ResultSetPhrase class cFTS_ResultSorter is a cArray item_property_list item_property integer piArticle.i item_property date pdDate.i item_property string psTime.i item_property integer piHits.i end_item_property_list cFTS_ResultSorter procedure AddArticle integer liArticle date ldDate string lsTime integer liHits integer liRow get row_count to liRow set piArticle.i liRow to liArticle set pdDate.i liRow to ldDate set psTime.i liRow to lsTime set piHits.i liRow to liHits end_procedure procedure DumpToArray integer lhArray integer liMax liRow send delete_data of lhArray get row_count to liMax decrement liMax for liRow from 0 to liMax set value of lhArray item liRow to (piArticle.i(self,liRow)) loop end_procedure procedure DumpToChannel integer liChannel integer liMax liRow get row_count to liMax writeln channel liChannel liMax decrement liMax for liRow from 0 to liMax writeln (piArticle.i(self,liRow)) loop end_procedure end_class // cFTS_ResultSorter class cFTS_ResultAttacher is a cDocumentAttacher_vdfq procedure construct_object forward send construct_object // A directory of this name will be created under // the directory holding filelist.cfg: send DoSetHomeDirectoryRelative "FTS" end_procedure function CurrentRecordSubDirectory returns string string lsPrefix get psRootNamePrefix to lsPrefix function_return (lsPrefix+"_results") end_function function CurrentRecordRootName returns string // integer liFile liSearchId string lsPrefix get psRootNamePrefix to lsPrefix get filenumber_ftsearch to liFile get_field_value liFile 1 to liSearchId function_return (lsPrefix+IntToStrRzf(liSearchId,8)) end_function // This function really is not necessary. It instructs the // class about the original name of a given document (in // this case: a constant) if instructed to copy it out // of the 'database'. function CurrentRecordOriginalFileName returns string string lsPrefix get psRootNamePrefix to lsPrefix function_return (lsPrefix+".res") end_function end_class // cFTS_ResultAttacher class cFTS_Searcher is a cArray procedure construct_object forward send construct_object object oFinalSet is a cArray end_object object oResultSorter is a cFTS_ResultSorter end_object object oResultAttacher is a cFTS_ResultAttacher end_object // This class accesses a property of name phTableAccessObject. This is // not defined in this class but should be defined in the encapsulating // object (a cFTS_System object). property integer piSearchTimeout public 5 // Search timeout value in seconds end_procedure item_property_list item_property integer pbNegative.i item_property integer piEstimatedHits.i item_property integer pbIsPhrase.i item_property integer phResultObj.i item_property integer piActualHits.i end_item_property_list cFTS_Searcher procedure DoReset integer liRow liMax lhObj get row_count to liMax decrement liMax for liRow from 0 to liMax get phResultObj.i liRow to lhObj if lhObj send request_destroy_object to lhObj loop send delete_data end_procedure function filenumber_ftartwrd returns integer function_return (piFile.i(phTableAccessObject(self),FTSTABLE_ARTWRD)) end_function function filenumber_ftartphr returns integer function_return (piFile.i(phTableAccessObject(self),FTSTABLE_ARTPHR)) end_function function filenumber_ftarticl returns integer function_return (piFile.i(phTableAccessObject(self),FTSTABLE_ARTICL)) end_function function filenumber_ftword returns integer function_return (piFile.i(phTableAccessObject(self),FTSTABLE_WORD)) end_function function filenumber_ftsearch returns integer function_return (piFile.i(phTableAccessObject(self),FTSTABLE_SEARCH)) end_function function piPhraseLength returns integer function_return (piPhraseLength(phTableAccessObject(self))) end_function function psRootNamePrefix returns string function_return (psRootNamePrefix(phTableAccessObject(self))) end_function procedure add_search_item string lsSearchString integer lbNegative integer lbIsPhrase integer lhObj liRow lhWordSplitter // ************************************************************************************* // If lbIsPhrase is false, we still have to examine whether we have to treat it as // a phrase. This is due to words like this: WINERR=2. We have to break it up in order // to see if it's actually a phrase. ifnot lbIsPhrase begin get phWordsplitterObject to lhWordSplitter send DoReset to lhWordSplitter send DoAddText to lhWordSplitter lsSearchString if (row_count(lhWordSplitter)>1) begin // It's a phrase! move DFTRUE to lbIsPhrase end send DoReset to lhWordSplitter end // ************************************************************************************* get row_count to liRow if lbIsPhrase begin object oResultSet is a cFTS_ResultSetPhrase move self to lhObj end_object end else begin object oResultSet is a cFTS_ResultSetWord move self to lhObj end_object end set psSearchValue of lhObj to lsSearchString set pbNegative of lhObj to lbNegative set piArticleCount of lhObj to 0 set pbIsPopulated of lhObj to DFFALSE // Not populated set pbNegative.i liRow to lbNegative set pbIsPhrase.i liRow to lbIsPhrase set piEstimatedHits.i liRow to -1 // Don't know set piActualHits.i liRow to -1 // Don't know set phResultObj.i liRow to lhObj end_procedure function InterpreteSearchString string lsSearchString returns integer integer liItm liMax lsItem integer lbInPhrase lbErrorCode lbNegative lbNegativePhrase string lsWord lsPhrase move FTIS_NO_ERROR to lbErrorCode get HowManyWords (trim(lsSearchString)) " " to liMax move DFFALSE to lbInPhrase move "" to lsPhrase for liItm from 1 to liMax get ExtractWord lsSearchString " " liItm to lsWord // First we sort out the negative positive thing: ifnot lbInPhrase begin if (left(lsWord,1)="-") begin move DFTRUE to lbNegative move (trim(StringRightBut(lsWord,1))) to lsWord // Note lsWord may be empty after this end else begin if (left(lsWord,1)="+") begin move DFFALSE to lbNegative move (trim(StringLeftBut(lsWord,1))) to lsWord // Note lsWord may be empty after this end end end else move DFFALSE to lbNegative if (lsWord<>"") begin if lbInPhrase begin move (lsPhrase*lsWord) to lsPhrase if (right(lsWord,1)='"') begin move (StringLeftBut(lsPhrase,1)) to lsPhrase send add_search_item lsPhrase lbNegativePhrase DFTRUE move "" to lsPhrase move DFFALSE to lbInPhrase end end else begin if (left(lsWord,1)='"') begin // If phrase start move (replace('"',lsWord,"")) to lsWord move DFTRUE to lbInPhrase move lsWord to lsPhrase move lbNegative to lbNegativePhrase if (right(lsWord,1)='"') begin // If the phrase is terminated immediately. move (StringLeftBut(lsPhrase,1)) to lsPhrase send add_search_item lsPhrase lbNegativePhrase DFTRUE move "" to lsPhrase move DFFALSE to lbInPhrase end move "" to lsWord end else send add_search_item lsWord lbNegative DFFALSE end end loop if lbInPhrase send add_search_item lsWord lbNegativePhrase DFTRUE function_return lbErrorCode end_function procedure CalculateMaxPossibleHits integer liMax liRow lhObj liEstimatedHits get row_count to liMax decrement liMax for liRow from 0 to liMax get phResultObj.i liRow to lhObj get iEstimatedHits of lhObj to liEstimatedHits set piEstimatedHits.i liRow to liEstimatedHits loop end_procedure procedure PrioritizeTheSearch send sort_rows 0 1 // ValueCantBePresent NumberOfHits end_procedure function iDoSearchRow integer liRow integer liCurrentResultSize returns integer integer lhResultObj liEstimatedHits liError liGarbage get phResultObj.i liRow to lhResultObj get piEstimatedHits.i liRow to liEstimatedHits move FTIS_NO_ERROR to liError if liRow begin // not the first row ifnot (pbNegative.i(self,liRow)) begin // We only do this if we have less than 1000 estimated: if (liEstimatedHits<1000 and liCurrentResultSize>25) get iBuildTheSet of lhResultObj to liError end ifnot liError get bDoLogicalAnd of (phResultObj.i(self,0)) lhResultObj to liError end else begin // First row // if (liEstimatedHits>5000) move FTIS_TOO_MANY to liError // else get iBuildTheSet of lhResultObj to liGarbage get iBuildTheSet of lhResultObj to liError end function_return liError end_function procedure BuildFinalSet integer lhResultSet lhFinalResultSet liMax liArticle liCounter move (phResultObj.i(self,0)) to lhResultSet move (oFinalSet(self)) to lhFinalResultSet get item_count of lhResultSet to liMax decrement liMax move 0 to liCounter for liArticle from 0 to liMax if (integer(value(lhResultSet,liArticle))) begin set value of lhFinalResultSet item liCounter to liArticle increment liCounter end loop end_procedure function DoPostSearchProcessing returns integer end_function // This is a low level access to the search function // 0 means OK, result set was generated // liMaxSeconds=0 => no limit! function iDoSearch string lsSearchString integer liMaxSeconds returns integer integer liError lhResultSet liMax liRow liCurrentResultSize send DoReset move FTIS_NO_ERROR to liError get InterpreteSearchString lsSearchString to liError send delete_data to (oFinalSet(self)) if liMaxSeconds begin get TS_SysTime to ft_searcher@stop_time move (ft_searcher@stop_time+liMaxSeconds) to ft_searcher@stop_time move liMaxSeconds to ft_searcher@max_time end else begin move 0 to ft_searcher@stop_time move 0 to ft_searcher@max_time end ifnot liError begin send CalculateMaxPossibleHits send PrioritizeTheSearch if (row_count(self)) begin ifnot (pbNegative.i(self,0)) begin get phResultObj.i 0 to lhResultSet get row_count to liMax move 0 to liRow move -1 to liCurrentResultSize while (not(liError) and liRow<liMax) get iDoSearchRow liRow liCurrentResultSize to liError get piArticleCount of lhResultSet to liCurrentResultSize increment liRow end ifnot liError send BuildFinalSet end else move FTIS_NO_POSITIVE to liError end else move FTIS_MISSING_VALUE to liError end // send DoReset ifnot liError get DoPostSearchProcessing to liError function_return liError end_function // iDoSearch function bSelectArticle integer liArticleId returns integer function_return 1 end_function // The ArticleId_ArrayValueToArticleId function has been introduced to get // around the following problem: In Electos the system is built to find // articles by what is known as the DocumentId. But when the search is // completed the array of document ID's is converted into an array of // TimeLine ID's (possibly not even the same number of items). Therefore // this little function with the funny name is needed to allow Electos to // 'get back' to its original DocumentId - Phew! function ArticleId_ArrayValueToArticleId integer liArticleId returns integer function_return liArticleId end_function function iDoSearchActiveSearchRecord returns integer integer liSearchFile integer lhResultSorter integer lhFinalSet integer liMax liItem integer liArticleFile integer liArtId liGenericArtId integer liHitCount integer lbOk integer liOrder integer liChannel integer liError integer liArticleCount date ldFrom ldTo date ldDate string lsSearchString string lsTime string lsStartTime lsStopTime // Used for measuring the duration of the search string lsFileName // Name of sequential file where search result will be written number lnElap // Very temporarily move (oFinalSet(self)) to lhFinalSet // Mark the time we started the search: get MilliSeconds_Systime to lsStartTime // Open output to file in whichs we will store the result: get CurrentRecordAbsoluteFileName of oResultAttacher to lsFileName get SEQ_DirectOutput lsFileName to liChannel get filenumber_ftsearch to liSearchFile get_field_value liSearchFile 3 to lsSearchString // FTSEARCH.SEARCH_STRING get iDoSearch lsSearchString (piSearchTimeout(self)) to liError writeln channel liChannel liError if (liError=FTIS_NO_ERROR) begin get_field_value liSearchFile 8 to ldFrom // FTSEARCH.LOW_DATE_LIMIT get_field_value liSearchFile 9 to ldTo // FTSEARCH.HIGH_DATE_LIMIT if (integer(ldTo)=0) move LargestPossibleDate to ldTo // LargestPossibleDate (constant defined in dates.nui) get filenumber_ftarticl to liArticleFile move (oResultSorter(self)) to lhResultSorter send delete_data of lhResultSorter get result_count to liMax decrement liMax for liItem from 0 to liMax // Go through the articles of the result set get result_article liItem to liArtId // Electos stunt: get ArticleId_ArrayValueToArticleId liArtId to liGenericArtId clear liArticleFile set_field_value liArticleFile 1 to liGenericArtId // FTArticl.Article_Id vfind liArticleFile 1 EQ // find eq FTArticl by index.1 if (found) begin get_field_value liArticleFile 2 to ldDate // FTArticl.Date move (ldDate>=ldFrom and ldDate<=ldTo) to lbOk if lbOk get bSelectArticle liArtId to lbOk if lbOK begin get_field_value liArticleFile 3 to lsTime // FTArticl.Time get_field_value liArticleFile 4 to liHitCount // FTArticl.Hit_Count send AddArticle of lhResultSorter liArtId ldDate lsTime liHitCount end end loop // Now we check if we need to sort the articles according to date or hit count: get_field_value liSearchFile 10 to liOrder if (liOrder=1) send sort_rows_descending of lhResultSorter 1 2 // Date, Time if (liOrder=2) send sort_rows_descending of lhResultSorter 3 // Hit counter send DumpToChannel of lhResultSorter liChannel // Write to result file send DumpToArray of lhResultSorter lhFinalSet get row_count of lhResultSorter to liArticleCount send delete_data of lhResultSorter end else begin move 0 to liArticleCount writeln channel liChannel (FT_ErrorText(liError)) end send SEQ_CloseOutput liChannel get MilliSeconds_Systime to lsStopTime // Mark the stoptime if (liError=FTIS_NO_ERROR and liArticleCount=0) move FTIS_NO_ITEMS_FOUND to liError reread liSearchFile set_field_value liSearchFile 4 to (dSysDate()) // SEARCH_DATE set_field_value liSearchFile 5 to (sSysTime()) // SEARCH_TIME set_field_value liSearchFile 6 to liArticleCount // RESULT_COUNT move (MilliSeconds_Elapsed(lsStartTime,lsStopTime)) to lnElap set_field_value liSearchFile 7 to lnElap // EXECUTION_TIME set_field_value liSearchFile 11 to liError // ERROR_CODE saverecord liSearchFile unlock function_return liError end_function function iNextAvailableSearchId returns integer integer liFile liNewId get filenumber_ftsearch to liFile clear liFile set_field_value liFile 1 to 99999999 // // FTSEARCH.SEARCH_ID vfind liFile 1 LT if (found) get_field_value liFile 1 to liNewId else move 0 to liNewId increment liNewId clear liFile function_return liNewId end_function procedure DoPreCreateSearchRecord end_procedure procedure DoCreateSearch integer liUserId string lsSearchString date ldFrom date ldTo integer liOrderby integer liSearchFile liNewId liError get filenumber_ftsearch to liSearchFile lock get iNextAvailableSearchId to liNewId clear liSearchFile set_field_value liSearchFile 1 to liNewId // FTSEARCH.SEARCH_ID set_field_value liSearchFile 2 to liUserId // FTSEARCH.USER_ID set_field_value liSearchFile 3 to lsSearchString // FTSEARCH.SEARCH_STRING set_field_value liSearchFile 8 to ldFrom // FTSEARCH.LOW_DATE_LIMIT set_field_value liSearchFile 9 to ldTo // FTSEARCH.HIGH_DATE_LIMIT set_field_value liSearchFile 10 to liOrderBy // FTSEARCH.ORDER_BY send DoPreCreateSearchRecord saverecord liSearchFile unlock get iDoSearchActiveSearchRecord to liError end_procedure function result_count returns integer function_return (item_count(oFinalSet(self))) end_function function result_article integer liItm returns integer function_return (value(oFinalSet(self),liItm)) end_function procedure end_construct_object integer lhSelf forward send end_construct_object move self to lhSelf set phSearcherObject to lhSelf // This is resolved in the encapsulating cFTS_System object end_procedure end_class // cFTS_Searcher