在我的项目中,为了插入自动提示功能(也存在像Google这样的小插入错误),我创建了这个类:
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;
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;
}
}
对于您来说,可以提高此算法的效率和速度吗?如果是,那怎么可能? PS。我知道存在专用于这些函数的库(如Lucene)但我不能用它们实现带有插入错误的自动提供功能。
答案 0 :(得分:0)
在不了解细节的情况下,您的代码有两个明显的问题:
您的代码会循环每个建议。如果可能的建议列表很长,那么迭代每一个项目将会变得无法接受。您可以按某种顺序对建议进行排序和/或切断最大数量的建议。
您的并行线程没有缩放。他们都在争夺getProssimo
所持的锁定,然后做很少的工作(我想象),所以大多数时候,你不会从多个线程中获得任何好处。通过让线程一次获得批量建议来减少争用。