source: pmb4.2/trunk/fuentes/pmb/classes/analyse_query.class.php @ 815

Last change on this file since 815 was 815, checked in by jrpelegrina, 4 years ago

Initial release of pmb 4.2

  • Property svn:executable set to *
File size: 48.7 KB
Line 
1<?php
2// +-------------------------------------------------+
3// © 2002-2004 PMB Services / www.sigb.net pmb@sigb.net et contributeurs (voir www.sigb.net)
4// +-------------------------------------------------+
5// $Id: analyse_query.class.php,v 1.60.2.1 2015-09-14 07:20:23 jpermanne Exp $
6
7if (stristr($_SERVER['REQUEST_URI'], ".class.php")) die("no access");
8
9require_once($class_path."/stemming.class.php");
10//Structure de stockage d'un terme
11class term {
12        public $word;           //mot (si pas sous expression)
13        public $operator;       //opérateur (and, or ou vide)
14        public $sub;            //sous expression = tableau de term
15        public $not;            //Négation du terme (not)
16        public $literal;        //Le terme est entier (il y avait des guillemets)
17        public $start_with; //L'expression doit commencer par
18        public $pound;          //poids du terme
19        public $special_term;   //on spécifie si le terme particulier
20       
21        //Constructeur
22        function term($word,$literal,$not,$start_with,$operator,$sub,$pound=1,$special_term='') {
23                $this->word=$word;
24                $this->operator=$operator;
25                $this->sub=$sub;       
26                $this->not=$not;               
27                $this->literal=$literal;
28                $this->start_with=$start_with;
29                $this->pound=$pound;
30                $this->special_term = $special_term;
31        }
32}
33
34//Classe d'analyse d'une requête booléenne
35class analyse_query {
36        public $current_car;            //Caractère courant analysé
37        public $parenthesis;            //Est-ce une sous expression d'une expression ?
38        public $operator="";            //Opérateur du terme en cours de traitement
39        public $neg=0;                          //Négation appliquée au terme en cours de traitement
40        public $guillemet=0;            //Le terme en cours de traitement est-il entouré par des guillemets
41        public $start_with=0;           //Le terme en cours est-il à traiter avec commence par ?
42        public $input;                          //Requete à analyser
43        public $term="";                        //Terme courant
44        public $literal=0;                      //Le terme en cours de traitement est-il litéral ?
45        public $tree=array();           //Arbre de résultat
46        public $error=0;                        //Y-a-t-il eu un erreur pendant le traitement
47        public $error_message="";       //Message d'erreur
48        public $input_html="";          //Affichage html de la requête initiale (éventuellement avec erreur surlignée)
49        public $search_linked_words=1;  //rechercher les mots liés pour le mot
50        public $keep_empty;                     //on garde les mots vides
51        public $positive_terms;         //liste des termes positifs
52        public $empty_words;            //Liste des mots vides présents dans la recherche initiale
53        public $stemming;
54        protected $default_operator; 
55        protected $allow_term_troncat_search;
56        protected $exclude_fields;
57        protected $tmp_prefix = 'gestion_searcher_';
58        protected $search_relevant_with_frequency;
59       
60        //Constructeur
61    function analyse_query($input,$debut=0,$parenthesis=0,$search_linked_words=1,$keep_empty=0,$stemming=false) {
62        // remplacement espace insécable 0xA0:  &nbsp;
63        global $empty_word;
64
65        global $pmb_default_operator;
66        global $search_allow_term_troncat_search;
67                global $search_exclude_fields;
68                global $pmb_search_relevant_with_frequency;
69               
70                $this->default_operator = $pmb_default_operator;
71        $this->allow_term_troncat_search = $search_allow_term_troncat_search;
72        $this->exclude_fields = $search_exclude_fields;
73        $this->search_relevant_with_frequency = $pmb_search_relevant_with_frequency;
74       
75                $input=clean_nbsp($input);
76        $this->parenthesis=$parenthesis;
77                $this->current_car=$debut;
78                $this->input=$input;
79                $this->keep_empty=$keep_empty;
80                $this->stemming = $stemming;
81                $this->search_linked_words=$search_linked_words;
82                $this->recurse_analyse();
83        if($this->parenthesis==0){
84                        $this->tree=$this->nettoyage_etoile($this->tree,false);
85                }
86                if($this->stemming){
87                        $this->add_stemming();
88                }
89                // pour remonter les termes exacts, mais ne marche pas pour les autorités. A revoir
90        if(!$parenthesis) {
91                if((!$this->keep_empty && in_array($this->input,$empty_word)===false) || $this->keep_empty) {
92                        $t=new term(trim($this->input,"_~\""),2,0,1,"or",null,0.2);
93                                $this->store_in_tree($t,0);             
94                }               
95                }   
96    }
97   
98    function nettoyage_etoile($tree_array,$is_sub){
99        //Pour chaque terme du tableau
100        foreach($tree_array as $key=>$value){
101                //Si le mot est *
102                if($value->word == "*"){
103                        //On efface si on est dans une sub ou s'il y a d'autres termes
104                        if($is_sub || (count($tree_array)>1)){
105                                unset($tree_array[$key]);
106                        }
107                }elseif(is_array($value->sub) && count($value->sub)){
108                        //Le terme est une sub : on nettoie le tableau de termes de la sub
109                        $tree_array[$key]->sub = $this->nettoyage_etoile($tree_array[$key]->sub,true);
110                        //Si la sub est vide, on l'efface
111                        if(!count($tree_array[$key]->sub)){
112                                unset($tree_array[$key]);
113                        }
114                }
115        }
116         
117        return $tree_array;
118    }
119   
120        // Recherche les synonymes d'un mot 
121    function get_synonymes($mot) {
122        global $dbh;
123                $mot= addslashes($mot);
124                $rqt="select id_mot from mots where mot='".$mot."'";
125                $execute_query=pmb_mysql_query($rqt,$dbh);
126                if (pmb_mysql_num_rows($execute_query)) {                       
127                        //constitution d'un tableau avec le mot et ses synonymes
128                        $r=pmb_mysql_fetch_object($execute_query);
129                        $rqt1="select mot,ponderation from mots,linked_mots where type_lien=1 and num_mot=".$r->id_mot." and mots.id_mot=linked_mots.num_linked_mot";
130                        $execute_query1=pmb_mysql_query($rqt1,$dbh);                                           
131                        if (pmb_mysql_num_rows($execute_query1)) {
132                                while (($r1=pmb_mysql_fetch_object($execute_query1))) {
133                                        $synonymes[$r1->mot]=$r1->ponderation;                                 
134                                }
135                        }
136                }               
137                return($synonymes);
138         }
139   
140        function nettoyage_mot_vide($string) {
141                //Récupération des mots vides
142                global $empty_word;
143                if (!is_array($empty_word)) $empty_word=array();
144                //Supression des espaces avant et après le terme
145                $string = trim($string);
146                //Décomposition en mots du mot nettoyé (ex : l'arbre devient l arbre qui donne deux mots : l et arbre)
147                $words=array();
148                if ($string) {
149                        $words=explode(" ",$string);
150                }
151                //Variable de stockage des mots restants après supression des mots vides
152                $words_empty_free=array();
153                //Pour chaque mot
154                for ($i=0; $i<count($words); $i++) {
155                        $words[$i]=trim($words[$i]);
156                        //Vérification que ce n'est pas un mot vide
157                        if (($this->keep_empty)||(in_array($words[$i],$empty_word)===false)) {
158                                //Si ce n'est pas un mot vide, on stoque
159                                $words_empty_free[]=$words[$i];
160                        }
161                }
162                return $words_empty_free;
163        }
164       
165        function calcul_term(&$t,$mot,$litteral,$ponderation) {         
166                // Littéral ?   
167                if($litteral) {
168                        // Oui c'est un mot littéral
169                        $t->word=$mot;
170                        $t->literal=1;
171                        // fin
172                        return;
173                } else {
174                        // Non ce n'est pas un mot littéral
175                        // Un espace dans le mot?
176                        if(strchr($mot, ' ')) {
177                                // Oui ula un espace
178                                $t->word=$mot;
179                                $t->literal=1;
180                                // fin
181                                return;                         
182                        } else {
183                                // Non, pas d'espace dans le mot
184                                // Nettoyage des caractères
185                                $mot_clean = convert_diacrit($mot);
186                               
187                                $mot_clean = pmb_alphabetic('^a-z0-9\s\*', ' ',pmb_strtolower($mot_clean));             
188                                // Nettoyage des mots vides
189                                $mot_clean_vide=$this->nettoyage_mot_vide($mot_clean);
190                                // Combien de mots reste-t-il ?
191                                if(count($mot_clean_vide) > 1) {
192                                        // Plusieurs                                   
193                                        if (!count($t->sub)) $op_sub=''; else $op_sub="or";                             
194                                        foreach($mot_clean_vide as $key => $word) {
195                                                if($key == 0){
196                                                        $terms[]=new term($word,0,0,0,"","",$ponderation);
197                                                }else{
198                                                        $terms[]=new term($word,0,0,0,$op_sub,"",$ponderation);
199                                                }
200                                                $op_sub="or";
201                                        }
202                                        $t->sub=$terms;
203                                } elseif(count($mot_clean_vide) == 1)  {
204                                        // Un seul
205                                        $t->word=$mot_clean_vide[0];
206                                        $t->literal=0;
207                                        // fin
208                                        return;                         
209                                }else return;                           
210                        }
211                }
212        }
213       
214    //Stockage d'un terme dans l'arbre de résultat
215        function store_in_tree($t,$search_linked_words) {
216                // Mot ou expression ?
217                if (!$t->sub && $t->word) {
218                        //C'est un mot
219                        // Synonyme activé && ce n'est pas une expression commence par '_xx*' ?
220                        if ($search_linked_words && !$this->start_with) { 
221                                // Oui, Synonyme activé
222                                // C'est un littéral ?
223                                if ($t->literal) {
224                                        // Oui, c'est un littéral
225                                        // Recherche de synonymes
226                                        $synonymes=$this->get_synonymes($t->word);
227                                        $mots=$t->word;
228                                       
229                                        // Y-a-t'il des synonymes ?
230                                        if($synonymes) {                                               
231                                                // Oui il y a des synonymes                                                                                                     
232                                                // Pour chaque synonyme et le terme ajout à $t->sub
233                                                $op_sub="";
234                                                foreach($synonymes as $synonyme => $ponderation) {
235                                                       
236                                                        $t->sub[]=new term($synonyme,0,0,0,$op_sub,"",$ponderation);   
237                                                        $this->calcul_term($t->sub[count($t->sub)-1],$synonyme,0,$ponderation);
238                                                        $op_sub="or";
239                                                }               
240                                                // Ajout du term force litéral à 1     
241                                                $t->word="";
242                                                $t->sub[]=new term($mots,1,0,0,$op_sub,"",$t->pound);   
243                                                $this->calcul_term($t->sub[count($t->sub)-1],$mots,1,$t->pound);
244                                                $op_sub="or";
245                                               
246                                        }                                       
247                                } else {
248                                        // Non, ce n'est pas un littéral
249                                        // Recherche de synonymes
250                                        $synonymes=$this->get_synonymes($t->word);
251                                        $mots=$t->word;
252                                        $t->word="";
253                                       
254                                        // Y-a-t'il des synonymes ?
255                                        if($synonymes) {                                               
256                                                // Oui il y a des synonymes
257                                                foreach($synonymes as $synonyme => $ponderation) {                                                                                                                             
258                                                        $liste_mots[$synonyme]=$ponderation;
259                                                }                                                                                       
260                                        } 
261                                        // Suite et, Non, il n'y a pas de synonyme
262                                        // Nettoyage des caractères
263                                        $mot_clean = convert_diacrit($mots);                                   
264                                        $mot_clean = pmb_alphabetic('^a-z0-9\s\*', ' ',pmb_strtolower($mot_clean));             
265                                        // Nettoyage des mots vides
266                                        $mot_clean_vide=$this->nettoyage_mot_vide($mot_clean);
267                                       
268                                        // Pour chaque mot nettoyer
269                                        if(count($mot_clean_vide)) foreach($mot_clean_vide as $word) {                                         
270                                                // Recherche de synonymes
271                                                $synonymes_clean=$this->get_synonymes($word);                                                                   
272                                                // Pour chaque synonyme et le terme ajout à $t->sub
273                                                if(count($synonymes_clean))foreach($synonymes_clean as $synonyme => $ponderation) {                                                                     
274                                                        $liste_mots[$synonyme]=$ponderation;                                           
275                                                }                                                                                                       
276                                        }
277                                                                                       
278                                        // ajout des mots nettoyés
279                                        if(count($mot_clean_vide))foreach($mot_clean_vide as $word) {
280                                                $liste_mots[$word]=$t->pound;           
281                                        }
282                                               
283                                        if (!count($t->sub)) $op_sub=''; else $op_sub="or";             
284                                        if(count($liste_mots) > 1) {
285                                                $t->word="";
286                                                // Plusieurs mots                                                                       
287                                                foreach($liste_mots as $word => $ponderation) {
288                                                        $t->sub[]=new term($word,0,0,0,$op_sub,"",$ponderation);       
289                                                        $this->calcul_term($t->sub[count($t->sub)-1],$word,0,$ponderation);
290                                                        $op_sub="or";
291                                                }
292                                                //$t->sub=$terms;
293                                        } elseif(count($liste_mots) == 1)  {
294                                                // Un seul mot
295                                                foreach($liste_mots as $word=> $ponderation) {
296                                                        $t->word=$word;         
297                                                }                                                       
298                                        } else return;
299                                }                               
300                        } else {
301                                // Non, Synonyme désactivé
302                                // C'est un littéral ?
303                                if ($t->literal) {
304                                        // Oui, c'est un littéral
305                                        // plus rien à faire                                   
306                                } else {
307                                        // Non, ce n'est pas un littéral
308                                        // Nettoyage des caractères
309                                        $mot_clean = convert_diacrit($t->word);
310                                       
311                                        $mot_clean = pmb_alphabetic('^a-z0-9\s\*', ' ',pmb_strtolower($mot_clean));
312                                        // Nettoyage des mots vides
313                                        $mot_clean_vide=$this->nettoyage_mot_vide($mot_clean);
314                                        // Combien de mots reste-t-il ?
315                                        if(count($mot_clean_vide) > 1) {
316                                                $t->word="";
317                                                // Plusieurs mots                                       
318                                                if (!count($t->sub)) $op_sub=''; else $op_sub="or";                             
319                                                foreach($mot_clean_vide as $word) {
320                                                        $terms[]=new term($word,0,0,0,$op_sub,"",$ponderation);                 
321                                                        $op_sub="or";
322                                                }
323                                                $t->sub=$terms;
324                                        } elseif(count($mot_clean_vide) == 1)  {
325                                                // Un seul mot
326                                                $t->word=$mot_clean_vide[0];                                                           
327                                        } else return;
328                                }       
329                        }
330                } elseif ($t->sub && !$t->word) {
331                        // C'est une expression :
332                        // Vider opérateur
333                        if (!count($this->tree)) $t->operator="";
334                } else {
335                        //      Ce n'est ni un mot, ni une exrssion: c'est rien                         
336                        return;
337                }
338                // Inscription dans l'arbre
339                $this->tree[]=$t;               
340                //print "<pre>";print_r($this->tree);print"</pre>";                     
341        }
342       
343        //Affichage sous forme RPN du résultat de l'analyse
344        function show_analyse_rpn($tree="") {
345                //Si tree vide alors on prend l'arbre de la classe
346                if ($tree=="") $tree=$this->tree;
347                $r="";
348                //Pour chaque branche ou feuille de l'arbre
349                for ($i=0; $i<count($tree); $i++) {
350                        //Si le terme est un mot
351                        if ($tree[$i]->sub==null) {
352                                //Affichage du mot avec le préfixe N pour terme Normal et L pour terme litéral, C pour Commence par
353                                if ($tree[$i]->start_with) $r.="C "; 
354                                if ($tree[$i]->literal) $r.="L "; else $r.="N ";
355                                $r.=$tree[$i]->word."\n";
356                        } else
357                                //Sinon on analyse l'expression
358                                $r.=$this->show_analyse_rpn($tree[$i]->sub);
359                        //Affichage négation et opérateur si nécessaire
360                        if ($tree[$i]->not) $r.="not\n";
361                        if ($tree[$i]->operator) $r.=$tree[$i]->operator."\n";
362                }
363                return $r;
364        }
365
366        //Affichage sous forme mathématique logique du résultat de l'analyse
367        function show_analyse($tree="") {
368                if ($tree=="") $tree=$this->tree;
369                $r="";
370                for ($i=0; $i<count($tree); $i++) {
371                        if ($tree[$i]->operator) $r.=$tree[$i]->operator." ";
372                        if ($tree[$i]->not) $r.="not";
373                        if ($tree[$i]->sub==null) {
374                                if ($tree[$i]->start_with) $start_w="start with "; else $start_w="";
375                                if ($tree[$i]->not) $r.="(";
376                                $r.=$start_w;
377                                if ($tree[$i]->literal) $r.="\"";
378                                $r.=$tree[$i]->word;
379                                if ($tree[$i]->literal) $r.="\"";
380                                if ($tree[$i]->not) $r.=")";
381                                $r.=" ";
382                        } else { $r.="( ".$this->show_analyse($tree[$i]->sub).") "; }
383                }
384                return $r;
385        }       
386
387        //Construction récursive de la requête SQL
388        function get_query_r($tree,&$select,&$pcount,$table,$field_l,$field_i,$id_field,$neg_parent=0,$main=1) {
389               
390                // Variable globale permettant de choisir si l'on utilise ou non la troncature à droite du terme recherché
391                global $empty_word;
392                $troncat = "";
393                if ($this->allow_term_troncat_search) {
394                         $troncat = "%";
395                }
396               
397                $where="";
398                for ($i=0; $i<count($tree); $i++) {
399                       
400                        if (($tree[$i]->operator)&&($tree[$i]->literal!=2)) $where.=$tree[$i]->operator." ";
401                        if ($tree[$i]->sub==null) {
402                                if ($tree[$i]->literal) $clause="trim(".$field_l.") "; else $clause=$field_i." ";
403                                if ($tree[$i]->not) $clause.="not ";
404                                $clause.="like '";
405                                if (!$tree[$i]->start_with) $clause.="%";
406                                if (!$tree[$i]->literal) $clause.=" ";
407                               
408                                // Condition permettant de détecter si on a déjà une étoile dans le terme
409                                // Si la recherche avec troncature à droite est activee dans l'administration
410                                // et qu'il n'y a pas d'étoiles ajout du '%' à droite du terme
411                                if(strpos($tree[$i]->word,"*") === false) {
412                                        //Si c'est un mot vide, on ne troncature pas
413                                        if (in_array($tree[$i]->word,$empty_word)===false) {
414                                                $clause.=addslashes($tree[$i]->word.$troncat);
415                                        } else {
416                                                $clause.=addslashes($tree[$i]->word);
417                                        }
418                                } else {
419                                       
420                                $clause.=addslashes(str_replace("*","%",$tree[$i]->word));
421                                }
422                               
423                                if (!$tree[$i]->literal) $clause.=" ";
424                                $clause.="%'";
425                                if($tree[$i]->literal!=2) $where.=$clause." ";
426                                //if ((!$tree[$i]->not)&&(!$neg_parent)) {
427                                        if ($select) $select.="+";
428                                        $select.="(".$clause.")";
429                                        if ($tree[$i]->pound && ($tree[$i]->pound!=1)) $select.="*".$tree[$i]->pound;
430                                        $pcount++;
431                                //}
432                        } else { 
433                                if ($tree[$i]->not) $where.="not ";
434                                //$tree[$i]->not
435                                $where.="( ".$this->get_query_r($tree[$i]->sub,$select,$pcount,$table,$field_l,$field_i,$id_field,$tree[$i]->not,0).") "; 
436                        }
437                }
438                if ($main) {
439                        if ($select=="") $select="1";
440                        if ($where=="") $where="0";
441                        $q["select"]="(".$select.")";
442                        $q["where"]="(".$where.")";
443                        $q["post"]=" group by ".$id_field." order by pert desc,".$field_i." asc";
444                        return $q;
445                }
446                else
447                        return $where;
448        }
449
450        //Fonction d'appel de la construction récursive de la requête SQL
451        function get_query($table,$field_l,$field_i,$id_field,$restrict="",$offset=0,$n=0) {
452                $select="";
453                $pcount=0;
454                $q=$this->get_query_r($this->tree,$select,$pcount,$table,$field_l,$field_i,$id_field,0,1);
455                $res="select ".$id_field.",".$q["select"]." as pert from ".$table." where (".$q["where"].")";
456                if ($restrict!="") $res.=" and ".$restrict;
457                $res.=$q["post"];
458                if ($n!=0) $res.=" limit ".$offset.",".$n;
459                return $res;
460        }
461       
462        function get_query_members($table,$field_l,$field_i,$id_field,$restrict="",$offset=0,$n=0,$is_fulltext=false) {
463                global $pmb_search_full_text;
464                if (($is_fulltext)&&($pmb_search_full_text)) $q=$this->get_query_full_text($table,$field_l,$field_i,$id_field); else {
465                        $select="";
466                        $pcount=0;
467                        $q=$this->get_query_r($this->tree,$select,$pcount,$table,$field_l,$field_i,$id_field,0,1);
468                }
469                if ($restrict) $q["restrict"]=$restrict;
470                return $q;
471        }
472       
473        //Adaptation de la recherche pour notices_mots_global_index
474        function get_query_mot($field_id,$table_mot,$field_mot,$table_term,$field_term,$restrict=array(),$neg_restrict=false,$all_fields=false) {
475                if(count($this->tree)){
476                        //return $this->get_query_r_mot($this->tree,$field_id,$table_mot,$field_mot,$table_term,$field_term,$restrict,$neg_restrict);
477                        return $this->get_query_r_mot_with_table_tempo_all($this->tree,$field_id,$table_mot,$field_mot,$table_term,$field_term,$restrict,$neg_restrict,$all_fields);
478                }else{
479                        return  "select $field_id from $table_mot where $field_id = 0";
480                }
481        }
482       
483        function get_query_r_mot_with_table_tempo_all($tree,$field_id,$table_mot,$field_mot,$table_term,$field_term,$restrict,$neg_restrict=false,$all_fields=false) {
484        // Variable globale permettant de choisir si l'on utilise ou non la troncature à droite du terme recherché
485                global $empty_word;
486                global $dbh;
487                $temporary_table = $last_table = "";
488                $troncat = "";
489                if ($this->allow_term_troncat_search) {
490                        $troncat = "%";
491                }
492                $lang_restrict = $field_restrict = array();
493                for($i=0 ; $i<count($restrict) ; $i++){
494                        if($restrict[$i]['field'] == "lang"){
495                                $lang_restrict[] = $restrict[$i];
496                        }else{
497                                $field_restrict[] = $restrict[$i];
498                        }
499                }
500                $restrict = $field_restrict;
501                for ($i=0; $i<count($tree); $i++) {
502                        $elem_query ="";
503                        if($tree[$i]->sub){
504                                $elem_query = $this->get_query_r_mot_with_table_tempo_all($tree[$i]->sub,$field_id,$table_mot,$field_mot,$table_term,$field_term,$restrict,$neg_restrict,$all_fields);
505                        }else{
506                                if($tree[$i]->word !=  "*") {
507                                        if($tree[$i]->literal == 0){
508                                                // on commence...
509                                                //$elem_query = "select distinct $field_id from words straight_join $table_mot on num_word = id_word where ";
510                                                $elem_query = "select distinct $field_id from $table_mot where pond>0 and ";
511                                                $qw = "select distinct id_word from words where ".(count($lang_restrict)>0 ? $this->get_field_restrict($lang_restrict,$neg_restrict)." and ": "");
512                                               
513                                                //on applique la restriction si besoin
514                                                if($restrict){
515                                                        $elem_query.= $this->get_field_restrict($restrict,$neg_restrict)." and ";
516                                                }
517                                                $table= $table_mot;
518                                                //on ajoute le terme
519                                                //$elem_query.= " words.".$field_mot." ";
520                                                $qw.= " words.".$field_mot." ";
521                                                if(strpos($tree[$i]->word, "*") !== false || $this->allow_term_troncat_search){
522                                                        //                                              if($i==0 && $tree[$i]->not){
523                                                        //                                                      $elem_query.= "not ";
524                                                        //                                              }
525                                                        //$elem_query.="like '";
526                                                        $qw.="like '";
527                                                        if (strpos($tree[$i]->word,"*") === false) {
528                                                                //Si c'est un mot vide, on ne troncature pas
529                                                                if (in_array($tree[$i]->word,$empty_word)===false) {
530                                                                        //$elem_query.=addslashes($tree[$i]->word.$troncat);
531                                                                        $qw.=addslashes($tree[$i]->word.$troncat);
532                                                                } else {
533                                                                        //$elem_query.=addslashes($tree[$i]->word);
534                                                                        $qw.=addslashes($tree[$i]->word);
535                                                                }
536                                                        } else {
537                                                                //$elem_query.=addslashes(str_replace("*","%",$tree[$i]->word));
538                                                                $qw.=addslashes(str_replace("*","%",$tree[$i]->word));
539                                                        }
540                                                        //$elem_query.="'";
541                                                        $qw.="'";
542                                                }else{
543                                                        //                                              if($i==0 && $tree[$i]->not){
544                                                        //                                                      $elem_query.= "!";
545                                                        //                                              }
546                                                        //$elem_query.="='".addslashes($tree[$i]->word)."'";
547                                                        $qw.="='".addslashes($tree[$i]->word)."'";
548                                                }
549                                               
550                                                $tw = array();
551                                                $rw = pmb_mysql_query($qw,$dbh);
552                                                if(pmb_mysql_num_rows($rw)) {
553                                                        while($o = pmb_mysql_fetch_object($rw) ) {
554                                                                $tw[]=$o->id_word;
555                                                        }
556                                                }
557                                                $sw=0;
558                                                if(count($tw)) {
559                                                        $sw=implode(',',$tw);
560                                                }
561                                               
562                                                $elem_query.= "num_word in($sw)";
563
564                                                if($tree[$i]->start_with){
565                                                        $elem_query.=" and position ='1'";
566                                                }
567                                        }else if ($tree[$i]->literal == 1){
568                                                // on commence...
569                                                $elem_query = "select distinct $field_id from $table_term where pond>0 and ";
570                                                //on applique la restriction si besoin
571                                                if($restrict){
572                                                        $elem_query.= $this->get_field_restrict($restrict,$neg_restrict)." and ";
573                                                }
574                                                $table= $table_term;
575                                                //on ajoute le terme
576                                                $elem_query.= " ".$table.".".$field_term." ";
577                                                //                                      if($i==0 && $tree[$i]->not){
578                                                //                                              $elem_query.= "not ";
579                                                //                                      }
580                                                $elem_query.= "like '";
581                                                if(!$tree[$i]->start_with){
582                                                        $elem_query.="%";
583                                                }
584                                                if (strpos($tree[$i]->word,"*") === false) {
585                                                        //Si c'est un mot vide, on ne troncature pas
586                                                        if (in_array($tree[$i]->word,$empty_word)===false) {
587                                                                $elem_query.=addslashes($tree[$i]->word.$troncat);
588                                                        } else {
589                                                                $elem_query.=addslashes($tree[$i]->word);
590                                                        }
591                                                } else {
592                                                        $elem_query.=addslashes(str_replace("*","%",$tree[$i]->word));
593                                                }
594                                                $elem_query.="%'";
595                                        }
596       
597
598                                        if($table_mot == "notices_mots_global_index" && $all_fields && $this->exclude_fields!=""){
599                                                $elem_query.= " and code_champ not in (".$this->exclude_fields.")";
600                                        }
601                                }else if(count($tree)==1){
602                                        $elem_query = "select distinct $field_id from $table_mot where 1";
603                                        if($restrict){
604                                                $elem_query.= " and ".$this->get_field_restrict($restrict,$neg_restrict)." ";
605                                        }
606                                        if($table_mot == "notices_mots_global_index" && $all_fields && $this->exclude_fields!=""){
607                                                $elem_query.= " and code_champ not in (".$this->exclude_fields.")";
608                                        }
609                                }
610
611                        }
612                               
613                        if($tree[$i]->literal!=2 && $elem_query!= ""){
614                                $last_table = $temporary_table;
615                                $temporary_table = $this->tmp_prefix.md5(microtime(true)."#".$this->keep_empty.$i);
616                                switch($tree[$i]->operator){
617                                        case "and" :
618                                                //on créé la table tempo avec les résultats du critère...
619                                                $rqt = "create temporary table ".$temporary_table." ($field_id int, index using btree($field_id)) engine=memory $elem_query";
620                                                pmb_mysql_query($rqt,$dbh);
621                                                if($tree[$i]->not){
622                                                        $rqt = "delete from ".$last_table." where ".$field_id." in (select ".$field_id." from ".$temporary_table.")";
623                                                        pmb_mysql_query($rqt,$dbh);
624                                                        pmb_mysql_query("drop table ".$temporary_table,$dbh);
625                                                        $temporary_table = $last_table;
626                                                        $last_table = "";
627                                                }else{
628                                                        $new_temporary_table =$this->tmp_prefix.md5(microtime(true)."new_temporary_table".$this->keep_empty.$i);
629                                                        $rqt = "create temporary table ".$new_temporary_table." ($field_id int, index using btree($field_id)) engine=memory select $last_table.$field_id from $last_table join $temporary_table on $last_table.$field_id = $temporary_table.$field_id";
630                                                        pmb_mysql_query($rqt,$dbh);
631                                                        pmb_mysql_query("drop table ".$temporary_table,$dbh);
632                                                        pmb_mysql_query("drop table ".$last_table,$dbh);
633                                                        $temporary_table=$new_temporary_table;
634                                                }
635                                                break;
636                                        case "or" :
637                                                $temporary_table = $last_table;
638                                                if($tree[$i]->not){
639                                                        $rqt = "create temporary table tmp_".$temporary_table." ($field_id int, index using btree($field_id)) engine=memory $elem_query";
640                                                        pmb_mysql_query($rqt,$dbh);
641                                                        $rqt = "insert ignore into ".$temporary_table." select distinct $field_id from $table_term where ".$field_id." not in(select ".$field_id." from tmp_".$temporary_table.") and code_champ = 1";
642                                                        pmb_mysql_query($rqt,$dbh);
643                                                        pmb_mysql_query("drop table if exists tmp_".$temporary_table,$dbh);
644                                                        $last_table= "";
645                                                }else{
646                                                        $rqt = "insert ignore into ".$temporary_table." ".$elem_query;
647                                                        $last_table= "";
648                                                        pmb_mysql_query($rqt,$dbh);
649                                                }
650                                                break;
651                                        default :
652                                                if($tree[$i]->not){
653                                                        $rqt = "create temporary table tmp_".$temporary_table." ($field_id int, index using btree($field_id)) engine=memory $elem_query";
654                                                        pmb_mysql_query($rqt,$dbh);
655                                                        $rqt = "create temporary table ".$temporary_table." ($field_id int, index using btree($field_id)) engine=memory select distinct $field_id from $table_term where ".$field_id." not in(select ".$field_id." from tmp_".$temporary_table.") and code_champ = 1";
656                                                        pmb_mysql_query($rqt,$dbh);
657                                                        pmb_mysql_query("drop table if exists tmp_".$temporary_table,$dbh);
658                                                }else{
659                                                        $rqt = "create temporary table ".$temporary_table." ($field_id int, index using btree($field_id)) engine=memory $elem_query";
660                                                }
661                                                pmb_mysql_query($rqt,$dbh);
662                                                break;
663                                }
664                                $query = "select distinct $field_id from ".$temporary_table;
665                                if($last_table != ""){
666                                        pmb_mysql_query("drop table if exists ".$last_table,$dbh);
667                                }
668                        }
669                }
670                return $query;
671        }
672       
673       
674        function get_field_restrict($restrict,$neg=false){
675                $is_multi=false;
676                $return = "";
677                $field_restrict = "";
678       
679                foreach($restrict as $field => $infos){
680                        if ($return != "") $return.=" ".$infos['op']." ";
681                        $return .= ($infos['not'] ? "not ":"")."(".$infos["field"];
682                        if(is_array($infos['values'])){
683                                $return .= " in ('".implode("','",$infos['values'])."')";
684                        }else{
685                                $return .= "='".$infos['values']."'";
686                        }
687                        if($infos['sub'] && is_array($infos['sub']) && count($infos['sub'])){
688                                $sub ="";
689                               
690                                foreach($infos['sub'] as $subfield => $subinfos){
691                                        if ($sub != "") $sub .= " ".$subinfos['op'];
692                                        $sub .= " ".($subinfos['not'] ? "not ":"")."(".$subinfos["sub_field"];
693                                        if(is_array($subinfos['values'])){
694                                                $sub .= " in ('".implode("','",$subinfos['values'])."')";
695                                        }else{
696                                                $sub .= "='".$subinfos['values']."'";
697                                        }
698                                        $sub .= ")";
699                                }
700                                $return.= " and (".$sub.")";
701                        }
702                        $return .= ")";
703                }
704                if($neg){
705                        $return = "not (".$return.")";
706                }else{
707                        $return = "(".$return.")";
708                }
709//              print "<span style='color:green'>$return</span>";
710                return $return;
711        }       
712       
713        function get_query_full_text($table,$field_l,$field_i,$id_field) {
714                $q["select"]="(match($field_l) against ('".addslashes($this->input)."' in boolean mode))";
715                $q["where"]="(match($field_l) against ('".addslashes($this->input)."' in boolean mode))";
716                $q["post"]=" group by ".$id_field." order by pert desc,".$field_i." asc";
717                return $q;
718        }
719       
720        //Requête de comptage des résultats
721        function get_query_count($table,$field_l,$field_i,$id_field,$restrict="") {
722                $select="";
723                $pcount=0;
724                $q=$this->get_query_r($this->tree,$select,$pcount,$table,$field_l,$field_i,$id_field,0,1);
725                $res="select count(distinct ".$id_field.") from ".$table." where (".$q["where"].")";
726                if ($restrict!="") $res.=" and ".$restrict;
727                return $res;
728        }
729       
730        //Analyse de la requête saisie (machine d'état)
731        function recurse_analyse() {
732                global $msg;
733                global $charset;
734
735                $s="new_word";
736                $end=false;
737               
738                while (!$end) {
739                        switch ($s) {
740                                //Début d'un nouveau terme
741                                case "new_word":
742                                        if ($this->current_car>(pmb_strlen($this->input)-1)) { 
743                                                $end=true; 
744                                                if ($this->parenthesis) {
745                                                        $this->error=1;
746                                                        $this->error_message=$msg["aq_missing_term_and_p"];
747                                                        break;
748                                                }
749                                                if ($this->guillemet) {
750                                                        $this->error=1;
751                                                        $this->error_message=$msg["aq_missing_term_and_g"];
752                                                        break;
753                                                }
754                                                break; 
755                                        }       
756                                        $cprec=pmb_getcar($this->current_car - 1,$this->input);                 
757                                        $c=pmb_getcar($this->current_car,$this->input);
758                                        $this->current_car++;
759                                        //Si terme précédé par un opérateur (+, -, ~) et pas d'opérateur et pas de guillemet ouvert et pas de commence par :
760                                        //affectation opérateur. Néanmoins, si c'est le premier terme on n'en tient pas compte
761                                        if ((($c=="+")||($c=="-" && $cprec == " ")||($c=="~"))&&($this->operator=="")&&(!$this->guillemet)&&(!$this->neg)&&(!$this->start_with)) {
762                                                if (($c=="+")&&(count($this->tree))) {
763                                                        if ($this->default_operator == 1) {
764                                                                $this->operator="or";
765                                                        } else {
766                                                                $this->operator="and";
767                                                        }
768                                                } else if (($c=="-" && $cprec == " ")&&(count($this->tree))) {
769                                                        $this->operator="and";
770                                                        $this->neg=1;
771                                                } else if ((($c=="-" && $cprec == " ")&&(!count($this->tree)))||($c=="~")) $this->neg=1;
772                                                //Après l'opérateur, on continue à chercher le début du terme
773                                                $s="new_word";
774                                                break;
775                                        }
776                                        //Si terme précédé par un opérateur et qu'il y a déjà un opérateur ou un commence par et qu'on est pas
777                                        //dans des guillemets alors erreur !
778                                        if ((($c=="+")||($c=="-" && $cprec == " ")||($c=="~"))&&(!$this->guillemet)&&(($this->operator!="")||($this->neg)||($this->start_with))) {
779                                                if (!$this->start_with) {
780                                                        if (($c=="~")&&($this->operator=="and")) {
781                                                                if (!$this->neg)
782                                                                        $message_op=$msg["aq_and_not_error"];
783                                                                else
784                                                                        $message_op=$msg["aq_minus_error"];
785                                                        } else if ((($c=="+")||($c=="-" && $cprec == " "))&&($this->neg)&&(!$this->operator)) {
786                                                                $message_op=sprintf($msg["aq_neg_error"],$c);
787                                                        }  else {
788                                                                $message_op=$msg["aq_only_one"];
789                                                        }
790                                                } else $message_op=$msg["aq_start_with_error"];
791                                                $end=true; $this->error_message=$message_op; $this->error=1; break;
792                                        }
793                                        //Si terme précédé par "commence par" et qu'on est pas dans les guillemets alors opérateur commence par activé
794                                        if (($c=="_")&&(!$this->guillemet)) {
795                                                $this->start_with=1;
796                                                break;
797                                        }
798                                       
799                                        //Si premier guillemet => terme litéral
800                                        if (($c=="\"")&&($this->guillemet==0))  {
801                                                $this->guillemet=1;
802                                                $this->literal=1;
803                                                //Après le guillemets, on continue à chercher le début du terme
804                                                break;
805                                        }                       
806                                        //Si guillement et guillemet déjà ouvert => annulation du terme litéral
807                                        if (($c=="\"")&&($this->guillemet==1)) {
808                                                $this->guillemet=0;
809                                                $this->literal=0;
810                                                //Après le guillemets, on continue à chercher le début du terme
811                                                break;
812                                        }
813                                        //Si il y a un espace et pas dans les guillemets, on en tient pas compte
814                                        if (($c==" ")&&(!$this->guillemet)) break;
815                                        //Si une parentèse ouverte, alors analyse de la sous expression
816                                        if (($c=="(")&&(!$this->guillemet)) {
817                                                $sub_a=new analyse_query($this->input,$this->current_car,1,$this->search_linked_words,$this->keep_empty,$this->stemming);
818                                                //Si erreur dans sous expression, erreur !
819                                                if ($sub_a->error) {
820                                                        $this->error=1;
821                                                        //Mise à jour du caractère courant où s'est produit l'erreur
822                                                        $this->current_car=$sub_a->current_car;
823                                                        $this->error_message=$sub_a->error_message;
824                                                        $end=true;
825                                                        break;
826                                                } else {
827                                                        //Si pas d'erreur, stockage du résultat dans terme
828                                                        $this->term=$sub_a->tree;
829                                                        //Si il n'y a pas d'opérateur et que ce n'est pas le premier terme,
830                                                        //opérateur par défaut
831                                                        //if ((!$this->operator)&&(count($this->tree))) $this->operator="or";
832                                                        if ((!$this->operator)&&(count($this->tree))){
833                                                        if ($this->default_operator == 1) {
834                                                                $this->operator="and";
835                                                        } else {
836                                                                $this->operator="or";
837                                                        }
838                                                }
839                                                        $this->current_car=$sub_a->current_car;
840                                                        //Début Attente du prochain terme
841                                                        $s="space_first";
842                                                        break;
843                                                }
844                                        }
845                                        //Si parentèse fermante et parentèse déjà ouverte alors on s'en va
846                                        if (($c==")")&&($this->parenthesis)&&(!$this->guillemet)) {
847                                                $end=true;
848                                                break;
849                                        }
850                                        //Si aucun des cas précédents, c'est le début du terme
851                                        $this->term.=$c;
852                                        //Si il n'y a pas d'opérateur et que ce n'est pas le premier terme,
853                                        //opérateur par défaut
854                                        //if ((!$this->operator)&&(count($this->tree))) $this->operator="or";
855                                        if ((!$this->operator)&&(count($this->tree))){
856                                                if ($this->default_operator == 1) {
857                                                        $this->operator="and";
858                                                } else {
859                                                        $this->operator="or";
860                                                }
861                                        }
862                                        //Lecture du terme
863                                        $s="stockage_car";
864                                        break;
865                                //Lecture d'un terme
866                                case "stockage_car":
867                                        if ($this->current_car>(pmb_strlen($this->input)-1)) {
868                                                //Si on lit une sous expression et qu'on arrive à la fin avant la parentèse fermante
869                                                //alors erreur
870                                                //sinon, passage à l'état attente du prochain terme (pourquoi me direz-vous alors qu'on arrive à la fin ? parceque ce cas est géré en space_first)
871                                                if ($this->guillemet) { $this->error_message=$msg["aq_missing_g"]; $end=true; $this->error=1; break; }
872                                                if ($this->parenthesis) { $this->error_message=$msg["aq_missing_p"]; $end=true; $this->error=1; break; }
873                                                $s="space_first";
874                                        }
875                                        //Lecture caractère
876                                        $cprec=pmb_getcar($this->current_car - 1,$this->input); 
877                                        $c=pmb_getcar($this->current_car,$this->input);
878                                        $this->current_car++;
879                                        //Si espace et terme litéral : l'espace fait partie du terme
880                                        if ((($c==" ")||($c=="+")||($c=="-" && $cprec == " "))&&($this->guillemet==1)) { $this->term.=$c; break; }
881                                        //Si espace et terme non litéral : espace = séparateur de terme => passage à Début Attente du prochain terme
882                                        if ((($c==" ")||($c=="+")||($c=="-" && $cprec == " "))&&($this->guillemet==0)) { $s="space_first"; $this->current_car--; break; }
883                                        //Si guillemet et terme litéral : guillemet = fin du terme => passage à Début Attente du prochain terme
884                                        if (($c=="\"")&&($this->guillemet==1)) { $s="space_first"; $this->guillemet=0; break; }
885                                        //Si parentèse fermante et sous-expression et que l'on est pas dans un terme litéral,
886                                        //alors fin de sous expression à analyser => passage à Début Attente du prochain terme
887                                        if (($c==")")&&($this->parenthesis==1)&&($this->guillemet==0)) { $s="space_first"; $this->current_car--; break; }
888                                        //Si aucun des cas précédent, ajout du caractère au terme... et on recommence
889                                        $this->term.=$c;
890                                        break;
891                                //Début Attente du prochain terme après la fin d'un terme
892                                //A ce niveau, on s'attend à un caractère séparateur et si on le trouve, on enregistre le terme dans l'arbre
893                                //Ensuite on passe à l'état attente du prochain terme ("space_wait") qui saute tous les caractères vides avant de renvoyer à new_word
894                                case "space_first":
895                                        if ($this->current_car>(pmb_strlen($this->input)-1)) {
896                                                //Si fin de chaine et parentèse ouverte => erreur
897                                                if ($this->parenthesis) { $end=true; $this->error_message=$msg["aq_missing_p"]; $this->error=1; break; }
898                                                //Sinon c'est la fin de l'analyse : on enregistre le dernier terme et on s'arrête
899                                                $end=true;
900                                                if (is_array($this->term))
901                                                        $t=new term("",$this->literal,$this->neg,$this->start_with,$this->operator,$this->term);
902                                                else
903                                                        $t=new term($this->term,$this->literal,$this->neg,$this->start_with,$this->operator,null);
904                                                $this->store_in_tree($t,$this->search_linked_words);
905                                                break;
906                                        }                               
907                                        //Lecture du prochain caractère
908                                        $cprec=pmb_getcar($this->current_car - 1,$this->input); 
909                                        $c=pmb_getcar($this->current_car,$this->input);
910                                        $this->current_car++;
911                                        //Si parentèse fermante et sous expression en cours d'analyse => fin d'analyse de la sous expression
912                                        if (($c==")")&&($this->parenthesis)) {
913                                                $end=true;
914                                                //Enregistrement du dernier terme
915                                                if (is_array($this->term))
916                                                        $t=new term("",$this->literal,$this->neg,$this->start_with,$this->operator,$this->term);
917                                                else
918                                                        $t=new term($this->term,$this->literal,$this->neg,$this->start_with,$this->operator,null);
919                                                $this->store_in_tree($t,$this->search_linked_words);
920                                                break;
921                                        }
922                                        //Sinon, si ce n'est pas un espace, alors erreur (ce n'est pas le séparateur attendu)
923                                        if (($c!=" ")&&($c!="+")&&($c!="-" && $cprec!=" ")) {
924                                                $end=true; $this->error_message=$msg["aq_missing_space"]; $this->error=1; break;
925                                        }
926                                        //Si tout va bien, on attend le prochain terme
927                                        if ($c!=" ")
928                                                $this->current_car--;
929                                        $s="space_wait";
930                                        break;
931                                //Attente du prochain terme : on saute tous les espaces avant de renvoyer à la lecture du nouveau terme !
932                                case "space_wait":
933                                        if ($this->current_car>(pmb_strlen($this->input)-1)) {
934                                                //Si prentèse ouverte et fin de la chaine => erreur
935                                                if ($this->parenthesis) { $end=true; $this->error_message=$msg["aq_missing_p"]; $this->error=1; break; }
936                                                //Sinon, si fin de la chaine, enregistrement du terme précédent et fin d'analyse
937                                                if (is_array($this->term))
938                                                        $t=new term("",$this->literal,$this->neg,$this->start_with,$this->operator,$this->term);
939                                                else
940                                                        $t=new term($this->term,$this->literal,$this->neg,$this->start_with,$this->operator,null);
941                                                $this->store_in_tree($t,$this->search_linked_words);
942                                                $end=true;
943                                                break;
944                                        }
945                                        //Lecture du caractère suivant
946                                        $c=pmb_getcar($this->current_car,$this->input);
947                                        $this->current_car++;
948                                        //Si ) et sous expression en cours d'analyse, fin de l'analyse de la sous expression
949                                        if (($c==")")&&($this->parenthesis==1)) {
950                                                //Enregistrement du terme et fin d'analyse
951                                                if (is_array($this->term))
952                                                        $t=new term("",$this->literal,$this->neg,$this->start_with,$this->operator,$this->term);
953                                                else
954                                                        $t=new term($this->term,$this->literal,$this->neg,$this->start_with,$this->operator,null);
955                                                $this->store_in_tree($t,$this->search_linked_words);
956                                                $end=true;
957                                                break;
958                                        }
959                                        //Si le caractère n'est pas un espace, alors c'est le début du prochain terme
960                                        if ($c!=" ") {
961                                                $this->current_car--;
962                                                //Enregistrement du dernier terme
963                                                if (is_array($this->term))
964                                                        $t=new term("",$this->literal,$this->neg,$this->start_with,$this->operator,$this->term);
965                                                else
966                                                        $t=new term($this->term,$this->literal,$this->neg,$this->start_with,$this->operator,null);
967                                                $this->store_in_tree($t,$this->search_linked_words);
968                                                //Remise à zéro des indicateurs
969                                                $this->operator="";
970                                                $this->term="";
971                                                $this->neg=0;
972                                                $this->literal=0;
973                                                $this->start_with=0;
974                                                //Passage à nouveau terme
975                                                $s="new_word";
976                                                break;
977                                        }
978                                        //Sinon on reste en attente
979                                        break;
980                        }
981                }
982                if ($this->error) {
983                        $this->input_html=pmb_substr($this->input,0,$this->current_car-1)."!!red!!".pmb_substr($this->input,$this->current_car-1,1)."!!s_red!!".pmb_substr($this->input,$this->current_car);
984                } else $this->input_html=$this->input;
985                if ((!$this->error)&&(!count($this->tree))) {
986                        $this->error=1;
987                        $this->error_message=$msg["aq_no_term"];                       
988                }
989                $this->input_html=htmlentities($this->input_html,ENT_QUOTES,$charset);
990                $this->input_html=str_replace("!!red!!","<font color='#DD0000'><b><u>",$this->input_html);
991                $this->input_html=str_replace("!!s_red!!","</u></b></font>",$this->input_html);
992        }
993
994        function get_positive_terms($tree,$father_sign=0){
995                for($i=0;$i<(count($tree));$i++){
996                        $term_obj = $tree[$i];
997                        if($term_obj->word != "*"){
998                                if($term_obj->word && ($term_obj->not == $father_sign))
999                                        $this->positive_terms[] = $term_obj->word;
1000                                else if($term_obj->sub){
1001                                        $this->get_positive_terms($term_obj->sub,$term_obj->not);
1002                                }       
1003                        }
1004                }
1005                return $this->positive_terms;
1006        }
1007
1008        function get_positive_terms_obj($tree,$father_sign=0){
1009                for($i=0;$i<(count($tree));$i++){
1010                        $term_obj = $tree[$i];
1011                        if($term_obj->word && ($term_obj->not == $father_sign))
1012                                $this->positive_terms[] = $term_obj;
1013                        else if($term_obj->sub){
1014                                $this->get_positive_terms_obj($term_obj->sub,$term_obj->not);
1015                        }       
1016                }
1017                return $this->positive_terms;
1018        }
1019
1020        //récupère la pertinence d'une liste de notices sur la recherche instanciée!
1021        function get_pert($notices_ids,$restrict=array(),$neg_restrict=false,$with_explnum=false,$return_query = false,$all_fields=false){
1022                return $this->get_objects_pert($notices_ids, "id_notice", "notices_mots_global_index", "word", "notices_fields_global_index", "value", "notice_id",$restrict,$neg_restrict,$with_explnum,$return_query,$all_fields);
1023        }
1024       
1025        //généralisation du calcul de la pertinence
1026        public function get_objects_pert($objects_ids,$field_id,$table_mot,$field_mot,$table_term,$field_term,$final_id,$restrict=array(),$neg_restrict=false,$with_explnum=false,$return_query = false,$all_fields=false){
1027                global $empty_word;
1028                global $dbh;
1029               
1030                $troncat = "";
1031                if ($this->allow_term_troncat_search) {
1032                        $troncat = "%";
1033                }
1034                $terms = $this->get_positive_terms_obj($this->tree);
1035                $words = array();
1036                $literals = array();
1037                $queries = array();
1038                if(count($objects_ids)){
1039                        if(count($terms)){
1040                                foreach($terms as $term){
1041                                        if(!$term->literal){
1042                                                if(!in_array($term,$words)) {
1043                                                        $words[]=$term;
1044                                                }
1045                                        }else {
1046                                                $literals[] = $term;
1047                                        }
1048                                }
1049                        }
1050                        if($this->input !== "*"){
1051                                //pertinence sur documents numériques valable uniquement sur les notices
1052                                if($table_mot == "notices_mots_global_index" && $with_explnum && $this->input !== "*"){
1053                                        $noti_members = $this->get_query_members("explnum","explnum_index_wew","explnum_index_sew","explnum_notice","",0,0,true);
1054                                        $bull_members = $this->get_query_members("explnum","explnum_index_wew","explnum_index_sew","explnum_bulletin","",0,0,true);
1055                                        $noti = "select distinct explnum_notice as notice_id, ".$noti_members['select']." as pert from explnum where explnum_notice in (".$objects_ids.")";
1056                                        $bull = "select distinct num_notice as notice_id, ".$noti_members['select']." as pert from explnum join bulletins on explnum_bulletin = bulletin_id where num_notice in (".$objects_ids.")";
1057                                        $queries[] = "select distinct notice_id, pert as pert from (($noti) union all ($bull)) as q1";
1058                                }
1059                                if(count($words)){
1060                                        //si on veut nettoyer par rapport à la fréquence d'apparition, on compte le nombre total de lignes.
1061                                        if($this->search_relevant_with_frequency){
1062                                                $nb_lignes = 0;
1063                                                //pour les grosses volumétrie, on essaye d'etre plus efficace
1064                                                switch($table_mot){
1065                                                        case "notices_mots_global_index" :
1066                                                                $query =" select count(notice_id) from notices";
1067                                                                break;
1068                                                        default :
1069                                                                $query = "select count(distinct ".$field_id.") from ".$table_mot;
1070                                                                break;
1071                                                }
1072                                                $result = pmb_mysql_query($query,$dbh);
1073                                                if(pmb_mysql_num_rows($result)){
1074                                                        $nb_lignes = pmb_mysql_result($result,0,0);
1075                                                }
1076                                        }
1077                                        $pert_query_words = "select ".$field_id." as ".$final_id.", max(pond * (!!pert!!)) as pert from words straight_join ".$table_mot." on num_word = id_word where ";
1078                                        $where = "";
1079                                        foreach($words as $term){
1080                                                if($term->word != "*"){
1081                                                        if($where !="") $where.= " or ";
1082                                                        $crit="word ";
1083                                                        if (strpos($term->word,"*")!==false || $this->allow_term_troncat_search){
1084                                                                if (strpos($term->word,"*") === false) {
1085                                                                        //Si c'est un mot vide, on ne troncature pas
1086                                                                        if (in_array($term->word,$empty_word)===false) {
1087                                                                                if($term->not) $crit.= "not ";
1088                                                                                $crit.= "like '".addslashes($term->word.$troncat)."'";
1089                                                                        } else {
1090                                                                                if($term->not) $crit.= "! ";
1091                                                                                $crit.="= '".addslashes($term->word)."'";
1092                                                                        }
1093                                                                } else {
1094                                                                        if($term->not) $crit.= "not ";
1095                                                                        $crit.= "like '".addslashes(str_replace("*","%",$term->word))."'";
1096                                                                }
1097                                                        }else{
1098                                                                if($term->not) $crit.= "!";
1099                                                                $crit.= "= '".addslashes($term->word)."'";
1100                                                        }
1101                                                        $where.= " ".$crit;
1102                                                        if (in_array($term->word,$empty_word)) $tpound=$term->pound/10; else $tpound=$term->pound;
1103               
1104                                                        $query = "select id_word ";
1105                                                        if($this->search_relevant_with_frequency){
1106                                                                $query.=",count(distinct ".$field_id.") as freq, length(word)-length('".$term->word."') as dist ";
1107                                                                $dist = $freq = "case ";
1108                                                                $max_dist = 0;
1109                                                        }
1110                                                        $query.=" from words straight_join ".$table_mot." on id_word=num_word where $crit group by id_word";
1111                                                        $result = pmb_mysql_query($query,$dbh);
1112                                                        $ids_words = $subqueries = array();
1113                                                        $subwhere = "";
1114                                                        if(pmb_mysql_num_rows($result)){
1115                                                                while($row = pmb_mysql_fetch_object($result)){
1116                                                                        if($this->search_relevant_with_frequency){
1117                                                                                $freq.= " when id_word=".$row->id_word." then ".$row->freq;
1118                                                                                $dist.= " when id_word=".$row->id_word." then ".$row->dist;
1119                                                                                if($row->dist > $max_dist) $max_dist = $row->dist;
1120                                                                        }
1121                                                                        $ids_words[]= $row->id_word;
1122                                                                }
1123                                                                       
1124                                                                if($this->search_relevant_with_frequency){
1125                                                                        $ln_freq = "ln(1/(".$freq." end/".$nb_lignes."))";
1126                                                                        $ln_dist = "ln(1/(".$dist." end/".$max_dist."))";
1127                                                                       
1128                                                                        $coeff = "if(".$dist." end != 0, ((".$ln_dist." + ".$ln_freq.")/2 ), ".$ln_freq.")";
1129                                                                        $query_words = str_replace("!!pert!!",$coeff." * ".$tpound,$pert_query_words);
1130                                                                }else{
1131                                                                        $query_words = str_replace("!!pert!!",$tpound,$pert_query_words);
1132                                                                }
1133                                                                $subwhere = "id_word in (".implode(",",$ids_words).")";
1134                                                                $subwhere.= (count($restrict) > 0? " and ".$this->get_field_restrict($restrict,$neg_restrict) : "");
1135                                                                if($table_mot == "notices_mots_global_index" && $all_fields && $this->exclude_fields!=""){
1136                                                                        $subwhere.=" and code_champ not in (".$this->exclude_fields.")";
1137                                                                }
1138                                                                $queries[]= $query_words.$subwhere." group by ".$field_id." having pert > 0 ";
1139                                                        }
1140                                                }else{
1141                                                        $query = "select distinct id_notice as notice_id, 100 from notices_mots_global_index where 1 ";
1142                                                        $subwhere.= (count($restrict) > 0? " and ".$this->get_field_restrict($restrict,$neg_restrict) : "");
1143                                                        if($all_fields && $opac_exclude_fields!= ""){
1144                                                                $subwhere.=" and code_champ not in (".$opac_exclude_fields.")";
1145                                                        }
1146                                                        $queries[] = $query;
1147                                                }
1148                                        }
1149                                }
1150                               
1151                                if(count($literals)){
1152                                        $pert_query_literals = "select distinct ".$field_id." as ".$final_id.", sum(!!pert!!) as pert from ".$table_term." where ";
1153                                        $where = "";
1154                                        foreach($literals as $term){
1155                                                //on n'ajoute pas une clause dans le where qui parcours toute la base...
1156                                                if($where !="") $where.= " or ";
1157                                                $crit = "value ";
1158                                                if($term->not) $crit.= "not ";
1159                                                $crit.= "like '".($term->start_with == 0 ? "%":"").addslashes(str_replace("*","%",$term->word))."%'";
1160                                                $where.= " ".$crit;
1161                                                $crit = str_replace("%%","%",$crit);
1162                                                $pert_query_literals = str_replace("!!pert!!","((".$crit.") * pond *".$term->pound.")+!!pert!!",$pert_query_literals);
1163                                        }
1164                                        $where.= (count($restrict) > 0? " and ".$this->get_field_restrict($restrict,$neg_restrict) : "");
1165                                        $pert_query_literals = str_replace("!!pert!!",0,$pert_query_literals);
1166                                        if($table_mot == "notices_mots_global_index" && $all_fields && $this->exclude_fields!=""){
1167                                                $where.=" and code_champ not in (".$this->exclude_fields.")";
1168                                        }
1169                                        $queries[]= $pert_query_literals.$where." group by ".$field_id." having pert > 0 ";
1170                                }
1171                                //aucun terme positif
1172                                if(!count($words) && !count($literals)){
1173                                        $where= (count($restrict) > 0? $this->get_field_restrict($restrict,$neg_restrict) : "");
1174                                        if($table_mot == "notices_mots_global_index" && $all_fields && $this->exclude_fields!=""){
1175                                                if($where !="") $where.= " and";
1176                                                $where.=" code_champ not in (".$this->exclude_fields.")";
1177                                        }
1178                                        $queries[]= "select distinct ".$field_id." as ".$final_id.",max(pond) as pert from ".$table_term." ".($where ? " where ".$where : "")." group by ".$field_id." ";
1179                                }
1180                                $query = "select distinct ".$final_id.", sum(pert) as pert from ((".implode(") union all (",$queries).")) as uni where ".$final_id." in (".$objects_ids.") group by ".$final_id."";
1181                        }else{
1182                                //Si recherche * alors la pondération est la même pour toutes les notices
1183                                //$query = "select * from(select id_notice as notice_id, sum(pond) as pert from notices_fields_global_index ".(count($restrict) > 0 ? "where ".$this->get_field_restrict($restrict,$neg_restrict) : "")." group by id_notice) as uni where notice_id in (".$notices_ids.")";
1184                                $query = "SELECT distinct(".$field_id.") as ".$final_id.", 100 as pert FROM ".$table_term." WHERE ".$field_id." in (".$objects_ids.")";
1185                        }
1186                }
1187                if($return_query){
1188                        return $query;
1189                }else{
1190                        $table = "search_result".md5(microtime(true));
1191                        $rqt = "create temporary table ".$table." $query";
1192                        $res = pmb_mysql_query($rqt,$dbh);
1193                        pmb_mysql_query("alter table ".$table." add index i_id(".$final_id.")",$dbh);
1194                        return $table;
1195                }               
1196        }       
1197       
1198        public function add_stemming(){
1199                if(!$tree) $tree = $this->tree;
1200                for($i=0 ; $i<count($this->tree) ; $i++){
1201                        $this->tree[$i] = $this->_add_stemming($this->tree[$i]);
1202                }
1203        }
1204       
1205        protected function _add_stemming($term){
1206                global $lang,$dbh;
1207                if(!$term->literal && !$term->sub && !$term->not){
1208                        $sub = array();
1209                        //on perd pas le terme d'origine quand même...
1210                        $sub[]= new term($term->word,$term->literal,$term->not,$term->start_with,"",$term->sub,$term->pound);
1211                        //on cherche les mots de la base avec la même racine !
1212                        $stemming = new stemming($term->word);
1213                        $query = "select distinct word from words where stem like '".$stemming->stem."' and lang in ('','".$lang."') and word != '".addslashes($term->word)."'";
1214                        $result = pmb_mysql_query($query,$dbh);
1215                        if(pmb_mysql_num_rows($result)){
1216                                if(pmb_mysql_num_rows($result)>1){
1217                                        $sub_stem = array();
1218                                        $op = "";
1219                                        while ($row = pmb_mysql_fetch_object($result)){
1220                                                if(count($sub_stem)) $op = "or";
1221                                                $sub_stem[] = new term($row->word,0,0,0,$op,null,$term->pound);
1222                                        }
1223                                        $sub[] = new term("",0,0,0,"or",$sub_stem,0.4,"stemming");
1224                                }else{
1225                                        $row = pmb_mysql_fetch_object($result);
1226                                        $sub[] = new term($row->word,0,0,0,"or",null,$term->pound*0.4,"stemming");
1227                                }
1228                        }
1229                        $term->word = "";
1230                        $term->sub = $sub;
1231                }else if(!$term->literal && !$term->not){
1232                        for ($i=0 ; $i<count($term->sub) ; $i++){
1233                                $term->sub[$i] = $this->_add_stemming($term->sub[$i]);
1234                        }
1235                }
1236                return $term;           
1237        }
1238}
1239?>
Note: See TracBrowser for help on using the repository browser.