Я сделал что-то похожее с базой данных из названий Википедии и сумел спуститься до нескольких сотен миллисекунд за каждый документ ~ 50 КБ. Это было все еще недостаточно быстро для моих нужд, но, возможно, это может сработать для вас.
В основном идея заключалась в том, чтобы как можно больше работать с хешами и выполнять только строковые сравнения на возможных совпадениях, которые довольно редки.
Сначала вы берете свою базу данных и конвертируете ее в массив хешей. Если у вас есть миллиарды фраз, это может быть не для вас. Когда вы вычисляете хэш, обязательно передавайте фразы через токенизатор, который удалит знаки препинания и пробелы. Эта часть должна быть выполнена только один раз.
Затем вы идете по документу с тем же токенизатором, сохраняя список запусков последних 1,2, .., n токенов, хешированных.На каждой итерации вы выполняете двоичный поиск хешей, которые у вас есть против базы хешей.
Когда вы найдете совпадение, вы выполняете фактическое сравнение строк, чтобы узнать, нашли ли вы совпадение.
Вот код, чтобы дать вам вкус подогреть я имею в виду, жесткий этот пример не на самом деле сделать сравнение строк:
HashSet<Long> foundHashes = new HashSet<Long>();
LinkedList<String> words = new LinkedList<String>();
for(int i=0; i<params.maxPhrase; i++) words.addLast("");
StandardTokenizer st = new StandardTokenizer(new StringReader(docText));
Token t = new Token();
while(st.next(t) != null) {
String token = new String(t.termBuffer(), 0, t.termLength());
words.addLast(token);
words.removeFirst();
for(int len=params.minPhrase; len<params.maxPhrase; len++) {
String term = Utils.join(new ArrayList<String>(words.subList(params.maxPhrase-len,params.maxPhrase)), " ");
long hash = Utils.longHash(term);
if(params.lexicon.isTermHash(hash)) {
foundHashes.add(hash);
}
}
}
for(long hash : foundHashes) {
if(count.containsKey(hash)) {
count.put(hash, count.get(hash) + 1);
} else {
count.put(hash, 1);
}
}
Допускается использование нескольких сотен миллисекунд. Я дам этот подход – Tourch