Valider addce92c rédigé par cerdic's avatar cerdic
Parcourir les fichiers

#1903 : permettre une recherche sur base distante.

Dans ce cas, on stocke dans la table resultats du serveur principal les résultats de recherche, et on produit une requete qui contient
explicitement les id et les points des résultats (comme le faisait SPIP<2)
Pour ce faire on étend la table des résultats avec une colonne serveur qui stocke un hash du serveur (pour limiter la longueur du champ) quand ce n'est pas le serveur principal.

Au passage, on ajoute également une colonne table_objet pour faire expliciter la table_objet des résultats, le hash ne contenant plus que le terme de la recherche proprement dite, ce qui réouvre la voie vers une boucle de recherche composite multi-objets
parent fdb49a8c
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+2 −0
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -19,6 +19,8 @@ $spip_resultats = array(
 		"recherche"	=> "char(16) DEFAULT '' NOT NULL",
		"id"	=> "INT UNSIGNED NOT NULL",
 		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
		"table_objet"	=> "varchar(30) DEFAULT '' NOT NULL",
		"serveur"	=> "char(16) DEFAULT '' NOT NULL", // hash md5 partiel du serveur de base ('' pour le serveur principal)
		"maj"	=> "TIMESTAMP" );

$spip_resultats_key = array(
+60 −9
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -21,6 +21,11 @@ if (!defined('_DELAI_CACHE_resultats')) define('_DELAI_CACHE_resultats', 600);
 * et points =  des requetes du moteur de recherche
 * http://doc.spip.org/@inc_prepare_recherche_dist
 * 
 * Le parametre $serveur est utilise pour savoir sur quelle base on cherche
 * mais l'index des resultats est toujours stocké sur le serveur principal
 * car on ne sait pas si la base distante dispose d'une table spip_resultats
 * ni meme si on aurait le droit d'ecrire dedans
 *
 * @param string $recherche
 *    chaine recherchee
 * @param string $table
@@ -31,9 +36,11 @@ if (!defined('_DELAI_CACHE_resultats')) define('_DELAI_CACHE_resultats', 600);
 *    serveur de base de donnees
 * @param array $modificateurs
 *    modificateurs de boucle, ie liste des criteres presents
 * @param string $primary
 *    cle primaire de la table de recherche
 * @return array
 */
function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false, $serveur='', $modificateurs = array()) {
function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false, $serveur='', $modificateurs = array(), $primary='') {
	static $cache = array();
	$delai_fraicheur = min(_DELAI_CACHE_resultats,time()-$GLOBALS['meta']['derniere_modif']);

@@ -49,13 +56,14 @@ function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false,
	
	$rechercher = false;

	if (!isset($cache[$recherche][$table])){
	if (!isset($cache[$serveur][$table][$recherche])){
		$hash_serv = ($serveur?substr(md5($serveur),0,16):'');
		$hash = substr(md5($recherche . $table),0,16);
		$row = sql_fetsel('UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(maj) AS fraicheur','spip_resultats',"recherche='$hash'",'','fraicheur DESC','0,1','',$serveur);
		$where = "(resultats.recherche='$hash' AND resultats.table_objet=".sql_quote($table)." AND resultats.serveur='$hash_serv')";
		$row = sql_fetsel('UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(resultats.maj) AS fraicheur','spip_resultats AS resultats',$where,'','fraicheur DESC','0,1');
		if (!$row OR ($row['fraicheur']>$delai_fraicheur)){
		 	$rechercher = true;
		}
		$cache[$recherche][$table] = array("resultats.points AS points","recherche='$hash'");
	}

	// si on n'a pas encore traite les donnees dans une boucle precedente
@@ -80,7 +88,7 @@ function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false,

		// supprimer les anciens resultats de cette recherche
		// et les resultats trop vieux avec une marge
		sql_delete('spip_resultats', 'NOT(' .sql_date_proche('maj', (0-($delai_fraicheur+100)), " SECOND") . ") OR (recherche='$hash')",$serveur);
		sql_delete('spip_resultats', 'NOT(' .sql_date_proche('maj', (0-($delai_fraicheur+100)), " SECOND") . ") OR ($where)");

		// inserer les resultats dans la table de cache des resultats
		if (count($points)){
@@ -89,16 +97,59 @@ function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false,
				$tab_couples[] = array(
					'recherche' => $hash,
					'id' => $id,
					'points' => $p['score']
					'points' => $p['score'],
					'table_objet' => $table,
					'serveur' => $hash_serv,
				);
			}
			sql_insertq_multi('spip_resultats',$tab_couples,array(),$serveur);
			sql_insertq_multi('spip_resultats',$tab_couples,array());
		}
	}

	if (!isset($cache[$serveur][$table][$recherche])){
		if (!$serveur)
			$cache[$serveur][$table][$recherche] = array("resultats.points AS points",$where);
		else {
			if (sql_countsel('spip_resultats as resultats',$where))
			$rows = sql_allfetsel('resultats.id,resultats.points','spip_resultats as resultats',$where);
			$cache[$serveur][$table][$recherche] = generer_select_where_explicites($table, $primary, $rows, $serveur);
		}
	}

	return $cache[$recherche][$table];
	return $cache[$serveur][$table][$recherche];
}


/**
 * Generer le select et where qui contiennent explicitement
 * les id et points (ie comme dans SPIP 1.9.x)
 * quand on fait une recherche sur une table externe
 *
 * @param string $table
 * @param string $primary
 * @param array $rows
 * @param string $serveur
 * @return array
 */
function generer_select_where_explicites($table, $primary, $rows, $serveur){
	# calculer le {id_article IN()} et le {... as points}
	if (!count($rows)){
		return array("''", "0=1");
	}
	else {
		$listes_ids = array();
		$select = '0';
		foreach ($rows as $r)
			$listes_ids[$r['points']][] = $r['id'];

		foreach ($listes_ids as $p => $ids)
			$select .= "+$p*(".
			           sql_in("$table.$primary", $ids,'',$serveur)
			           .") ";

		return array("$select AS points ",calcul_mysql_in("$table.$primary",array_map('reset',$rows),'',$serveur));
	}
}


?>
+1 −1
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -321,7 +321,7 @@ $spip_version_branche = "2.3.0-dev";
// (= numero SVN de leur derniere modif cassant la compatibilite et/ou necessitant un recalcul des squelettes)
$spip_version_code = 17306;
// version de la base SQL (= numero SVN de sa derniere modif)
$spip_version_base = 16428;
$spip_version_base = 17555;

// version de l'interface a la base
$spip_sql_version = 1;
+4 −3
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -320,8 +320,6 @@ function maj_liens($pivot,$l='') {
	}
}

//TODO : upgrades a activer
/*
$GLOBALS['maj'][17311] = array(
	array('ecrire_meta',"multi_objets",implode(',',
				 array_diff(
@@ -334,6 +332,9 @@ $GLOBALS['maj'][17311] = array(
					 array('')
				 ))),
);
*/
$GLOBALS['maj'][17555] = array(
	array('sql_alter',"TABLE spip_resultats ADD table_objet varchar(30) DEFAULT '' NOT NULL"),
	array('sql_alter',"TABLE spip_resultats ADD serveur char(16) DEFAULT '' NOT NULL"),
);

?>
+7 −3
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -191,14 +191,18 @@ function critere_recherche_dist($idb, &$boucles, $crit) {
	$boucle->hash .= '
	// RECHERCHE
	$prepare_recherche = charger_fonction(\'prepare_recherche\', \'inc\');
	list($rech_select, $rech_where) = $prepare_recherche('.$quoi.', "'.$boucle->id_table.'", "'.$crit->cond.'","' . $boucle->sql_serveur . '",'.$_modificateur.');
	list($rech_select, $rech_where) = $prepare_recherche('.$quoi.', "'.$boucle->id_table.'", "'.$crit->cond.'","' . $boucle->sql_serveur . '",'.$_modificateur.',"'.$boucle->primary.'");
	';

	$t = $boucle->id_table . '.' . $boucle->primary;
	if (!in_array($t, $boucles[$idb]->select))
	  $boucle->select[]= $t; # pour postgres, neuneu ici
	// jointure uniquement sur le serveur principal
	// (on ne peut joindre une table d'un serveur distant avec la table des resultats du serveur principal)
	if (!$boucle->sql_serveur) {
		$boucle->join['resultats']=array("'".$boucle->id_table."'","'id'","'".$boucle->primary."'");
		$boucle->from['resultats']='spip_resultats';
	}
	$boucle->select[]= '$rech_select';
	//$boucle->where[]= "\$rech_where?'resultats.id=".$boucle->id_table.".".$boucle->primary."':''";