2011-08-29 15 views
7

Sto provando a creare un motore di ricerca per un sito basato su inventario. Il problema è che ho informazioni all'interno di bbtags (come in [b]test[/b] sentence, lo test deve essere valutato a 3, mentre sentence deve essere valutato a 1).PHP mysql query di ricerca

Ecco un esempio di un indice:
My test sentence, my my (ha uno SKU di TST-DFS)
Database:

|Product| word |relevancy| 
| 1 | my | 3 | 
| 1 | test | 1 | 
| 1 |sentence| 1 | 
| 1 | TST-DFS| 10 | 

Ma come faccio a corrispondere TST-DFS se l'utente ha digitato in TST DFS? Vorrei che la SKU avesse una rilevanza di dire, invece del completo 10 ..

Ho sentito dire che la funzione di ricerca FULL TEXT in MySQL sarebbe di aiuto, ma non riesco a trovare un buon modo per fallo. Vorrei evitare cose come UNIONS e mantenere la query il più ottimizzata possibile.

Qualsiasi aiuto con un buon sistema per questo sarebbe fantastico.

Grazie, Max

+0

non è possibile utilizzare le funzionalità 'FULLTEXT' di MySQL, o è che cosa si intende quando si dice "indice"? – Bojangles

+0

Il problema è che ho molte informazioni importanti, ma FULLTEXT di MySQL non sa che è importante (come i numeri di sku, il nome del prodotto e altre parole certe). Quindi sto indicizzando ogni parola in ogni prodotto, e non credo che il FULLTEXT di MySQL possa aiutarmi a cercare tra le righe. – Ben

+0

Oh giusto. Per quanto posso vedere, no, 'FULLTEXT' non sarebbe affatto utile. Davvero un peccato, visto che è una parte meravigliosa di MySQL. – Bojangles

risposta

5

Ma come dovrei abbinare TST-DFS se l'utente ha digitato TST DFS?
Vorrei che SKU per avere una rilevanza dei ricorda 8, al posto del pieno 10 ..

Se ho ricevuto la domanda giusta, la risposta è in realtà facile.
Bene, se la tua query è forge prima di inviarla a mysql.

Ok, diciamo che abbiamo $query e contiene TST-DFS.

Ci concentreremo su intervalli di tempo? Suppongo che dovremmo, come la maggior parte dei motori di ricerca fanno, quindi:

$ok=preg_match_all('#\w+#',$query,$m); 

Ora se questo modello ha trovato ... $m[0] contiene l'elenco delle parole in $query.
Questo può essere sintonizzato sulla SKU, ma la corrispondenza con parole complete in una moda AND è praticamente ciò che l'utente presume sta accadendo. (Come accade su google e yahoo)

Poi abbiamo bisogno di cucinare un $expr un'espressione che sarà iniettato nella nostra query finale.

if(!$ok) { // the search string is non-alphanumeric 
    $expr="false"; 
} else { // the search contains words that are no in $m[0] 
    $expr=''; 
    foreach($m[0] as $word) { 
    if($expr) 
     $expr.=" AND "; // put an AND inbetween "LIKE" subexpressions 
    $s_word=addslashes($word); // I put a s_ to remind me the variable 
           // is safe to include in a SQL statement, that's me 
    $expr.="word LIKE '%$s_word%'"; 
    } 
} 

Ora $expr dovrebbe essere simile "words LIKE '%TST%' AND words LIKE '%DFS%'"

con quel valore, possiamo costruire la query finale:

$s_expr="($expr)"; 
$s_query=addslashes($query); 

$s_fullquery= 
"SELECT (Product,word,if((word LIKE '$s_query'),relevancy,relevancy-2) as relevancy) ". 
"FROM some_index ". 
"WHERE word LIKE '$s_query' OR $s_expr"; 

che recita, per "TST-DFS":

SELECT (Product,word,if((word LIKE 'TST-DFS'),relevancy,relevancy-2) as relevancy) 
FROM some_index 
WHERE word LIKE 'TST-DFS' OR (word LIKE '%TST%' AND word LIKE '%DFS%') 

Come potete vedere, nella prima riga SELECT, se la partita è parziale, MySQL ritorno pertinenza-2

Nella terza, la clausola WHERE, se la partita piena fallisce, $s_expr, query corrispondenza parziale abbiamo cucinato in anticipo, è provato anziché.

+0

corretto. la mia logica era sbagliata. ** Ora ** '$ expr' dovrebbe apparire come' parole LIKE '% TST%' E parole LIKE '% DFS%' ' – ZJR

+0

Quindi dove stai ottenendo la colonna' relevancy'? – Ben

+0

non importa su quanto sopra, come funzionerebbe con una query di più parole? Sembra che si stia paragonando sia alla parola perfettamente, sia che contenga tutte le parole d'ordine, ho ragione su questo? – Ben

0

vorrei aggiungere una colonna che è spogliato di tutto, errori di ortografia del personaggio speciale, e quindi upcased (o creare una funzione che mette a confronto il testo che è stato spogliato e upcased). In questo modo la tua pertinenza sarà coerente.

2

mi piace in minuscolo tutto e togliere i caratteri speciali (come in un numero di telefono o carta di credito prendo tutto fuori da entrambe le parti, che non è un numero)

1

Piuttosto che cercare di creare il proprio FTS soluzione, potresti provare ad adattare il motore MySQL FTS alle tue esigenze. Quello che ho visto fare è creare una nuova tabella per memorizzare i tuoi dati FTS. Crea una colonna per ogni diversa porzione di dati che desideri avere una pertinenza diversa. Per il tuo campo sku puoi memorizzare lo sku grezzo, con spazi, trattini bassi, trattini e qualsiasi altro carattere speciale intatto. Quindi memorizzare una versione ridotta con tutte queste cose rimosse. Potresti anche voler salvare una versione con gli zeri iniziali rimossi, poiché le persone spesso lasciano cose del genere. Puoi memorizzare tutte queste variazioni nella stessa colonna. Memorizza il nome del tuo prodotto in un'altra colonna e la descrizione del prodotto in un'altra colonna. Crea un indice separato su ogni colonna. Quindi, quando esegui la ricerca, puoi cercare ciascuna colonna singolarmente e moltiplicare la classifica dei risultati in base all'importanza che ritieni sia quella colonna. Quindi potresti moltiplicare i risultati di sku per 10, titolo per 5 e lasciare i risultati della descrizione come sono. Potrebbe essere necessario fare una piccola sperimentazione per ottenere i risultati desiderati, ma potrebbe essere in definitiva più semplice della creazione del proprio indice.

+0

Ho un bbcode che circonda i sottotitoli nella descrizione. potrei prendere tutto tra i bbcode e unire tutti i mondi insieme (con spazi tra di loro) in una colonna, e moltiplicare quella colonna per dire 3? Inoltre, potresti fornire un semplice esempio di utilizzo del fulltext con diversi moltiplicatori? – Ben

+0

Se vorreste ampliare la vostra risposta, sarei felice di aggiungere una taglia a questa domanda. – Ben

1

Creare una tabella di parole chiave. Qualcosa sulla falsariga di:

integer keywordId (autoincrement) | varchar keyword | int pointValue 

Assegna tutte le possibili parole chiave, SKU, ecc, in questa tabella. Creare un altro tavolo, un ponte post-parole chiave, (supponendo postId è l'id avete assegnato nella tabella originale) lungo le linee di:

integer keywordId | integer postId 

Una volta fatto questo, si può facilmente aggiungere una parola chiave per ogni post come è interessato. Per calcolare il valore totale punto per un determinato posto, una query come la seguente dovrebbe fare il trucco:

SELECT sum(pointValue) FROM keywordPostsBridge kpb 
JOIN keywords k ON k.keywordId = kpb.keywordId 
WHERE kpb.postId = YOUR_INTENDED_POST 
1

Penso che la soluzione è abbastanza semplice se non ho perso qualcosa.

Fondamentalmente eseguire due ricerche, una è la corrispondenza esatta, l'altra è come la corrispondenza o la corrispondenza regolare.

Unisci due gruppi di risultati insieme, ad esempio, corrisponde alla corrispondenza esatta. Quindi, ad esempio:

final_relevancy = (IFNULL(like_relevancy, 0) + IFNULL(exact_relevancy, 0) * 3)/4 

Non ho provato me stesso però. Solo un'idea

0
/* 
q and q1 - you table 
this query takes too much resources, 
make from it update-query (scheduled task or call it on_save if you develop new system) 
*/ 
SELECT 
     CASE 
       WHEN word NOT REGEXP "^[a-zA-Z]+$" 
        /*many replace with junk characters 
        or create custom function 
        or if you have full db access install his https://launchpad.net/mysql-udf-regexp 
        */ 
       THEN REPLACE(REPLACE(word, '-', ' '), '#', ' ') 
       ELSE word 
     END word , 
     CASE 
       WHEN word NOT REGEXP "^[a-zA-Z]+$" 
       THEN 8 
       ELSE relevancy 
     END   relevancy 
FROM (SELECT 'my' word, 
       3  relevancy 

     UNION 

     SELECT 'test' word, 
       1  relevancy 

     UNION 

     SELECT 'sentence' word, 
       1   relevancy 

     UNION 

     SELECT 'TST-DFS' word, 
       10 relevancy 
     ) 
     q 

UNION 

SELECT * 
FROM (SELECT 'my' word, 
       3  relevancy 

     UNION 

     SELECT 'test' word, 
       1  relevancy 

     UNION 

     SELECT 'sentence' word, 
       1   relevancy 

     UNION 

     SELECT 'TST-DFS' word, 
       10 relevancy 
     ) 
     q1 
0
it is a page coading where query result shows 

**i can not use functions by use them work are more easier** 

<html> 
<head> 
</head> 
<body> 
<?php 
//author S_A_KHAN 
//date 10/02/2013 
$dbcoonect=mysql_connect("127.0.0.1","root"); 
if (!$dbcoonect) 
{ 
die ('unable to connect'.mysqli_error()); 
} 
else 
{ 
echo "connection successfully <br>"; 

} 
$data_base=mysql_select_db("connect",$dbcoonect); 


if ($data_base==FALSE){ 

die ('unable to connect'.mysqli_error($dbcoonect)); 
    } 
else 
    { 
echo "connection successfully done<br>"; 
    ***$SQLString = "select * from user where id= " . $_GET["search"] . ""; 
$QueryResult=mysql_query($SQLString,$dbcoonect);*** 

echo "<table width='100%' border='1'>\n"; 
    echo "<tr><th bgcolor=gray>Id</th><th bgcolor=gray>Name</th></tr>\n"; 
    while (($Row = mysql_fetch_row($QueryResult)) !== FALSE) { 
     echo "<tr><td bgcolor=tan>{$Row[0]}</td>"; 
     echo "<td bgcolor=tan>{$Row[1]}</td></tr>"; 
    } 
} 
?> 

</body> 
</html>