Changeset 93151 in spip-zone


Ignore:
Timestamp:
Nov 24, 2015, 9:27:53 PM (5 years ago)
Author:
fil@…
Message:

en cas de résultats décevants, utiliser aspell pour suggérer des propositions de mots qui sont 1) correctement orthographiés 2) existant dans la base sphinx

Location:
_plugins_/indexer/trunk
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/indexer/trunk/inc/indexer.php

    r92724 r93151  
    223223        return array_filter($liste);
    224224}
     225
     226// suggerer des mots (si aspell est installee)
     227// code adapté de https://github.com/splitbrain/dokuwiki-plugin-spellcheck/blob/master/spellcheck.php
     228function indexer_suggestions($mot) {
     229
     230        include_spip('lib/aspell');
     231        if (!class_exists('Aspell')) {
     232                spip_log('pas trouvé aspell.php', 'indexer');
     233                return array();
     234        }
     235
     236        try {
     237                $spell = new Aspell($GLOBALS['spip_lang'],null,'utf-8');
     238                // $spell->setMode(PSPELL_FAST);
     239                if(!$spell->runAspell($mot, $out,$err,array('!','+html','@nbsp'))){
     240                        spip_log("An error occurred while trying to run the spellchecker: ".$err, 'indexer');
     241                        return null;
     242                }
     243        } catch(Exception $e) {
     244                spip_log($e, 'indexer');
     245                return null;
     246        }
     247
     248
     249        // go through the result
     250        $lines = split("\n",$out);
     251        $rcnt  = count($lines)-1;    // aspell result count
     252        for($i=$rcnt; $i>=0; $i--){
     253                $line = trim($lines[$i]);
     254                if($line[0] == '@') continue; // comment
     255                if($line[0] == '*') continue; // no mistake in this word
     256                if($line[0] == '+') continue; // root of word was found
     257                if($line[0] == '?') continue; // word was guessed
     258                if(empty($line)){
     259                        continue;
     260                }
     261                // now get the misspelled words
     262                if (preg_match('/^& ([^ ]+) (\d+) (\d+): (.*)/',$line,$match)){
     263                        // match with suggestions
     264                        $word = $match[1];
     265                        $off  = $match[3]-1;
     266                        $sug  = split(', ',$match[4]);
     267                } else if (preg_match('/^# ([^ ]+) (\d+)/',$line,$match)) {
     268                        // match without suggestions
     269                        $word = $match[1];
     270                        $off  = $match[2]-1;
     271                        $sug  = null;
     272                } else {
     273                        // couldn't parse output
     274                        spip_log("The spellchecker output couldn't be parsed line $i '$line'", 'indexer');
     275                        return null;
     276                }
     277        }
     278
     279        // aspell peut nous renvoyer des mots accentués
     280        // qui auront la même valeur dans sphinx,
     281        // il faut donc unifier
     282        // ne pas non plus accepter de mots avec apostrophe
     283        $suggests = array();
     284        if (is_array($sug)) {
     285                foreach($sug as $t) {
     286                        if (strpos($t, "'") === false) {
     287                                $s = translitteration($t);
     288                                $suggests[$s] = $t;
     289                        }
     290                }
     291                $sug = $suggests;
     292        }
     293       
     294        return $sug;
     295}
     296
     297
     298// trier les mots par nombre d'occurrences reelles dans la base Sphinx
     299// et supprimer ceux qui n'y figurent pas
     300// on se base sur la forme exacte (=mot) ; et sans espaces ni tirets !
     301function indexer_motiver_mots($mots) {
     302        $liste = $mots;
     303        foreach($mots as $i => $m) {
     304                $mots[$i] = '='.preg_replace('/\W/', '', $m);
     305        }
     306        $m = join(' ', $mots);
     307        $query = "SELECT count(id) FROM " . SPHINX_DEFAULT_INDEX . " WHERE MATCH('$m')";
     308
     309        $sphinx = new Sphinx\SphinxQL\SphinxQL(SPHINX_SERVER_HOST, SPHINX_SERVER_PORT);
     310        $all = $sphinx->allfetsel($query);
     311
     312        if (!is_array($all)
     313        OR !is_array($all['query'])
     314        OR !is_array($all['query']['meta'])) {
     315                echo "<p class=error>" . _L('Erreur Sphinx')."</p>";
     316        } else {
     317                foreach($all['query']['meta']['keywords'] as $i => $w) {
     318                        $translitt = substr($w['keyword'], 1);
     319                        $liste[$translitt] = intval($w['docs']);
     320                }
     321                $liste = array_filter($liste);
     322                arsort($liste);
     323                return array_keys($liste);
     324        }
     325}
     326
     327// compare une liste de suggestions au contenu indexé dans la base sphinx
     328function indexer_suggestions_motivees($mot) {
     329        $sug = indexer_suggestions($mot);
     330        if (is_array($sug) AND count($sug) > 0) {
     331                $sug = indexer_motiver_mots($sug);
     332        }
     333        return $sug;
     334}
  • _plugins_/indexer/trunk/iterateur/sphinx.php

    r92023 r93151  
    275275                }
    276276
     277                // expérimental : utiliser aspell
     278                // pour chercher des suggestions de mots-clés
     279                // define('_INDEXER_SUGGESTIONS', 5);
     280                // define('ASPELL_BIN', '/usr/local/bin/aspell');
     281                if (defined('_INDEXER_SUGGESTIONS') AND _INDEXER_SUGGESTIONS) {
     282                        $max_suggestions = _INDEXER_SUGGESTIONS;
     283                        if (isset($result['query']['meta']['keywords'])){
     284                                foreach($result['query']['meta']['keywords'] as $w) {
     285                                        // un mot inexistant ou rare
     286                                        // est possiblement mal orthographié
     287                                        if($w['docs'] <= 2) {
     288                                                $mot = $this->keyword2word($w['keyword'], $q);
     289                                                $suggests = indexer_suggestions_motivees($mot);
     290                                                if (is_array($suggests) && count($suggests)>0) {
     291                                                        $liens_suggestion = array();
     292                                                        // on prend n suggestions
     293                                                        spip_log($suggests, 'indexer');
     294                                                        foreach(array_slice($suggests, 0, $max_suggestions) as $sug) {
     295
     296                                                                $rech = preg_replace('/'.$mot.'/i', $sug, $q);
     297
     298                                                                // tester si la requete modifiée donne plus de resultats ?
     299                                                                // attention à ne pas creer de boucle infernale
     300
     301                                                                $url = parametre_url(self(), 'recherche', $rech);
     302                                                                $liens_suggestion[] = inserer_attribut('<a rel="nofollow">'.$sug.'</a>', 'href', $url);
     303                                                        }
     304                                                }
     305                                                if (count($liens_suggestion)>0) {
     306                                                        $message .= '<div class="indexer_suggestions">'._L('Suggestion : ') .join(', ', $liens_suggestion)."</div>";
     307                                                        $GLOBALS['sphinxReplaceMessage'][$q] = $message;
     308                                                        $this->save('message', $message);
     309                                                }
     310                                        }
     311                                }
     312                        }
     313                }
    277314
    278315                // decaler les docs en fonction de la pagination demandee
Note: See TracChangeset for help on using the changeset viewer.