functions - php mysqli example




Come trovare la somiglianza tra le righe mySQL? (12)

Sto cercando di creare uno script che trovi una percentuale corrispondente tra le mie righe di tabella. Ad esempio il mio database mySQL nei prodotti tabella contiene il nome del campo (indicizzato, FULLTEXT) con valori come

LG 50PK350 PLASMA TV 50" Plasma TV Full HD 600Hz 
LG TV 50PK350 PLASMA 50"
LG S24AW 24000 BTU
Aircondition LG S24AW 24000 BTU Inverter

Come puoi vedere, tutti hanno una stessa parola chiave. Ma il 1 ° nome e il 2 ° nome sono più simili. Inoltre, 3 ° e 4 ° hanno più parole chiave simili tra loro rispetto al 1 ° e 2 °.

Il mio DB mySQL ha migliaia di nomi di prodotti. Quello che voglio è trovare quei nomi che hanno più di una percentuale (diciamo il 60%) di somiglianza.

Ad esempio, come ho detto, il 1 °, 2 ° (e qualsiasi altro nome) che si abbinano tra loro con più del 60%, verrà riecheggiato in un formato in stile gruppo per farmi sapere che questi prodotti sono simili. Il 3 ° e il 4 ° e tutti gli altri con più del 60% di corrispondenza verranno riprodotti dopo in un altro gruppo, dicendomi che quei prodotti corrispondono.

Se è possibile, sarebbe bello fare eco alle parole chiave che soddisfano tutti i nomi corrispondenti raggruppati. Ad esempio LG S24AW 24000 BTU è la parola chiave contenuta nel 3 ° e 4 ° nome.

Alla fine creerò un elenco di tutte quelle parole chiave.

Quello che ho ora è la seguente query (come suggerito da Jitamaro)

Select t1.name, t2.name From products t1, products t2

che crea un nuovo campo nome accanto a tutti gli altri nomi. Scusami se non so come spiegarlo, ma questo è quello che fa: (I veri valori sono nomi di prodotti come sopra)

Prima della query

-name-
A
B
C
D
E

Dopo la query

-name- -name-
A        A
B        A
C        A
D        A
E        A
A        B
B        B
C        B
D        B
E        B
.
.
.

C'è un modo con mySQL o PHP che mi troverà i nomi corrispondenti e estrarre le parole chiave come ho descritto sopra? Si prega di condividere esempi di codice.

Grazie della comunità.


È possibile utilizzare LIKE per trovare nomi di prodotti simili all'interno della tabella. Per esempio:

SELECT * FROM product WHERE product_name LIKE 'LG%';

Ecco un'altra idea (ma sto votando per levenshtein() ):

Crea una tabella temporanea di tutte le parole usate nei nomi e nelle loro frequenze.

Scegli la gamma di risultati (le parole più popolari sono probabilmente parole come LCD o LED, le parole più uniche potrebbero essere buone, potrebbero essere i nomi effettivi del prodotto).

Suggerisci per ciascuna delle parole risultato:


Il tuo approccio sembra sano. Per la corrispondenza di prodotti simili, suggerirei una ricerca trigram. C'è una spiegazione abbastanza decente di come funziona insieme al modulo String::Trigram Perl.

Ti suggerirei di utilizzare la ricerca trigram per ottenere un elenco di corrispondenze, magari abbinato a una revisione manuale in base a quanti dati hai a che fare e alla frequenza con cui hai bisogno di aggiungere nuovi prodotti. Ho trovato questo approccio per funzionare abbastanza bene nella pratica.


Interrogare il DB con LIKE OR REGEXP:

SELECT * FROM product WHERE product_name LIKE '%LG%';
SELECT * FROM product WHERE product_name REGEXP "LG";

Effettua il loop dei risultati e usa similar_text ():

$a = "LG 50PK350 PLASMA TV 50\" Plasma TV Full HD 600Hz"; // DB value
$b = "LG TV 50PK350 PLASMA 50\"" ; // USER QUERY

$i = similar_text($a, $b, $p);
echo("Matched: $i  Percentage: $p%");

//outputs: Matched: 21 Percentage: 58.3333333333%

Il tuo secondo esempio corrisponde a 62.0689655172%:

$a = "LG S24AW 24000 BTU"; // DB value
$b = "Aircondition LG S24AW 24000 BTU Inverter" ; // USER QUERY

$i = similar_text($a, $b, $p);
echo("Matched: $i  Percentage: $p%");

Puoi definire una percentuale più alta di, diciamo, del 40%, per abbinare i prodotti.
Si noti che similar_text () è case SensItivE, quindi è necessario ridurre la maiuscole e minuscole alla stringa.


Per quanto riguarda la seconda domanda, la funzione levenshtein() ( in MySQL ) sarebbe un buon candidato.


Quando guardo i tuoi esempi, considero come proverei a trovare prodotti simili basati sul titolo. Dai tuoi due esempi, posso vedere una cosa in ogni riga che si distingue sopra ogni altra cosa: i numeri del modello. Probabilmente il 50PK350 non viene visualizzato in nessun altro luogo rispetto a questo modello.

Ora, MySQL stesso non è progettato per affrontare domande come questa, ma alcuni strumenti bolt-on sopra di esso sono. Parte del problema è che l'interrogazione su tutti quei campi in tutte le posizioni è costosa. Vuoi davvero dividerlo in un certo modo e indicarlo. La classe di similarità di Lucene garantirà un punteggio elevato alle parole che appaiono raramente in tutti i dati, ma appaiono come un'alta percentuale di dati. Vedi la spiegazione di alto livello della classe di similarità per Lucene?

Si dovrebbe anche guardare il confronto del motore di ricerca full text - Lucene, Sphinx, Postgresql, MySQL?

Segnare ogni parola contro la classe di similitudine di Lucene dovrebbe essere più veloce e più affidabile. La somma dei tuoi punteggi dovrebbe darti i prodotti più correlati. Per la TV, mi aspetto di vedere prima le corrispondenze esatte, poi alcune altre della stessa dimensione, poi la marca, poi la TV in generale, ecc.

Qualunque cosa tu faccia, renditi conto che se non modifichi le strutture dati utilizzando un altro strumento in cima al sistema SQL per creare strutture dati migliori, le tue query saranno troppo lente e costose. Penso che Lucene sia probabilmente la strada da percorrere. Sfinge o altre opzioni non menzionate potrebbero anche essere prese in considerazione.


Questo è più complicato di quanto sembri e nel tuo post mancano informazioni:

  • In che modo le persone useranno questa funzione di completamento automatico?
  • È importante che tu possa trovare tutti i nomi per un prodotto? Perché apparentemente non tutti i negozi chiamano i loro prodotti allo stesso modo, quindi un impiegato potrebbe non essere in grado di trovare i prodotti che ha trovato.
  • Avete informazioni su quali nomi di prodotti sono per lo stesso prodotto?
  • È rilevante da quale negozio stai cercando? dove viene usato questo auto-completamento?
  • Il completamento automatico dovrebbe suggerire solo prodotti che corrispondono a tutte le parole digitate? (non è così difficile, tecnicamente, correggere errori di battitura)

Penso che tu abbia bisogno di un'immagine più chiara di ciò che tu (o meglio ancora: gli utenti) vogliono fare questa funzione di completamento automatico.

Una funzione di completamento automatico è una caratteristica di tipo molto intuitiva. Aiuta l'utente, possibilmente in modo sfocato, quindi non esiste una risposta giusta. Devi capire cosa funziona meglio, non cosa è più facile da fare tecnicamente.

Prima capisci cosa vuoi, poi preoccupati della tecnologia.


Questo è un problema di clustering, che può essere risolto con un metodo di data mining. ( http://en.wikipedia.org/wiki/Cluster_analysis ) Richiede molte operazioni intensive di memoria e calcolo che non sono adatte per il motore di database. In caso contrario, il software separato di data mining, text mining o business analytics non sarebbe esistito.


Se si desidera verificare tutti i nomi uno contro l'altro è necessario un cross join in mysql. Ci sono molti modi per ottenere questo:

1. Select a, b From t1, t2

2. Select a, b From t1 Join t2

3. Select a, b From t1 Cross Join t2

Quindi puoi scorrere il risultato. Questo è lo stesso quando dico di creare un array 2d con elementi n ^ 2- (n-1) e ogni elemento è connesso l'uno con l'altro.

PS: selezionare t1.name, t2.name dai prodotti t1, prodotti t2


Sembra che potresti sempre voler restituire la corda più corta ?? È più o una domanda che altro. Ma allora potresti avere qualcosa come ...

SELECT * FROM products LIMIT 1
WHERE product_name like '%LG%'
ORDER BY LENGTH(product_name) ASC

Ti consiglierei di usare un motore di ricerca a tutto campo, come la sphinx . Ha la possibilità di implementare qualsiasi algoritmo tu voglia. Ad esempio, puoi utilizzare le ricerche "quorom" o "any".


Una possibile soluzione è usare la distanza di Damerau-Levenstein . Potrebbe essere usato in questo modo

select *
from products p
where DamerauLevenstein(p.name, '*user input here*')<=*X*

Dovrai capire X che soddisfa al meglio le tue esigenze. Dovrebbe essere un numero intero maggiore di zero. Potresti averlo codificato, parametrizzato o calcolato secondo necessità.

La cosa più DamerauLevenstein qui è DamerauLevenstein . Deve essere memorizzata la procedura, che implementa l'algoritmo di Damerau-Levenstein. Non ho MySQL qui, quindi potrei scriverlo per te più tardi questo giorno.

Aggiornamento: MySQL non supporta gli array nelle stored procedure, quindi non c'è modo di implementare Damerau-Levenstein in MySQL, eccetto l'uso della tabella temporanea per ogni chiamata di funzione. E ciò si tradurrà in una performance terribile. Quindi hai due opzioni: scorrere i risultati in PHP con levenstein come suggerisce Alix Axel, o migrare il tuo database su PostgreSQL, dove sono supportati gli array. C'è anche un'opzione per creare una funzione definita dall'utente, ma ciò richiede la scrittura di questa funzione in C, collegandola a MySQL e possibilmente ricostruendo MySQL, quindi in questo modo aggiungerai altro mal di testa.





mysql