Pagina 1 di 7 1 2 3 ... ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 68
  1. #1

    [PILLOLA] Costruiamo un VERO motore di ricerca per il nostro sito con MATCH e AGAINST

    Costruiamo un VERO motore di ricerca per il nostro sito con MATCH e AGAINST

    In questa pillola illustrerò come creare una ricerca nel db che sappia ordinare i risultati relativamente alla pertinenza con la chiave. Nel corso della spiegazione, per riferirmi alla stringa di ricerca, utilizzerò la variabile $key.

    Tutti (o quasi) sanno fare un ricerca utilizzando la direttiva LIKE. Questo metodo va bene per ricerche relativamente semplici. Ad esempio per cercare un cognome in una rubrica utilizzeremo una query del genere:

    Codice PHP:
    $sql “SELECT FROM rubrica WHERE cognome LIKE ‘$key’”
    La questione si complica un tantino quando dobbiamo fare una ricerca in un testo e magari la stringa di ricerca che ci aspettiamo non è di una sola parola, ma si può fare ugualmente. Mettiamo che il nostro database contenga una raccolta di articoli di giornale.

    Codice PHP:

    $keys 
    explode (“ “$key);  // creo un array con le varie parole inserite nel campo di ricerca
    $sql “SELECT FROM articoli WHERE “;  //imposto l’inizio della query

    $max count($keys);

    for (
    $a 0$a $max$a++)
    {
    $sql .= “contenuto LIKE ‘$keys[$a]’ OR // aggiungo una parte di query per ogni parola cercata
    }

    $sql .= “0”;  // annullo l’effetto dell’ultimo OR 
    In questo modo abbiamo costruito la query di ricerca dinamicamente. Se avessimo inserito nel campo di ricerca “cane gatto topo” risulterebbe la seguente query:

    Codice PHP:
    $sql “SELECT FROM articoli WHERE contenuto LIKE ‘cane’ OR contenuto LIKE ‘gatto’ OR contenuto LIKE ‘topo’ OR 0”
    Ho fatto tutta questa filippica per far capire i limiti di LIKE. Infatti la query che abbiamo creato ci restituirà gli articoli contenenti cane o gatto o topo ma ordinati per come li trova.

    Quello che vogliamo, invece, è che i risultati siano ordinati per pertinenza. Quindi prima voglio gli articoli che contengono tutte le chiavi di ricerca (cane,gatto,topo) poi quelli che ne contengono solo due, e infine quelli che ne contengono uno solo. Esattamente come quando facciamo una ricerca con google.

    Questa operazione non è possibile con LIKE.


    Lavoreremo quindi le direttive MATCH e AGAINST. I vantaggi li scopriremo in seguito ma una cosa la si può dire subito. Le ricerche eseguite con queste direttive risultano oltre 10 volte più veloci, il motivo principale è che utilizzano un indice fulltext.

    1. Indice fulltext
    Se vogliamo utilizzare MATCH e AGAINST dobbiamo aggiungere un indice fulltext nei campi dove vogliamo poter eseguire le ricerche. L’indice fulltext può essere aggiunto unicamente nei campi di testo (VARCHAR, LONGTEXT, TEXT, ecc…).
    Mettiamo che il nostro database di articoli sia strutturato in questo modo
    Id – titolo – autore – contenuto
    E diciamo che ci interesserà la ricerca nel campo titolo e ovviamente nel campo contenuto.

    Come aggiungere gli indici fulltext al momento della creazione della tabella:

    Codice PHP:
    CREATE TABLE `articoli` ( 
    `
    idINTUNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
    `
    autoreVARCHAR30 NOT NULL ,
    `
    titoloVARCHAR50 NOT NULL ,
    `
    contenutoLONGTEXT NOT NULL ,
    FULLTEXT 
    `
    titolo` ,
    `
    contenuto
    )
    TYPE MYISAM
    Come aggiungere gli indici se la tabella esiste già


    Codice PHP:
    ALTER TABLE `articoliADD FULLTEXT 
    `
    titolo`, 
    `
    contenuto`

    O più semplicemente con PhpMyAdmin, quando si crea un nuovo campo, alla fine si può selezionare fulltext (testo completo).

    Ora siamo pronti per la ricerca. La query più semplice che si può fare (ma anche la più inutile) è la seguente:

    Codice PHP:

    SELECT 
    FROM articoli WHERE MATCH(titolo,contenutoAGAINST('cane'
    Dicevo inutile perché per sfruttare appieno le caratteristiche della ricerca fulltext dobbiamo attivare il modo boleano. Inoltre dobbiamo tenere conto che MATCH e AGAINST restituiscono un valore di pertinenza con il risultato trovato, quindi come dicevo prima, possiamo ordinare il risultato.
    Questo è il modello di query forse più utile:

    Codice PHP:

    SELECT 
    *, MATCH(titolo,descrizioneAGAINST('cane gatto topo' IN BOOLEAN MODE) AS tot FROM articoli WHERE MATCH(titolo,descrizione
    AGAINST ('cane gatto topo' IN BOOLEAN MODEORDER BY tot DESC 
    Come vediamo, con il modo boleano, non abbiamo nemmeno dovuto preoccuparci di explodere la chiave di ricerca. Infatti “cane gatto topo” significa cane OR gatto OR topo (vedremo poco più avanti altri tipi di operatori). Inoltre grazie al valore di pertinenza restituito possiamo creare “tot” per mezzo del quale possiamo ordinare il risultato.
    Ecco dunque che questa query funziona come un motore di ricerca tipo google.
    E questo dovrebbe bastare.
    Ma se avete delle necessità molto particolari gli operatori boleani ci permettono di fare delle ricerche molto raffinate:

     ‘cane gatto topo scoiattolo’ : Deve esserci almeno una di queste parole (OR) come abbiamo visto
     ‘+cane +gatto +topo’ : Devono esserci tutte queste parole (AND). In questo caso avrebbe poco senso ordinare per pertinenza perché tutti i risultati (se ce ne sono) avranno pertinenza totale
     ‘+cane gatto topo’ : Deve esserci cane eventualmente gatto eventualmente topo
     ‘+cane gatto –topo – rana’: Deve esserci cane eventualmente gatto ma NON topo e NON rana
     ‘”cane gatto topo”’ : Deve esserci esattamente “cane gatto topo” in questa sequenza

    Esistono altre combinazioni anche molto complesse, ma vi rimando alla documentazione di MySql.

    Spero di essere stato utile. E per ricompensarvi della fatica di avere letto questo mattone, vi posto la mia classe Search.


    Codice PHP:

    /**
     * Search
     *
     * @package lib
     * @author Tarchini Maurizio
     * @copyright 2008
     * @version 2.0
     * @access public
     */
     
    class Search
    {
        
    #CONFIGURA
        #Parametri ricerca
        
    var $fulltext "campi fulltext da analizzare separati da virgola senza spazi";
        var 
    $table "tabella oggetto della ricerca";
        
    #parametri db
        
    var $host "localhost";
        var 
    $password "db password";
        var 
    $user "root";
        var 
    $db "nome database";
        
    #metodo score -> p in percentuale, f in frazione
        
    var $pf "f";
        
    #FINE CONFIGURAZIONE
        #NON EDITARE OLTRE QUESTA LINEA
        
    var $key;
        var 
    $conn;
        var 
    $res;
        var 
    $total;
        
            function 
    Search($key)
            {
                
    $this->key $key;
            }

            function 
    DbConnectAndSelect()
            {
                
    $this->conn = @mysql_connect($this->host$this->user$this->password) or die ("Impossibile stabilire una connessione con il server.
    MySql risponde: " 
    mysql_error() . "
    Il codice errore é:" 
    mysql_errno());
                
                @
    mysql_select_db($this->db$this->conn) or die ("Impossibile connettersi al database $this->db.
    MySql risponde: " 
    mysql_error() . "
    Il codice errore é:" 
    mysql_errno());
            }

            function 
    GetResource()
            {
                
    $this->DbConnectAndSelect();
                
    $sql "SELECT *, MATCH($this->fulltext) AGAINST('$this->key' IN BOOLEAN MODE) AS tot FROM $this->table WHERE MATCH($this->fulltext) AGAINST('$this->key' IN BOOLEAN MODE) ORDER BY tot DESC";
                
    $this->res mysql_query($sql$this->conn);
                
            }
            
            function 
    CalcScore($tot)
            {
                switch(
    $this->pf)
                {
                    case 
    "f":
                    
    $key_array explode(" "$this->key);
                    
    $this->total count($key_array);
                    return 
    $tot " / " $this->total;
                    break;
                    case 
    "p":
                    
    $key_array explode(" "$this->key);
                    
    $this->total count($key_array);
                    
    $output intval($tot $this->total 100) . "%";
                    return 
    $output;
                    break;
                    default:
                    
    $key_array explode(" "$this->key);
                    
    $this->total count($key_array);
                    return 
    $tot " / " $this->total;
                    
                }
            }
            

    Uso:

    Vanno configurati i parametri all’inizio della classe

    Uso semplice:

    Codice PHP:

    $search 
    = new Search($key);
    $search->GetResource();

    questo punto disponiamo della risorsa necessaria per poter stampare la ricerca

     
    while ($row mysql_fetch_array($search->res))
     {    
        echo 
    $row['titolo'];
     } 
    Se desideriamo avere anche la pertinenza (score):

    Codice PHP:
    $search = new Search($key);
    $search->GetResource();
    while (
    $row mysql_fetch_array($search->res))
    {
        echo 
    $row['titolo'] . " score: " $search->CalcScore($row['tot']);    

    E’ possible avere lo score in percentuale o in frazione.

  2. #2
    interessante thx
    http://codecanyon.net/category/all?ref=Manuelandro
    And I bet she told a million people that she'd stay in touch, Well all the little promises they dont mean much,When theres
    memories to be made

  3. #3

  4. #4
    insomma, é destino che passi inosservata

  5. #5
    Utente di HTML.it
    Registrato dal
    Feb 2003
    Messaggi
    158
    Bè intanto ti ringrazio... in 5 minuti prendendo spunto da te ho creato il mio motore di ricerca ampliando la ricerca a piu tabelle del db, una domanda però.... se non voglio prendere solo le parole intere come devo modificare questa:

    Codice PHP:
    SELECT *, MATCH(titolo,descrizioneAGAINST('cane gatto topo' IN BOOLEAN MODE) AS tot FROM articoli WHERE MATCH(titolo,descrizione
    AGAINST ('cane gatto topo' IN BOOLEAN MODEORDER BY tot DESC 
    Con questa mi trova solo le parole intere, posso mettere da qulche parte un like???

  6. #6
    Davvero un bel pillolone!

    Complimenti... anche per la spiegazione dettagliata e semplice.

    <ALCIO />
    Per cortesia: no PVT Tecnici
    ******* LINKS *******
    SRL
    MetalWave

  7. #7
    Originariamente inviato da Yeye
    una domanda però.... se non voglio prendere solo le parole intere come devo modificare questa:
    Cosa intendi? qualcosa tipo il % in like?

  8. #8
    Utente di HTML.it L'avatar di telegio
    Registrato dal
    Sep 2001
    Messaggi
    2,592
    avrei voluto darti la soddisfazione di UPparti quando l'hai postata, ma evidentemente dormivo da qualche parte.. forse ero appisolato nel forum di flash..
    ti uppo ora e ti ringrazio, anche senza provarla, perchè credo sia una cosa molto utile...
    anche io avevo fatto una cosa simile ma essendo a un livello di gran lunga inferiore a te ( ) mancavano delle cosette, delle funzioni, anche se sul sito per cui l'ho fatta va e dall'estate non si sono lamentati...


  9. #9
    complimenti mtx_maurizio

    cmq ho una domandina da porti: in questo modo cerca la parola esatta o le parole esatte, ma se invece volessi cercare unaparola contenuta in una stringa?

    mi spiego meglio conun esempio:

    testando questo metodo da te descritto se ad esempio cerco la parola "assicurazione" mi trova tuttii risultati che contengono la parola. fin quì ok, ma se cerco solo "assicur" ad esempio non mi da risultati.
    come posso risolvere?

    posso fare un controllo dopo la query match verificando se sono ritornate 0 righe facendogli po fare un like? o è tardi e sto dicendo minchiae a vanvera?

    cmq ancora complimenti
    Per una battaglia sono sempre a disposizione

  10. #10
    Credo (e dico credo perchè mysql è così vasto che ogni giorno si può imparare qualcosa di nuovo) che non sia possibile fare una cosa del genere direttamente. MATCH e AGAINST opernao una ricerca fulltext basata su degli indici; il suo scopo preciso è fare un'analisi del testo nel suo insieme. Voler fare una ricerca del genere (fulltex + parti di stringa) mi sembra un po' come volere una ferrari con le ridotte.
    E' possibile che vi sia una soluzione, ma al momento non ho idee. Ci vorrebbe un gran vizir di mysql tipo piero.mac

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.