20, //Nombre maximum de mots de la notice à prendre en compte pour le calcul 'autoindex_stem_ratio'=>0.8, //Ratio de pondération des lemmes 'max_relevant_terms'=>10, //Nombre de termes à conserver aprés tri 'autoindex_max_up_distance'=>2, 'autoindex_max_up_ratio'=>0.01, 'autoindex_max_down_distance'=>2, 'autoindex_max_down_ratio'=>0.01, 'autoindex_see_also_ratio'=>0.01, 'autoindex_deep_ratio'=>0.05, 'autoindex_distance_type'=>1, 'autoindex_distance_ratio'=>0.5, ); global $thesaurus_auto_index_search_param; if($thesaurus_auto_index_search_param){ $tmp = explode(";",$thesaurus_auto_index_search_param); foreach($tmp as $param){ $pos = stripos($param,'='); if($pos) { $p = trim(substr($param,0,$pos)); $v = str_replace(',','.',trim(substr($param,$pos+1)))*1; if(array_key_exists($p,$autoindex_params) && $v) { $autoindex_params[$p] = $v; } //C'est quoi cette horreur !!! //@eval("\$".$param_command.";"); } } } foreach($autoindex_params as $p=>$v) { ${$p}=$v; } class autoindex_document { /** * texte brut à analyser * @var array * @access protected */ protected $raw_text=array(); /** * */ protected $clean_text=''; protected $full_clean_text=''; /** * langue du document * @var string * @access protected */ protected $lang='fr_FR'; /** * Permet de préciser si l'on recherche aussi dans les mots sans langue */ protected $wo_lang = true; /** * Fonds des documents * @var autoindex_documents_collection * @access protected */ protected $collection; /** * tableau des mots distincts du document avec fréquence et ponderation * @var array(autoindex_word) * @access protected */ public $words = array(); /** * tableau des stems distincts du document avec fréquence * @var array(autoindex_stem) * @access protected */ protected $stems = array(); /** * Identifiant du thésaurus * @var integer * @access protected */ protected $id_thesaurus = 0; /** * tableau des termes pertinents pour le document * @var array(autoindex_term) * @access protected */ public $terms = array(); public function __construct() { } /** * calcule la pertinence d'un mot dans le fond * fréquence mot dans le document * log(frequence inverse dans le fond) * * @param autoindex_word word Mot pour lequel calculer la pertinence * @return float * @access public */ public function calc_word_relevancy($word) { $wr = 0; $w_idf = $this->collection->calc_inverse_frequency($word); if ($w_idf) { $wf = $word->frequency; $wr = $wf * log($w_idf,10); } return $wr; } /** * calcule la pertinence d'un stem dans le fond * fréquence stem dans le document * log(frequence inverse dans le fond) * * @param autoindex_stem : Stem pour lequel calculer la pertinence * @return float * @access public */ public function calc_stem_relevancy($stem) { global $autoindex_stem_ratio; $sr = 0; $s_idf = $this->collection->calc_stem_inverse_frequency($stem); if ($s_idf) { $sf = $stem->frequency; $sr = $sf * log($s_idf,10) * $autoindex_stem_ratio; } return $sr; } /** * Trouve les mots pertinents du document * * récupère le texte brut, effectue un nettoyage * calcule la fréquence des mots dans le document * * @return void * @access public */ public function find_revelants_words() { global $dbh; global $max_relevant_words; $tab_words = array(); if(is_array($this->raw_text) && count($this->raw_text)) { foreach ($this->raw_text as $k=>$v) { //nettoyage texte brut $this->clean_text = strip_empty_words($v['value'], $this->lang); $this->full_clean_text.= $this->clean_text.' '; $pond = $v['pond']; //TODO // echo $this->clean_text."
"; // echo $pond."
"; //calcul de la fréquence des mots dans le document $tab_clean_text = array(); if(strlen($this->clean_text)) { $tab_clean_text = explode(' ',$this->clean_text); } if (count($tab_clean_text)) { foreach($tab_clean_text as $v) { if ($v!=='') { if (!isset($tab_words[$v]) || !$tab_words[$v]) { $tab_words[$v]['frequency'] = 0; $tab_words[$v]['pond'] = 0; } if( $pond > $tab_words[$v]['pond']) { $tab_words[$v]['pond'] = $pond; } $tab_words[$v]['frequency']+=1; } } } unset($tab_clean_text); } } //TODO // echo "Mots du document avec leur fréquence et leur pondération par champ (".count($tab_words).") =
"; // highlight_string(print_r($tab_words,true)); // echo "
"; //instanciation des mots utilisés $tmp_words = array(); if(count($tab_words)) { foreach($tab_words as $label=>$v) { $w = new autoindex_word($label, $v['frequency'],$this->lang, $this->wo_lang, $v['pond']); $w_r = $this->calc_word_relevancy($w); $w_r= $w_r * $w->pond; $w->set_relevancy($w_r); $tmp_words[]=$w; } } unset($tab_words); // TODO // echo "Mots du document (".count($tmp_words).") =
"; // highlight_string(print_r($tmp_words,true)); // echo "
"; //limitation du nombre de mots if(count($tmp_words)) { usort($tmp_words, array("autoindex_word", "compare_relevancies")); $done=false; $i=0; while (!$done) { $this->words[$i] = $tmp_words[$i]; $i++; if($i==$max_relevant_words || $i==count($tmp_words)) { $done=true; } } } // TODO // echo "Mots pertinents du document (".count($this->words).") =
"; // highlight_string(print_r($this->words,true)); // echo "
"; //calcule la fréquence et la pertinence des stems dans le document $tab_stems = array(); if(count($tmp_words)) { foreach($tmp_words as $k=>$word) { if (!isset($tab_stems[$word->stem]) || !$tab_stems[$word->stem]) { $tab_stems[$word->stem]['frequency']=0; $tab_stems[$word->stem]['pond'] = 0; } if( $word->pond > $tab_stems[$word->stem]['pond']) { $tab_stems[$word->stem]['pond'] = $word->pond; } $tab_stems[$word->stem]['frequency']+=1; } } unset ($tmp_words); $tmp_stems=array(); if(count($tab_stems)) { foreach($tab_stems as $label=>$v) { $s = new autoindex_stem($label, $v['frequency'], $this->lang,$v['pond']); $s_r = $this->calc_stem_relevancy($s); $s_r= $s_r * $s->pond; $s->set_relevancy($s_r); $tmp_stems[]=$s; } } // TODO // echo "Stems du document (".count($tmp_stems).") =
"; // highlight_string(print_r($tmp_stems,true)); // echo "
"; //limitation du nombre de stems if(count($tmp_stems)) { usort($tmp_stems, array("autoindex_stem", "compare_relevancies")); $done=false; $i=0; while (!$done) { $this->stems[$i] = $tmp_stems[$i]; $i++; if($i==$max_relevant_words || $i==count($tmp_stems)) { $done=true; } } } unset($tmp_stems); // TODO // echo "Stems pertinents du document (".count($this->stems).") =
"; // highlight_string(print_r($this->stems,true)); // echo "
"; } /** * Retrouve les termes du thésaurus contenant au moins un mot (ou un synonyme) * pertinent et leur pertinence brute. * * En 2 passes : * La première avec les mots exacts. * La 2ème avec les stemmes de mot du document et les stemmes des mots des termes. * Si pas déjà trouvé avec les mots, on ajoute en sous-pondérant (ratio à définir) * * @return void * @access public */ public function get_relevants_terms() { global $dbh; $this->terms = array(); if(count($this->words)) { $used_words = array(); $terms = array(); // $terms1 = array(); // $terms2 = array(); $q_restrict = '1 '; $q0 = "select group_concat(id_noeud) from noeuds where autorite in ('TOP','ORPHELINS','NONCLASSES')"; $r0 = pmb_mysql_query($q0, $dbh); if(pmb_mysql_num_rows($r0)) { $q_restrict= 'num_noeud not in('.pmb_mysql_result($r0,0,0).') '; } //recherche des termes pour lesquels on a une correspondance exacte avec l'un des mots du document $used_word_ids=array(); foreach($this->words as $k=>$word) { if($word->id) { $used_word_ids[] = $word->id; } if($word->wo_lang_id) { $used_word_ids[] = $word->wo_lang_id; } $q1 = "select num_noeud, libelle_categorie, num_renvoi_voir, path from noeuds join categories on num_noeud=id_noeud where $q_restrict "; if ($this->id_thesaurus) { $q1.= "and noeuds.num_thesaurus=".$this->id_thesaurus." "; } if ($this->lang) { $q1.= "and langue='".$this->lang."' "; } $q1.= "and index_categorie like '% ".$word->label." %' "; $r1 = pmb_mysql_query($q1, $dbh); if(pmb_mysql_num_rows($r1)) { while($row1 = pmb_mysql_fetch_object($r1)) { if(!isset($terms[$row1->num_noeud]) || !$terms[$row1->num_noeud]) { // $terms1[]=$row1->libelle_categorie; $terms[$row1->num_noeud]['label']=$row1->libelle_categorie; $terms[$row1->num_noeud]['see']=$row1->num_renvoi_voir; $terms[$row1->num_noeud]['path']=$row1->path; $terms[$row1->num_noeud]['words']=array(); $terms[$row1->num_noeud]['stems']=array(); $terms[$row1->num_noeud]['relevancy']=0; } $terms[$row1->num_noeud]['words'][] = $word->label; $terms[$row1->num_noeud]['relevancy'] = $terms[$row1->num_noeud]['relevancy'] + $word->relevancy; } } } //TODO // echo "Termes contenant exactement un des mots pertinents du document (".count($terms1).") =
"; // highlight_string(print_r($terms1,true)); // echo "
"; //recherche des termes pour lesquels on a une correspondance avec l'un des stems du document foreach($this->stems as $k=>$stem) { $q2_restrict = "1 "; if(count($used_word_ids)) { $q2_restrict = "id_word not in (".implode(',',$used_word_ids).")"; } $q2 = "select word from words where $q2_restrict and stem='".addslashes($stem->label)."' "; if ($this->lang) { $q2.= "and lang='".$this->lang."' "; } $r2 = pmb_mysql_query($q2, $dbh); if (!pmb_mysql_num_rows($r2) && $this->wo_lang) { $q2 = "select word from words where $q2_restrict and stem='".addslashes($stem->label)."' and lang='' "; $r2 = pmb_mysql_query($q2, $dbh); } if (pmb_mysql_num_rows($r2)) { while ($row2 = pmb_mysql_fetch_object($r2)) { $q3 = "select num_noeud, libelle_categorie, num_renvoi_voir, path from noeuds join categories on num_noeud=id_noeud where $q_restrict "; if ($this->id_thesaurus) { $q3.= "and noeuds.num_thesaurus=".$this->id_thesaurus." "; } if ($this->lang) { $q3.= "and langue='".$this->lang."' "; } $q3.= "and index_categorie like '% ".$row2->word." %' "; $r3 = pmb_mysql_query($q3, $dbh); if(pmb_mysql_num_rows($r3)) { while($row3 = pmb_mysql_fetch_object($r3)) { if(!$terms[$row3->num_noeud]) { // $terms2[]=$row3->libelle_categorie; $terms[$row3->num_noeud]['label']=$row3->libelle_categorie; $terms[$row3->num_noeud]['see']=$row3->num_renvoi_voir; $terms[$row3->num_noeud]['path']=$row3->path; $terms[$row3->num_noeud]['words']=array(); $terms[$row3->num_noeud]['stems']=array(); $terms[$row3->num_noeud]['relevancy']=0; } $terms[$row3->num_noeud]['stems'][]=$stem->label.' --> '.$row2->word; $terms[$row3->num_noeud]['relevancy'] = $terms[$row3->num_noeud]['relevancy'] + $stem->relevancy; } } } } } //TODO // echo "Termes pours lesquels on a une correspondance avec l'un des stems pertinents du document (".count($terms2).") =
"; // print_r($terms2); // echo "
"; foreach($terms as $id=>$term) { $this->terms[]= new autoindex_term($id, $term['label'], $term['see'], $term['path'], $term['relevancy']); } //tri des termes sur raw_revelancy usort($this->terms, array("autoindex_term", "compare_raw_relevancies")); //TODO // echo "Termes contenant exactement un des mots, ou la racine d'un des mots pertinents du document (".count($this->terms)."), triés par raw_relevancy =
"; // print_r($this->terms); // echo "
"; } } /** * 1 - calcul pour chaque terme sa pertinence totale * 2 - appel du tri * * * @return void * @access public */ public function calc_total_terms_relevancy() { global $autoindex_max_up_distance; global $autoindex_max_down_distance; if(count($this->terms)) { foreach($this->terms as $k=>$term) { $term->calc_total_relevancy($this->terms, $autoindex_max_up_distance, $autoindex_max_down_distance); } } } /** * 1 - Calcule pour chaque terme la somme des distances dans le document * * 2 - Si Dmax >0, Pour chaque terme où une distance a pu être calculée : * Ajustement de la pertinence de chaque terme avec : pertinence totale + (((Dmax * - Dterme) / Dmax) * pertinence totale) * * 3 - appel du tri * * @return void * @access public */ public function calc_document_terms_distances() { if(count($this->terms)) { foreach($this->terms as $k=>$term) { $term->calc_term_document_distance($this->full_clean_text); } } } /** * Tri du tableau de termes par pertinence + Ecrêtage selon le seuil défini * @param float level Seuil pour l'écrêtage du tableau * @return void * @access protected */ public function sort_terms( $level=0, $sort_function='compare_total_relevancies') { global $max_relevant_terms; //suppression des termes renvoyés déjà présents $ids=array(); $sees=array(); foreach($this->terms as $k=>$term) { $ids[$k]=$term->id; $sees[$k]=$term->see; } foreach($sees as $k_see=>$see) { $k_id = array_search($see,$ids); if($k_id!==false) { if($this->terms[$k_see]->total_relevancy > $this->terms[$k_id]->total_relevancy) { $this->terms[$k_id]->total_relevancy = $this->terms[$k_see]->total_relevancy; } unset ($this->terms[$k_see]); } } usort($this->terms, array("autoindex_term", $sort_function)); if($level) { $done=false; while(!$done) { $term = end($this->terms); if($term && ($term->total_relevancy <= $level) ) { array_pop($this->terms); } else { $done=true; } } } elseif($max_relevant_terms) { while(count($this->terms) > $max_relevant_terms) { array_pop($this->terms); } } } }