ft_search.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:6k
源码类别:

MySQL数据库

开发平台:

Visual C++

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