In un mio progetto, per inserire la funzione di autosuggerimento (anche in presenza di piccoli errori di inserimento, tipo google), ho creato la seguente classe:
codice:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Claudio
*/
public class Searcher {
private ArrayList<String> titoli;
private boolean multiThread;
private int numeroCore;
private Thread [] threads;
private int indice;
private String [] testoSplittato;
private SortedSet<String> risultati;
private final Runnable runnable;
public Searcher (ArrayList<String> titoli , boolean multiThread) {
this.titoli = titoli;
this.multiThread = multiThread;
indice = 0;
risultati = new TreeSet<String> ();
numeroCore = multiThread ? Runtime.getRuntime().availableProcessors() : 1;
threads = new Thread [numeroCore];
runnable = new Runnable () {
@Override
public void run () {
String prossimo;
while ((prossimo = getProssimo ()) != null) {
if (suggerimentoDaAggiungere (prossimo.toLowerCase()))
aggiungiRisultato (prossimo);
}
}
};
for (int i=0;i<threads.length;i++) {
threads [i] = new Thread (runnable);
}
}
public Searcher (ArrayList<String> titoli) {
this (titoli, false);
}
private synchronized void setIndice (int n) {
indice = n;
}
private synchronized String getProssimo () {
try {
return titoli.get(indice++);
}catch (IndexOutOfBoundsException ioobe) {
return null;
}
}
public synchronized void aggiungiRisultato (String s) {
risultati.add(s);
}
private boolean mancaUnaLettera (String a , String b) {
int al = a.length() , bl = b.length();
if (al < 2 || al >= bl)
return false;
//a più corta di b
int primaLetteraSbagliata = -1;
for (int i=0;i<al;i++) {
if (a.charAt (i) != b.charAt(i)) {
primaLetteraSbagliata = i;
break;
}
}
return primaLetteraSbagliata >= 0 && (b.substring(0, primaLetteraSbagliata) + b.substring(primaLetteraSbagliata + 1)).indexOf(a) >= 0;
}
private boolean unaLetteraDiTroppo (String a , String b) {
int al = a.length() , bl = b.length();
if (al < 3 || al - 1 > bl)
return false;
//a più corta o stessa lunghezza di b
int primaLetteraSbagliata = -1;
for (int i=0;i<bl;i++) {
if (a.charAt(i) != b.charAt(i)) {
primaLetteraSbagliata = i;
break;
}
}
//non sono sicurissimo di qui
if (primaLetteraSbagliata == -1 && al + 1 == bl)
return true;
return primaLetteraSbagliata >= 0 && b.indexOf ((primaLetteraSbagliata > 0 ? a.substring(0 , primaLetteraSbagliata) : "") + (primaLetteraSbagliata + 1 < al ? a.substring(primaLetteraSbagliata + 1) : "") ) >= 0;
}
private boolean unaLetteraSbagliata (String a , String b) {
int al = a.length() , bl = b.length();
if (al < 3 || al > bl)
return false;
//a ha lunghezza >= di b
int primaLetteraSbagliata = -1;
for (int i=0;i<al;i++) {
if (a.charAt(i) != b.charAt(i)) {
primaLetteraSbagliata = i;
break;
}
}
boolean ok = primaLetteraSbagliata + 1 < al;
return primaLetteraSbagliata >= 0 && (b.substring(0, primaLetteraSbagliata) + (ok ? b.substring(primaLetteraSbagliata + 1) : "")).indexOf(a.substring(0, primaLetteraSbagliata) + (ok ? a.substring(primaLetteraSbagliata + 1) : "")) >= 0;
}
private boolean presenteConErrore (String chiave , String titolo) {
String [] titoloSplittato = titolo.split(" ");
if (titolo.indexOf (chiave) >= 0)
return true;
for (String s : titoloSplittato)
if (mancaUnaLettera (chiave , s) || unaLetteraDiTroppo (chiave, s) || unaLetteraSbagliata (chiave, s))
return true;
return false;
}
public boolean suggerimentoDaAggiungere (String titolo) {
for (String s : testoSplittato) {
if (!presenteConErrore (s,titolo))
return false;
}
return true;
}
public SortedSet<String> getSuggerimenti (String testo) {
for (Thread t : threads) {
if (/*t != null && */t.isAlive()) {
t.interrupt();
}
}
testoSplittato = testo.toLowerCase ().split (" ");
risultati.clear();
if (testoSplittato.length > 0) {
setIndice (0);
for (int i=0;i<threads.length;i++) {
threads [i] = new Thread (runnable);
threads [i].setPriority(Thread.MAX_PRIORITY);
threads [i].start();
}
}
for (Thread t : threads)
try {
t.join();
} catch (InterruptedException ex) {
Logger.getLogger(Searcher.class.getName()).log(Level.SEVERE, null, ex);
}
//System.out.println ("FINITO");
return risultati;
}
public static ArrayList<String> getTitoli (String titleFilePath) {
ArrayList<String> restituire = new ArrayList<String> ();
try {
BufferedReader br = new BufferedReader (new InputStreamReader (new FileInputStream (titleFilePath) {}));
String s;
while ((s = br.readLine ()) != null) {
restituire.add (s);
}
} catch (Exception ex) {
Logger.getLogger(Searcher.class.getName()).log(Level.SEVERE, null, ex);
}
return restituire;
}
}
E' possibile secondo voi migliorarne l'efficienza e la velocità?Se si, in che modo?
Ps. So che esistono delle librerie apposite per queste funzionalità (vedi Lucene) ma tramite essa non sono in grado di implementare l'autosuggerimento con errori di inserimento ma solo l'autosuggerimento con ricerca "in chiaro"..