source: spip-zone/_plugins_/fulltext/inc/recherche_to_array.php @ 47829

Last change on this file since 47829 was 47829, checked in by kent1@…, 10 years ago

Une erreur dans la requète à priori cependant la recherche sur la jointure avec les documents ne semble tout de même pas fonctionner...

File size: 8.9 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2011                                                *
7 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8 *                                                                         *
9 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
10 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
11\***************************************************************************/
12
13
14if (!defined('_ECRIRE_INC_VERSION')) return;
15
16// Determiner les tables gerees via spip_xxx_liens
17function recherche_tables_liens() {
18        if ($GLOBALS['spip_version_base'] >= 16428)
19                return array('document', 'auteur', 'mot');
20        else
21        if ($GLOBALS['spip_version_base'] >= 12008)
22                return array('document');
23        else
24                return array();
25}
26
27// methodes sql
28function inc_recherche_to_array_dist($recherche, $options=null) {
29
30        $requete = array(
31        "SELECT"=>array(),
32        "FROM"=>array(),
33        "WHERE"=>array(),
34        "GROUPBY"=>array(),
35        "ORDERBY"=>array(),
36        "LIMIT"=>"",
37        "HAVING"=>array()
38        );
39
40        $options = array_merge(
41                array('table' => 'article',
42                ),
43                (array)$options
44        );
45        $table = $options['table'];
46        $serveur = $options['serveur'];
47
48        include_spip('inc/rechercher');
49
50        // s'il n'y a qu'un mot mais <= 3 lettres, il faut le chercher avec une *
51        // ex: RFC => RFC* ; car mysql fulltext n'indexe pas ces mots
52        if (preg_match('/^\w{1,3}$/', $recherche))
53                $recherche .= '*';
54
55        list($methode, $q, $preg) = expression_recherche($recherche, $options);
56
57        $l = liste_des_champs();
58        $champs = $l[$table];
59
60        $jointures = $options['jointures']
61                ? liste_des_jointures()
62                : array();
63
64        $_id_table = id_table_objet($table);
65        $requete['SELECT'][] = "t.".$_id_table;
66        $a = array();
67        // Recherche fulltext
68        foreach ($champs as $champ => $poids) {
69                if (is_array($champ)){
70                  spip_log("requetes imbriquees interdites");
71                } else {
72                        if (strpos($champ,".")===FALSE)
73                                $champ = "t.$champ";
74                        $requete['SELECT'][] = $champ;
75                        $a[] = $champ.' '.$methode.' '.$q;
76                }
77        }
78        if ($a) $requete['WHERE'][] = join(" OR ", $a);
79        $requete['FROM'][] = table_objet_sql($table).' AS t';
80
81        // FULLTEXT
82        $fulltext = false; # cette table est-elle fulltext?
83        if ($keys = fulltext_keys($table, 't', $serveur)) {
84                $fulltext = true;
85
86                $r = trim(preg_replace(',\s+,', ' ', $recherche));
87
88                // si espace, ajouter la meme chaine avec des guillemets pour ameliorer la pertinence
89                $pe = (strpos($r, ' ') AND strpos($r,'"')===false)
90                        ? sql_quote(trim("\"$r\""), $serveur) : '';
91
92                // On utilise la translitteration pour contourner le pb des bases
93                // declarees en iso-latin mais remplies d'utf8
94                if (($r2 = translitteration($r)) != $r)
95                        $r .= ' '.$r2;
96
97                $p = sql_quote(trim("$r"), $serveur);
98
99                // On va additionner toutes les cles FULLTEXT
100                // de la table
101                $score = array();
102                foreach ($keys as $name => $key) {
103                        $val = "MATCH($key) AGAINST ($p)";
104                        // Une chaine exacte rapporte plein de points
105                        if ($pe)
106                                $val .= "+ 2 * MATCH($key) AGAINST ($pe)";
107
108                        // Appliquer les ponderations donnees
109                        // quels sont les champs presents ?
110                        // par defaut le poids d'une cle est fonction decroissante
111                        // de son nombre d'elements
112                        // ainsi un FULLTEXT sur `titre` vaudra plus que `titre`,`chapo`
113                        $compteur = preg_match_all(',`.*`,U', $key, $ignore);
114                        $mult = intval(sqrt(1000/$compteur))/10;
115
116                        // (Compat ascendante) si un FULLTEXT porte sur un seul champ,
117                        // ET est nomme de la meme facon : `titre` (`titre`)
118                        // sa ponderation est eventuellement donnee par la table $liste
119                        if ($key == "t.`${name}`"
120                        AND $ponderation = $liste[$table][$name])
121                                $mult = $ponderation;
122
123                        // Appliquer le coefficient multiplicatif
124                        if ($mult != 1)
125                                $val = "($val) * $mult";
126
127                        // si symboles booleens les prendre en compte
128                        if ($boolean = preg_match(', [+-><~]|\* |".*?",', " $r "))
129                                $val = "MATCH($key) AGAINST ($p IN BOOLEAN MODE) * $mult";
130                        $score[] = $val;
131                }
132
133                // On ajoute la premiere cle FULLTEXT de chaque jointure
134                $from = array_pop($requete['FROM']);
135
136                if (is_array($jointures[$table]))
137                foreach(array_keys($jointures[$table]) as $jtable) {
138                        $i++;
139                        if ($mkeys = fulltext_keys($jtable, 'obj'.$i, $serveur)) {
140                                $score[] = "SUM(MATCH(".array_shift($mkeys).") AGAINST ($p".($boolean ?' IN BOOLEAN MODE':'')."))";
141                                $_id_join = id_table_objet($jtable);
142                                $table_join = table_objet($jtable);
143
144
145                                $lesliens = recherche_tables_liens();
146                                if (in_array($jtable, $lesliens))
147                                        $from .= "
148                                        LEFT JOIN spip_${jtable}s_liens as lien$i ON lien$i.id_objet=t.$_id_table AND lien$i.objet='${table}'
149                                        LEFT JOIN spip_${jtable}s as obj$i ON obj$i.$_id_join=lien$i.$_id_join
150                                        ";
151                                else
152                                        $from .= "
153                                        LEFT JOIN spip_${jtable}s_${table}s as lien$i ON lien$i.$_id_table=t.$_id_table
154                                        LEFT JOIN spip_${table_join} AS obj$i ON lien$i.$_id_join=obj$i.$_id_join
155                                        ";
156                        }
157                }
158                $requete['FROM'][] = $from;
159                $score = join(' + ', $score).' AS score';
160                spip_log($score, 'recherche');
161
162                // si on define(_FULLTEXT_WHERE_$table,'date>"2000")
163                // cette contrainte est ajoutee ici:)
164                $requete['WHERE'] = array();
165                if (defined('_FULLTEXT_WHERE_'.$table))
166                        $requete['WHERE'][] = constant('_FULLTEXT_WHERE_'.$table);
167                else
168                        if (!test_espace_prive()
169                        AND in_array($table, array('article', 'rubrique', 'breve', 'forum', 'syndic_article')))
170                                $requete['WHERE'][] = "t.statut='publie'";
171
172                // nombre max de resultats renvoyes par l'API
173                define('_FULLTEXT_MAX_RESULTS', 500);
174
175                // preparer la requete
176                $requete['SELECT'] = array(
177                        "t.$_id_table"
178                        ,$score
179                );
180
181                // popularite ?
182                if (true # config : "prendre en compte la popularite
183                AND $table == 'article')
184                        $requete['SELECT'][] = "t.popularite";
185
186                # "t.date"
187                # "t.note"
188
189                #array_unshift($requete['FROM'], table_objet_sql($table)." AS t");
190                $requete['GROUPBY'] = array("t.$_id_table");
191                $requete['ORDERBY'] = "score DESC";
192                $requete['LIMIT'] = "0,"._FULLTEXT_MAX_RESULTS;
193                $requete['HAVING'] = '';
194
195                #var_dump($requete);
196                #spip_log($requete,'recherche');
197#                       exit;
198        }
199
200        $r = array();
201
202        $s = sql_select(
203                $requete['SELECT'], $requete['FROM'], $requete['WHERE'],
204                implode(" ",$requete['GROUPBY']),
205                $requete['ORDERBY'], $requete['LIMIT'],
206                $requete['HAVING'], $serveur
207        );
208
209        if (!$s) spip_log(mysql_errno().' '.mysql_error()."\n".$recherche, 'recherche');
210
211        while ($t = sql_fetch($s,$serveur)
212        AND (!isset($t['score']) OR $t['score']>0)) {
213                $id = intval($t[$_id_table]);
214
215                // FULLTEXT
216                if ($fulltext) {
217                        $pts = $t['score'];
218
219                        if (isset($t['popularite'])
220                        AND $mpop = $GLOBALS['meta']['popularite_max'])
221                                $pts *= (1+$t['popularite']/$mpop);
222
223                        $r[$id]['score'] = $pts;
224
225                } ELSE
226                // fin FULLTEXT
227
228                if ($options['toutvoir']
229                OR autoriser('voir', $table, $id)) {
230                        // indiquer les champs concernes
231                        $champs_vus = array();
232                        $score = 0;
233                        $matches = array();
234
235                        $vu = false;
236                        foreach ($champs as $champ => $poids) {
237                                $champ = explode('.',$champ);
238                                $champ = end($champ);
239                                if ($n = 
240                                        ($options['score'] || $options['matches'])
241                                        ? preg_match_all($preg, translitteration_rapide($t[$champ]), $regs, PREG_SET_ORDER)
242                                        : preg_match($preg, translitteration_rapide($t[$champ]))
243                                ) {
244                                        $vu = true;
245
246                                        if ($options['champs'])
247                                                $champs_vus[$champ] = $t[$champ];
248                                        if ($options['score'])
249                                                $score += $n * $poids;
250                                        if ($options['matches'])
251                                                $matches[$champ] = $regs;
252
253                                        if (!$options['champs']
254                                        AND !$options['score']
255                                        AND !$options['matches'])
256                                                break;
257                                }
258                        }
259
260                        if ($vu) {
261                                $r[$id] = array();
262                                if ($champs_vus)
263                                        $r[$id]['champs'] = $champs_vus;
264                                if ($score)
265                                        $r[$id]['score'] = $score;
266                                if ($matches)
267                                        $r[$id]['matches'] = $matches;
268                        }
269                }
270        }
271
272
273        // Gerer les donnees associees
274        if (!$fulltext
275        AND isset($jointures[$table])
276        AND $joints = recherche_en_base(
277                        $recherche,
278                        $jointures[$table],
279                        array_merge($options, array('jointures' => false))
280                )
281        ) {
282                foreach ($joints as $jtable => $jj) {
283                        $it = id_table_objet($table);
284                        $ij =  id_table_objet($jtable);
285                        $lesliens = recherche_tables_liens();
286                        if (in_array($jtable, $lesliens))
287                                $s = sql_select("id_objet as $it", "spip_${jtable}s_liens", array("objet='$table'",sql_in('id_'.${jtable}, array_keys($jj))), '','','','',$serveur);
288                        else
289                                $s = sql_select("$it,$ij", "spip_${jtable}s_${table}s", sql_in('id_'.${jtable}, array_keys($jj)), '','','','',$serveur);
290                        while ($t = sql_fetch($s)) {
291                                $id = $t[$it];
292                                $joint = $jj[$t[$ij]];
293                                if (!isset($r))
294                                        $r = array();
295                                if (!isset($r[$id]))
296                                        $r[$id] = array();
297                                if ($joint['score'])
298                                        $r[$id]['score'] += $joint['score'];
299                                if ($joint['champs'])
300                                foreach($joint['champs'] as $c => $val)
301                                        $r[$id]['champs'][$jtable.'.'.$c] = $val;
302                                if ($joint['matches'])
303                                foreach($joint['matches'] as $c => $val)
304                                        $r[$id]['matches'][$jtable.'.'.$c] = $val;
305                        }
306                }
307        }
308
309        return $r;
310}
311
312
313?>
Note: See TracBrowser for help on using the repository browser.