home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / myisam / ft_search.c < prev    next >
C/C++ Source or Header  |  2000-11-16  |  6KB  |  230 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.  
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.  
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17. /* Written by Sergei A. Golubchik, who has a shared copyright to this code */
  18.  
  19. #include "ftdefs.h"
  20.  
  21. /* queries isam and returns list of documents matched */
  22.  
  23. typedef struct st_all_in_one {
  24.   MI_INFO    *info;
  25.   uint          keynr;
  26.   uchar      *keybuff;
  27.   MI_KEYDEF  *keyinfo;
  28.   my_off_t    key_root;
  29.   TREE          dtree;
  30. } ALL_IN_ONE;
  31.  
  32. typedef struct st_ft_superdoc {
  33.     FT_DOC   doc;
  34.     FT_WORD *word_ptr;
  35.     double   tmp_weight;
  36. } FT_SUPERDOC;
  37.  
  38. static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2)
  39. {
  40.   if (p1->doc.dpos < p2->doc.dpos)
  41.     return -1;
  42.   if (p1->doc.dpos == p2->doc.dpos)
  43.     return 0;
  44.   return 1;
  45. }
  46.  
  47. static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
  48. {
  49.   uint           keylen, r, doc_cnt;
  50. #ifdef EVAL_RUN
  51.   uint           cnt;
  52.   double       sum, sum2, suml;
  53. #endif /* EVAL_RUN */
  54.   FT_SUPERDOC  sdoc, *sptr;
  55.   TREE_ELEMENT *selem;
  56. #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
  57.   float tmp_weight;
  58. #else
  59. #error
  60. #endif
  61.  
  62.   word->weight=LWS_FOR_QUERY;
  63.  
  64.   keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0);
  65. #ifdef EVAL_RUN
  66.   keylen-=1+HA_FT_WLEN;
  67. #else /* EVAL_RUN */
  68.   keylen-=HA_FT_WLEN;
  69. #endif /* EVAL_RUN */
  70.  
  71. #ifdef EVAL_RUN
  72.   sum=sum2=suml=
  73. #endif /* EVAL_RUN */
  74.   doc_cnt=0;
  75.  
  76.   r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen,
  77.            SEARCH_FIND | SEARCH_PREFIX, aio->key_root);
  78.  
  79.   while(!r)
  80.   {
  81.     if (_mi_compare_text(default_charset_info,
  82.              aio->info->lastkey,keylen,
  83.              aio->keybuff,keylen,0)) break;
  84.  
  85. #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
  86. #ifdef EVAL_RUN
  87.     mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
  88. #else /* EVAL_RUN */
  89.     mi_float4get(tmp_weight,aio->info->lastkey+keylen);
  90. #endif /* EVAL_RUN */
  91. #else
  92. #error
  93. #endif
  94.     if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */
  95.  
  96. #ifdef EVAL_RUN
  97.     cnt=*(byte *)(aio->info->lastkey+keylen);
  98. #endif /* EVAL_RUN */
  99.  
  100.     sdoc.doc.dpos=aio->info->lastpos;
  101.  
  102.     /* saving document matched into dtree */
  103.     if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1;
  104.  
  105.     sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
  106.  
  107.     if(selem->count==1) /* document's first match */
  108.       sptr->doc.weight=0;
  109.     else
  110.       sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
  111.  
  112.     sptr->word_ptr=word;
  113.     sptr->tmp_weight=tmp_weight;
  114.  
  115.     doc_cnt++;
  116. #ifdef EVAL_RUN
  117.     sum +=cnt;
  118.     sum2+=cnt*cnt;
  119.     suml+=cnt*log(cnt);
  120. #endif /* EVAL_RUN */
  121.  
  122.     if (_mi_test_if_changed(aio->info) == 0)
  123.     r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey,
  124.               aio->info->lastkey_length, SEARCH_BIGGER,
  125.               aio->key_root);
  126.     else
  127.     r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey,
  128.              aio->info->lastkey_length, SEARCH_BIGGER,
  129.              aio->key_root);
  130.   }
  131.   if(doc_cnt) {
  132.     word->weight*=GWS_IN_USE;
  133.     if(word->weight < 0) word->weight=0;
  134.   }
  135.  
  136.   return 0;
  137. }
  138.  
  139. static int walk_and_copy(FT_SUPERDOC *from,
  140.              uint32 count __attribute__((unused)), FT_DOC **to)
  141. {
  142.     from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
  143.     (*to)->dpos=from->doc.dpos;
  144.     (*to)->weight=from->doc.weight;
  145.     (*to)++;
  146.     return 0;
  147. }
  148.  
  149. static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b)
  150. {
  151.     return sgn(b->weight - a->weight);
  152. }
  153.  
  154. FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key,
  155.                 uint key_len, my_bool presort)
  156. {
  157.   TREE         *wtree;
  158.   ALL_IN_ONE aio;
  159.   FT_DOCLIST *dlist;
  160.   FT_DOC     *dptr;
  161.  
  162. /* black magic ON */
  163.   if ((int) (keynr = _mi_check_index((MI_INFO *)info,keynr)) < 0)
  164.     return NULL;
  165.   if (_mi_readinfo((MI_INFO *)info,F_RDLCK,1))
  166.     return NULL;
  167. /* black magic OFF */
  168.  
  169.   dlist=NULL;
  170.   aio.info=(MI_INFO *)info;
  171.   aio.keynr=keynr;
  172.   aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length;
  173.   aio.keyinfo=aio.info->s->keyinfo+keynr;
  174.   aio.key_root=aio.info->s->state.key_root[keynr];
  175.  
  176.   if (!(wtree=ft_parse(NULL,key,key_len))) return NULL;
  177.  
  178.   init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0,
  179.         NULL);
  180.  
  181.   if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio,
  182.         left_root_right))
  183.     goto err;
  184.  
  185.   dlist=(FT_DOCLIST *) my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*
  186.                  (aio.dtree.elements_in_tree-1),MYF(0));
  187.   if (!dlist)
  188.     goto err;
  189.  
  190.   dlist->ndocs=aio.dtree.elements_in_tree;
  191.   dlist->curdoc=-1;
  192.   dlist->info=aio.info;
  193.   dptr=dlist->doc;
  194.  
  195.   tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr,
  196.         left_root_right);
  197.  
  198.   if (presort)
  199.   {
  200.     qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
  201.   }
  202.  
  203. err:
  204.   delete_tree(&aio.dtree);
  205.   delete_tree(wtree);
  206.   my_free((char*) wtree,MYF(0));
  207.   return dlist;
  208. }
  209.  
  210. int ft_read_next(FT_DOCLIST *handler, char *record)
  211. {
  212.   MI_INFO *info=handler->info;
  213.  
  214.   if (++handler->curdoc >= handler->ndocs)
  215.   {
  216.     --handler->curdoc;
  217.     return HA_ERR_END_OF_FILE;
  218.   }
  219.  
  220.   info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
  221.  
  222.   info->lastpos=handler->doc[handler->curdoc].dpos;
  223.   if (!(*info->read_record)(info,info->lastpos,record))
  224.   {
  225.     info->update|= HA_STATE_AKTIV;        /* Record is read */
  226.     return 0;
  227.   }
  228.   return my_errno;
  229. }
  230.