/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Written by Sergei A. Golubchik, who has a shared copyright to this code */ #include "ftdefs.h" /* search with boolean queries */ typedef struct st_all_in_one { MI_INFO *info; uint keynr; uchar *keybuff; MI_KEYDEF *keyinfo; my_off_t key_root; TREE dtree; byte *start, *end; uint total_yes, total_no; } ALL_IN_ONE; typedef struct st_ft_superdoc { FT_DOC doc; //FT_WORD *word_ptr; //double tmp_weight; uint yes; uint no; uint wno; ALL_IN_ONE *aio; } FT_SUPERDOC; static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), FT_SUPERDOC *p1, FT_SUPERDOC *p2) { if (p1->doc.dpos < p2->doc.dpos) return -1; if (p1->doc.dpos == p2->doc.dpos) return 0; return 1; } static int walk_and_copy(FT_SUPERDOC *from, uint32 count __attribute__((unused)), FT_DOC **to) { if (from->yes == from->aio->total_yes && !from->no) { (*to)->dpos=from->doc.dpos; (*to)->weight=from->doc.weight; (*to)++; } return 0; } static double _wghts[11]={ 0.131687242798354, 0.197530864197531, 0.296296296296296, 0.444444444444444, 0.666666666666667, 1.000000000000000, 1.500000000000000, 2.250000000000000, 3.375000000000000, 5.062500000000000, 7.593750000000000}; static double *wghts=_wghts+5; // wghts[i] = 1.5**i static double _nwghts[11]={ -0.065843621399177, -0.098765432098766, -0.148148148148148, -0.222222222222222, -0.333333333333334, -0.500000000000000, -0.750000000000000, -1.125000000000000, -1.687500000000000, -2.531250000000000, -3.796875000000000}; static double *nwghts=_nwghts+5; // nwghts[i] = -0.5*1.5**i int do_boolean(ALL_IN_ONE *aio, uint nested __attribute__((unused)), int yesno __attribute__((unused)), int plusminus, bool pmsign) { int r, res; uint keylen, wno; FT_SUPERDOC sdoc, *sptr; TREE_ELEMENT *selem; FT_WORD w; FTB_PARAM param; #ifdef EVAL_RUN return 1; #endif /* EVAL_RUN */ param.prev=' '; for(wno=1; (res=ft_get_word(&aio->start,aio->end,&w,¶m)); wno++) { r=plusminus+param.plusminus; if (param.pmsign^pmsign) w.weight=nwghts[(r>5)?5:((r<-5)?-5:r)]; else w.weight=wghts[(r>5)?5:((r<-5)?-5:r)]; if (param.yesno>0) aio->total_yes++; if (param.yesno<0) aio->total_no++; switch (res) { case FTB_LBR: // ( //if (do_boolean(aio,nested+1,my_yesno,plusminus+my_plusminus)) // return 1; // ??? break; case 1: // word keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,&w,0); keylen-=HA_FT_WLEN; r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, SEARCH_FIND | SEARCH_PREFIX, aio->key_root); while (!r) { if (param.trunc) r=_mi_compare_text(default_charset_info, aio->info->lastkey+1,keylen-1, aio->keybuff+1,keylen-1,0); else r=_mi_compare_text(default_charset_info, aio->info->lastkey,keylen, aio->keybuff,keylen,0); if (r) break; sdoc.doc.dpos=aio->info->lastpos; /* saving document matched into dtree */ if (!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); if (selem->count==1) /* document's first match */ { sptr->yes=0; sptr->no=0; sptr->doc.weight=0; sptr->aio=aio; sptr->wno=0; } if (sptr->wno != wno) { if (param.yesno>0) sptr->yes++; if (param.yesno<0) sptr->no++; sptr->wno=wno; } sptr->doc.weight+=w.weight; if (_mi_test_if_changed(aio->info) == 0) r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, aio->info->lastkey_length, SEARCH_BIGGER, aio->key_root); else r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, aio->info->lastkey_length, SEARCH_BIGGER, aio->key_root); } break; case FTB_RBR: // ) break; } } return 0; } FT_DOCLIST *ft_boolean_search(MI_INFO *info, uint keynr, byte *query, uint query_len) { ALL_IN_ONE aio; FT_DOC *dptr; FT_DOCLIST *dlist=NULL; aio.info=info; aio.keynr=keynr; aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; aio.keyinfo=aio.info->s->keyinfo+keynr; aio.key_root=aio.info->s->state.key_root[keynr]; aio.start=query; aio.end=query+query_len; aio.total_yes=aio.total_no=0; init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0, NULL, NULL); if (do_boolean(&aio,0,0,0,0)) goto err; dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0)); if(!dlist) goto err; dlist->ndocs=aio.dtree.elements_in_tree; dlist->curdoc=-1; dlist->info=aio.info; dptr=dlist->doc; tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right); dlist->ndocs=dptr - dlist->doc; err: delete_tree(&aio.dtree); return dlist; }