2013-03-12 12 views
10

Al momento ho un singolo campo di ricerca la ricerca contro le colonne multiple utilizzando questo codice:Come fare un multiplo di ricerca colonna di mysql documento in cui le parole parziali sono abbinati

$searchArray = explode(" ", $searchVal); 
$query="SELECT * FROM users WHERE "; 
$i=0; 
foreach ($searchArray as $word) { 
    if ($i != 0) $query .= " OR "; 
    $query .= " MATCH (`first_name`, `last_name`, `email`) AGAINST ('".$word."*' IN BOOLEAN MODE)"; 
    $i++; 
} 

Diciamo che ho queste due righe della tabella:

id | last_name | first_name | email 
1 | Smith  | John  | [email protected] 
2 | Smith  | Bob  | [email protected] 

Se si digita "John S", solo il primo risultato mostra qual è il comportamento desiderato.

Se si digita "John Smith", solo il primo risultato mostra qual è il comportamento desiderato.

Se si digita "Smith J", entrambi i risultati mostrano anche se Bob non è una corrispondenza.

Se si digita "Smith John", entrambi i risultati mostrano anche se Bob non è una corrispondenza.

Infine, se si digita "Jo S", non vengono restituiti risultati nonostante la corrispondenza parziale su "Jo" e "S".

Qualcuno può aiutarmi a risolvere la mia query per gestire la funzionalità desiderata dell'ordine che non corrisponde a risultati parziali e importanti? Se può essere ordinato secondo le migliori corrispondenze (vale a dire la parte più lunga della parola, a partire dalla prima lettera solo non una sezione nel mezzo, nel più alto numero di colonne), ciò sarebbe di grande aiuto anche.

UPDATE:

Volevo solo inviare il codice finale che ha lavorato basa sulla soluzione. Il mio ciclo di creazione di più istruzioni di corrispondenza non era corretto come lo era il mio ft_min_word_len.

Il mio codice è ora:

$searchArray = explode(" ", $searchVal); 
$query="SELECT * FROM users WHERE MATCH (`first_name`, `last_name`, `email`) AGAINST ('"; 
$i=0; 
foreach ($searchArray as $word) { 
    $query .= "+".$word."* "; 
} 
$query .= "' IN BOOLEAN MODE)"; 

risposta

10

In modalità booleana, che richiede le stringhe di essere presente (invece di punteggio più alto), è fatto con +. la corrispondenza del prefisso viene eseguita con un finale *. Questo sembra essere ciò che si desidera, in modo da cercare:

+John* +S* 
+John* +Smith* 
+Smith* +J* 
+Jo* +S* 

Si noti che gli indici di testo completo non si può fare la ricerca 'ovunque in una parola'. quindi qualcosa come *mith* è destinato a fallire: sono intesi per corrispondere dal personaggio 1 in un indice.

Se anche voi volete ordinare loro da valori corrispondono, per esempio, hanno bisogno di John SmithprimaJohnny Smithson, faresti questo:

SELECT * FROM user 
WHERE MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE) 
ORDER BY MATCH(..fields..) AGAINST ('match' IN BOOLEAN MODE) DESC; 

Che si vedrà si arriva da nessuna a meno che non si aggiunge tutte le parole> = ft_min_word_len nuovo separatamente:

+John* +S* John 
+John* +Smith* John Smith 
+Smith* +J* Smith 
+Jo* +S* 

Per l'ultimo, entrambi sono < i predefiniti 4 caratteri, quindi non possiamo aggiungere l'ordinamento p arams per quello di default mysql, ma è possibile impostare ft_min_world_len in modo diverso è desiderato.

+0

Sembra che ci sia ancora un problema con l'ordine dei termini. Ho aggiunto Pablo Picasso al DB per ottenere un nome più lungo per i test.Il termine "Pablo Pica" restituisce un risultato. "Pica Pablo" no. Devo passare il set completo di termini con un + e un * in una singola istruzione MATCH o eseguire più istruzioni MATCH con un OR come sopra? – Max

+0

@Max: Non riesco a riprodurre questo, sia "Pica Pablo' come' Pablo Pica' (o '+ Pica * + Pablo *'/'+ Pablo * + Pica *') restituisce lo stesso utente per me. Sì, in una singola istruzione 'MATCH() AGAINST()'. Ogni singolo termine in 'MATCH()' richiede molto probabilmente il formato '+ term *'. Leggi anche il commento di @ PatrickB: i nomi <4 caratteri non corrisponderanno mai. – Wrikken

+0

Grazie! La combinazione di ft_min_word_len e la sua modifica in una singola istruzione MATCH lo ha risolto. Aggiornerò la domanda con il mio codice finale – Max

2

IN BOOLEAN MODE è possibile utilizzare la + -modifier per forzare AND o - -modifier per forzare NOT. Nessun operatore, il tuo caso, significa opzionale.

E è necessario controllare la lunghezza minima delle parole nella configurazione mysql per rendere le parole dell'indice FULLTEXT INDEX più piccole di una certa lunghezza.

ho dovuto impostare

ft_min_word_len = 2 

in my.cnf e ha dovuto ricostruire l'indice per rendere questo efficace. Di default è 3.

Per scoprire il vostro check min_word_len (e upvote) this question

+1

Il campo "ft_min_word_len' non è per la query MATCH, è per l'indice che è stato creato e la query è ora corrispondente. Quindi, qualcuno chiamato Jo Smith non corrisponderebbe a una corrispondenza '+ Jo *'. –

+0

Già cancellato il mio primo commento (dato che era falso, la modalità booleana _segue_ usa una lunghezza minima, mi scuso per quello). – Wrikken

2

Vedi http://dev.mysql.com/doc/refman/5.5/en//fulltext-boolean.html

si può mettere un "+", "-", o nessun operatore prima di una parola per renderlo cercare "e contiene questa parola", "NON contiene questa parola", e nessun operatore è "OR contiene questa parola"

Se si digita "John S", solo il primo risultato mostra qual è il comportamento desiderato.

C'è solo un John, quindi questo funziona, S è inferiore alla lunghezza minima parola e viene scartato

Se digito "John Smith", solo il primo mostra il risultato che è il comportamento desiderato .

C'è solo un John quindi questo funziona

Se scriv "Smith J", entrambi i risultati mostrano anche se Bob non è una partita.

J è inferiore alla lunghezza minima parola, per cui il suo unico corrispondenza Smith che è entrambe le file

Se scriv "Smith John", entrambi i risultati mostrano anche se Bob non è una partita.

Dato che sei in BOOLEAN MODE, MySQL lo interpreta come Smith OR John ... Smith corrisponde a entrambi.

Infine, se si digita "Jo S", non vengono restituiti risultati nonostante la corrispondenza parziale su "Jo" e "S".

Jo e S sono al di sotto della lunghezza minima di parola - Credo che MySQL considera questo come alla ricerca di niente

Ti consigliamo di aggiungere un "+" prima che i parametri di ricerca per trasformarle in una ricerca AND ... +Smith +John

+0

Sembra esserci ancora un problema con l'ordine dei termini. Ho aggiunto Pablo Picasso al DB. Il termine "Pablo Pica" restituisce un risultato. "Pica Pablo" no. Devo passare il set completo di termini con un + e un * in una singola istruzione MATCH o eseguire più istruzioni MATCH con un OR come sopra? – Max

Problemi correlati