Script php: Ordinare risultati di ricerca per rilevanza e pertinenza

   difficoltà:  script script script script script

Script simili
19/9/2006


Sul blog di Marlenek si discuteva su come poter ordinare i risultati di una ricerca per pertinenza alla stringa cercata. Il primo problema da risolvere è quello di capire cosa voglia dire pertinenza, secondo quindi quali fattori decidere che un risultato di una ricerca sia più pertinente di un altro.
Per maggiore chiarezza consiglio di andare a vedere il post sul blog: Ordinamento e pertinenza. Marlenek cita alcuni punti che farebbero una ricerca più pertinente di un altra. Riassumendo: Presenza del maggior numero di parole, Relazione/vicinanza tra le parole, Il significato delle parole, La social relevance.
Un fattore per me importante potrebbe essere anche la posizione in cui si trovano le parole. Ad esempio se le parole si trovano nel titolo la rilevanza delle stesse sarà superiore.

Nello script che segue l'idea è proprio questa.
Prendiamo la stringa di ricerca. La ripuliamo da quegli elementi che non sono rilevanti ai fini della ricerca. Per esempio le congiunzioni o gli avverbi. La funzione PulisciQuery() serve proprio a questo. Abbiamo li un elenco modificabile degli elementi da non conteggiare. Oltre ad essi sono eliminati anche tutto ciò che è punteggiatura.

Pulita la stringa abbiamo l'elenco delle keyword a noi necessarie che riuniremo in un array con la funzione QueryToArray().

Con un ciclo sulle keyword possiamo creare la nostra query mysql nella funzione CreaQueryRicerca(). Le variabili passate alla funzione oltre alle keyword sarà il peso delle parole trovate nel titolo, il peso delle parole trovate nel testo e il livello di accuratezza della ricerca. Il livello di accuratezza dirà se la ricerca dovrà cercare la parola anche se contenuta in altre (cerco osso trovo ossobuco) o meno.

Sommando il peso delle parole chiave trovate otterremo la rilevanza del risultato. Con 3 keyword trovate nel titolo (rilevanza 5) otterremo 15 punti. Con 4 parole trovate nel testo (rilevanza 3) otterremo 12 punti per un totale di 27 punti.

Cosa è migliorabile in questo script? Sicuramente che non tiene conto del numero di occorrenze di ogni parola nel testo. un titolo del tipo "keyword_1 keyword_2" avrà stessa rilevanza di "keyword_1 keyword_2 keyword_2". Con la funzione mysql substrCount, per contare occorrenze di una stringa in un altra, si potrebbe ovviare, ma essa è presente solo in Mysql 5. 

<?
// PulisciQuery: Restituisce la query pulita da porole inutili(congiunzioni etc.)
function PulisciQuery($queryvar){
// array parole di cui non tener conto nelle ricerche
$arrayBadWord=Array("lo", "l", "il", "la", "i", "gli", "le", "uno", "un", "una", "un", "su", "sul", "sulla", "sullo", "sull", "in", "nel", "nello", "nella", "nell", "con", "di", "da", "dei", "d", "della", "dello", "del", "dell", "che", "a", "dal", "è", "e", "per", "non", "si", "al", "ai", "allo", "all", "al", "o");
$queryclean=strtolower($queryvar);
for($a=0;$a<count($arrayBadWord);$a++){
// sostituisco bad words con espressioni regolari \b ->solo se parole singole, non facenti parti di altre
$queryclean=preg_replace("/\b".$arrayBadWord[$a]."\b/", "", $queryclean);
}
// elimino tutti caratteri non alfanumerici sostituendeli con uno spazio
$queryclean=preg_replace("/\W/", " ", $queryclean);
return $queryclean;
}

// QueryToArray: Restituisce array delle parole chiave da cercare
function QueryToArray($queryvar){
// pulisco query da parole accessorie e caratteri non alfanumerici
$querypulita=PulisciQuery($queryvar);
// costruisco l'array contenente tutte le parole da cercare
$arraySearch=explode(" ", $querypulita);
// elimino doppioni dall'array
$arraySearchUnique=array_unique($arraySearch);
// elimino valori array vuoti o con solo spazi
$arrayVuoto=Array(""," ");
$arrayToReturn=array_diff($arraySearchUnique, $arrayVuoto);
return $arrayToReturn;
}

// CreaQueryRicerca: Creo la query di ricerca.
// peso titolo se non specificato=5, peso testo se non specificato=3
// searchlevel -> 1 o 0. default 1. Se 0 trova parole non complete. Es. cerchi osso?ok anche ossobuco. Se 1 non succede.
function CreaQueryRicerca($queryvar, $pesotitolo=5, $pesotesto=3, $searchlevel=1){
// trasformo la stringa in un array di parole da cercare
$arrayToFind=QueryToArray($queryvar);
// numero elementi da cercare
$elementiToFind=count($arrayToFind);
// punteggio massimo raggiungibile
$maxPoint=$elementiToFind*$pesotitolo+$elementiToFind*$pesotesto;
if($elementiToFind==0){
return "";
}else{
$query="select ROUND((";
$sqlwhere="";
// ciclo per ogni parola trovata ($Valore)
foreach($arrayToFind As $Indice => $Valore){
// se $Valore è presente in titolo instr(titolo, '$Valore') restituirà 1 altrimenti 0
// moltiplico il valore restituito (1 o 0) per il peso della parola (5 per il titolo, 3 per testo)
if($searchlevel==1){
// regexp: uso espressioni regolari. [[:<:]] equivale a \b per separare parole
$query.="((titolo REGEXP '[[:<:]]".$Valore."[[:>:]]')>0)*$pesotitolo+";
$query.="((testo REGEXP '[[:<:]]".$Valore."[[:>:]]')>0)*$pesotesto+";
$sqlwhere.="titolo REGEXP '[[:<:]]".$Valore."[[:>:]]' OR testo REGEXP '[[:<:]]".$Valore."[[:>:]]' OR ";
}else{
$query.="(instr(titolo, '$Valore')>0)*$pesotitolo+";
$query.="(instr(testo, '$Valore')>0)*$pesotesto+";
$sqlwhere.="titolo like '%$Valore%' OR testo like '%$Valore%' OR ";
}
}
$sqlwhere=substr($sqlwhere, 0, strlen($sqlwhere)-4);
// calcolo la percentuale di rilevanza --> rilevanza*100/$maxPoint
$query.="0)*100/$maxPoint,2) as rilevanza, ID, titolo from tabella WHERE $sqlwhere order by rilevanza DESC";
return $query;
}
}

// stringa da ricercare presa da form.
//$queryvar="parola1 parola2"; //esempio
if(isset($_POST['search'])){$queryvar=$_POST['search'];}else{$queryvar="";}

if(trim($queryvar)=="" || strlen(trim($queryvar))<=3){
echo "La stringa di ricerca deve contenere più di 3 caratteri.";
}else{
// query da eseguire
// primo valore passato è peso delle parole cercate nel titolo, secondo peso parole nel testo
// terzo valore cercato: 1 o0: accuratezza ricerca. Se 0 trova parole non complete. Es. cerchi osso?ok anche ossobuco. Se 1 non succede.
// CreaQueryRicerca($queryvar) -> prende primo e secondo valore di default
$queryRicerca=CreaQueryRicerca($queryvar, 5, 3, 1);
// Eseguo la query
// La query restituisce ID, titolo e % di rilevanza del risultato
echo $queryRicerca;
}
?>





Commenti


  daweb

29/1/2007 11:41:09

Molto elegante anche questo script.

Ho visto che utilizzi una ricerca di tipo Like, non sarebbe meglio una fulltext?

  Fabio

29/1/2007 12:15:54

Guarda, quando stavo cercando una soluzione ho provato anche il FULLTEXT, ma avevo abbandonato questa via. Non ricordo esattamente il perchè..ma se non sbaglio l'ordine di rilevanza non mi sembrava corretto.

  daweb

29/1/2007 13:57:25

Forse perché ha diverse limitazioni la ricerca di tipo FULLTEXT.

In un vecchio progetto avevo pensato di switchare il tipo di ricerca a seconda della chiave passata... andrò a ridarci un'occhiata...

  bob

30/6/2007 18:07:38

Complimenti!Davvero uno splendido script!Molto funzionale!

  Mark116

23/8/2011 11:29:29

Ciao, per utilizzare lo script devo modificare in questo punto?

$query.="0)*100/$maxPoint,2) as rilevanza, ID, titolo from tabella WHERE $sqlwhere order by rilevanza DESC";

Inserendo al posto di tabella il nome della mia tabella e modificando ID e titolo per farli combaciare con i miei giusto?


  Simone

19/7/2012 17:38:57

Buonasera, vorrei sapere cosa modificare per adattarlo alle mie tabelle cortesemente.

Grazie



Lascia un commento


Codice di controllo*:
Nome*:
Email/Link:
Testo*:
 
I campi contrassegnati con * sono obbligatori.